def create(cls, name, course_id, description, topic_id=None, country=None, language=None): """Create a complete CourseTeam object. Args: name (str): The name of the team to be created. course_id (str): The ID string of the course associated with this team. description (str): A description of the team. topic_id (str): An optional identifier for the topic the team formed around. country (str, optional): An optional country where the team is based, as ISO 3166-1 code. language (str, optional): An optional language which the team uses, as ISO 639-1 code. """ unique_id = uuid4().hex team_id = slugify(name)[0:20] + '-' + unique_id discussion_topic_id = unique_id course_team = cls( team_id=team_id, discussion_topic_id=discussion_topic_id, name=name, course_id=course_id, topic_id=topic_id if topic_id else '', description=description, country=country if country else '', language=language if language else '', last_activity_at=datetime.utcnow().replace(tzinfo=pytz.utc) ) return course_team
def create(cls, title, course_id, description): """Create a complete MyJournal object for a course. Args: title (str): The title of the MyJournal to be created. course_id (str): The ID string of the course associated with this team. description (str): A description of MyJournal instance, e.g. it's purpose within the course. """ unique_id = uuid4().hex myjournal_id = slugify(title)[0:20] + '-' + unique_id course_myjournal = cls( myjournal_id=myjournal_id, title=title, course_id=course_id, description=description ) return course_myjournal
def toc_for_course(user, request, course, active_chapter, active_section, field_data_cache): ''' Create a table of contents from the module store Return format: { 'chapters': [ {'display_name': name, 'url_name': url_name, 'sections': SECTIONS, 'active': bool}, ], 'previous_of_active_section': {..}, 'next_of_active_section': {..} } where SECTIONS is a list [ {'display_name': name, 'url_name': url_name, 'format': format, 'due': due, 'active' : bool, 'graded': bool}, ...] where previous_of_active_section and next_of_active_section have information on the next/previous sections of the active section. active is set for the section and chapter corresponding to the passed parameters, which are expected to be url_names of the chapter+section. Everything else comes from the xml, or defaults to "". chapters with name 'hidden' are skipped. NOTE: assumes that if we got this far, user has access to course. Returns None if this is not the case. field_data_cache must include data from the course module and 2 levels of its descendants ''' with modulestore().bulk_operations(course.id): course_module = get_module_for_descriptor( user, request, course, field_data_cache, course.id, course=course ) if course_module is None: return None, None, None toc_chapters = list() chapters = course_module.get_display_items() # Check for content which needs to be completed # before the rest of the content is made available required_content = milestones_helpers.get_required_content(course.id, user) # The user may not actually have to complete the entrance exam, if one is required if user_can_skip_entrance_exam(user, course): required_content = [content for content in required_content if not content == course.entrance_exam_id] previous_of_active_section, next_of_active_section = None, None last_processed_section, last_processed_chapter = None, None found_active_section = False for chapter in chapters: # Only show required content, if there is required content # chapter.hide_from_toc is read-only (bool) display_id = slugify(chapter.display_name_with_default_escaped) local_hide_from_toc = False if required_content: if unicode(chapter.location) not in required_content: local_hide_from_toc = True # Skip the current chapter if a hide flag is tripped if chapter.hide_from_toc or local_hide_from_toc: continue sections = list() for section in chapter.get_display_items(): # skip the section if it is hidden from the user if section.hide_from_toc: continue is_section_active = (chapter.url_name == active_chapter and section.url_name == active_section) if is_section_active: found_active_section = True section_context = { 'display_name': section.display_name_with_default_escaped, 'url_name': section.url_name, 'format': section.format if section.format is not None else '', 'due': section.due, 'active': is_section_active, 'graded': section.graded, } _add_timed_exam_info(user, course, section, section_context) # update next and previous of active section, if applicable if is_section_active: if last_processed_section: previous_of_active_section = last_processed_section.copy() previous_of_active_section['chapter_url_name'] = last_processed_chapter.url_name elif found_active_section and not next_of_active_section: next_of_active_section = section_context.copy() next_of_active_section['chapter_url_name'] = chapter.url_name sections.append(section_context) last_processed_section = section_context last_processed_chapter = chapter toc_chapters.append({ 'display_name': chapter.display_name_with_default_escaped, 'display_id': display_id, 'url_name': chapter.url_name, 'sections': sections, 'active': chapter.url_name == active_chapter }) return { 'chapters': toc_chapters, 'previous_of_active_section': previous_of_active_section, 'next_of_active_section': next_of_active_section, }
def toc_for_course(user, request, course, active_chapter, active_section, field_data_cache): ''' Create a table of contents from the module store Return format: { 'chapters': [ {'display_name': name, 'url_name': url_name, 'sections': SECTIONS, 'active': bool}, ], 'previous_of_active_section': {..}, 'next_of_active_section': {..} } where SECTIONS is a list [ {'display_name': name, 'url_name': url_name, 'format': format, 'due': due, 'active' : bool, 'graded': bool}, ...] where previous_of_active_section and next_of_active_section have information on the next/previous sections of the active section. active is set for the section and chapter corresponding to the passed parameters, which are expected to be url_names of the chapter+section. Everything else comes from the xml, or defaults to "". chapters with name 'hidden' are skipped. NOTE: assumes that if we got this far, user has access to course. Returns None if this is not the case. field_data_cache must include data from the course module and 2 levels of its descendants ''' with modulestore().bulk_operations(course.id): course_module = get_module_for_descriptor( user, request, course, field_data_cache, course.id, course=course ) if course_module is None: return None, None, None toc_chapters = list() chapters = course_module.get_display_items() # Check for content which needs to be completed # before the rest of the content is made available required_content = milestones_helpers.get_required_content(course, user) # Check for gated content gated_content = gating_api.get_gated_content(course, user) # The user may not actually have to complete the entrance exam, if one is required if not user_must_complete_entrance_exam(request, user, course): required_content = [content for content in required_content if not content == course.entrance_exam_id] previous_of_active_section, next_of_active_section = None, None last_processed_section, last_processed_chapter = None, None found_active_section = False for chapter in chapters: # Only show required content, if there is required content # chapter.hide_from_toc is read-only (bool) display_id = slugify(chapter.display_name_with_default_escaped) local_hide_from_toc = False if required_content: if unicode(chapter.location) not in required_content: local_hide_from_toc = True # Skip the current chapter if a hide flag is tripped if chapter.hide_from_toc or local_hide_from_toc: continue sections = list() for section in chapter.get_display_items(): # skip the section if it is gated/hidden from the user if gated_content and unicode(section.location) in gated_content: continue if section.hide_from_toc: continue is_section_active = (chapter.url_name == active_chapter and section.url_name == active_section) if is_section_active: found_active_section = True section_context = { 'display_name': section.display_name_with_default_escaped, 'url_name': section.url_name, 'format': section.format if section.format is not None else '', 'due': section.due, 'active': is_section_active, 'graded': section.graded, } _add_timed_exam_info(user, course, section, section_context) # update next and previous of active section, if applicable if is_section_active: if last_processed_section: previous_of_active_section = last_processed_section.copy() previous_of_active_section['chapter_url_name'] = last_processed_chapter.url_name elif found_active_section and not next_of_active_section: next_of_active_section = section_context.copy() next_of_active_section['chapter_url_name'] = chapter.url_name sections.append(section_context) last_processed_section = section_context last_processed_chapter = chapter toc_chapters.append({ 'display_name': chapter.display_name_with_default_escaped, 'display_id': display_id, 'url_name': chapter.url_name, 'sections': sections, 'active': chapter.url_name == active_chapter }) return { 'chapters': toc_chapters, 'previous_of_active_section': previous_of_active_section, 'next_of_active_section': next_of_active_section, }
def toc_for_course(user, request, course, active_chapter, active_section, field_data_cache): ''' Create a table of contents from the module store Return format: [ {'display_name': name, 'url_name': url_name, 'sections': SECTIONS, 'active': bool}, ... ] where SECTIONS is a list [ {'display_name': name, 'url_name': url_name, 'format': format, 'due': due, 'active' : bool, 'graded': bool}, ...] active is set for the section and chapter corresponding to the passed parameters, which are expected to be url_names of the chapter+section. Everything else comes from the xml, or defaults to "". chapters with name 'hidden' are skipped. NOTE: assumes that if we got this far, user has access to course. Returns None if this is not the case. field_data_cache must include data from the course module and 2 levels of its descendents ''' with modulestore().bulk_operations(course.id): course_module = get_module_for_descriptor( user, request, course, field_data_cache, course.id, course=course ) if course_module is None: return None toc_chapters = list() chapters = course_module.get_display_items() # See if the course is gated by one or more content milestones required_content = milestones_helpers.get_required_content(course, user) # The user may not actually have to complete the entrance exam, if one is required if not user_must_complete_entrance_exam(request, user, course): required_content = [content for content in required_content if not content == course.entrance_exam_id] for chapter in chapters: # Only show required content, if there is required content # chapter.hide_from_toc is read-only (boo) display_id = slugify(chapter.display_name_with_default) local_hide_from_toc = False if required_content: if unicode(chapter.location) not in required_content: local_hide_from_toc = True # Skip the current chapter if a hide flag is tripped if chapter.hide_from_toc or local_hide_from_toc: continue sections = list() for section in chapter.get_display_items(): active = (chapter.url_name == active_chapter and section.url_name == active_section) if not section.hide_from_toc: section_context = { 'display_name': section.display_name_with_default, 'url_name': section.url_name, 'format': section.format if section.format is not None else '', 'due': section.due, 'active': active, 'graded': section.graded, } # # Add in rendering context if exam is a timed exam (which includes proctored) # section_is_time_limited = ( getattr(section, 'is_time_limited', False) and settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) ) if section_is_time_limited: # We need to import this here otherwise Lettuce test # harness fails. When running in 'harvest' mode, the # test service appears to get into trouble with # circular references (not sure which as edx_proctoring.api # doesn't import anything from edx-platform). Odd thing # is that running: manage.py lms runserver --settings=acceptance # works just fine, it's really a combination of Lettuce and the # 'harvest' management command # # One idea is that there is some coupling between # lettuce and the 'terrain' Djangoapps projects in /common # This would need more investigation from edx_proctoring.api import get_attempt_status_summary # # call into edx_proctoring subsystem # to get relevant proctoring information regarding this # level of the courseware # # This will return None, if (user, course_id, content_id) # is not applicable # timed_exam_attempt_context = None try: timed_exam_attempt_context = get_attempt_status_summary( user.id, unicode(course.id), unicode(section.location) ) except Exception, ex: # pylint: disable=broad-except # safety net in case something blows up in edx_proctoring # as this is just informational descriptions, it is better # to log and continue (which is safe) than to have it be an # unhandled exception log.exception(ex) if timed_exam_attempt_context: # yes, user has proctoring context about # this level of the courseware # so add to the accordion data context section_context.update({ 'proctoring': timed_exam_attempt_context, }) sections.append(section_context) toc_chapters.append({ 'display_name': chapter.display_name_with_default, 'display_id': display_id, 'url_name': chapter.url_name, 'sections': sections, 'active': chapter.url_name == active_chapter }) return toc_chapters
def _create_courseware_context(self): """ Returns and creates the rendering context for the courseware. Also returns the table of contents for the courseware. """ original_course_id = None if hasattr(self.course.id, 'ccx'): c = CustomCourseForEdX.objects.get(pk=self.course.id.ccx) original_course_id = c.course_id courseware_context = { 'csrf': csrf(self.request)['csrf_token'], 'COURSE_TITLE': self.course.display_name_with_default_escaped, 'course': self.course, 'original_course_id': original_course_id, 'init': '', 'fragment': Fragment(), 'staff_access': self.is_staff, 'studio_url': get_studio_url(self.course, 'course'), 'masquerade': self.masquerade, 'xqa_server': settings.FEATURES.get('XQA_SERVER', "http://your_xqa_server.com"), 'bookmarks_api_url': reverse('bookmarks'), 'language_preference': self._get_language_preference(), 'disable_optimizely': True, } table_of_contents = toc_for_course( self.effective_user, self.request, self.course, self.chapter_url_name, self.section_url_name, self.field_data_cache, ) courseware_context['accordion'] = render_accordion( self.request, self.course, table_of_contents['chapters']) # entrance exam data if course_has_entrance_exam(self.course): if getattr(self.chapter, 'is_entrance_exam', False): courseware_context[ 'entrance_exam_current_score'] = get_entrance_exam_score( self.request, self.course) courseware_context[ 'entrance_exam_passed'] = user_has_passed_entrance_exam( self.request, self.course) # staff masquerading data now = datetime.now(UTC()) effective_start = _adjust_start_date_for_beta_testers( self.effective_user, self.course, self.course_key) if not in_preview_mode() and self.is_staff and now < effective_start: # Disable student view button if user is staff and # course is not yet visible to students. courseware_context['disable_student_access'] = True if self.section: # chromeless data if self.section.chrome: chrome = [ s.strip() for s in self.section.chrome.lower().split(",") ] if 'accordion' not in chrome: courseware_context['disable_accordion'] = True if 'tabs' not in chrome: courseware_context['disable_tabs'] = True # default tab if self.section.default_tab: courseware_context['default_tab'] = self.section.default_tab # section data courseware_context[ 'section_title'] = self.section.display_name_with_default_escaped section_context = self._create_section_context( table_of_contents['previous_of_active_section'], table_of_contents['next_of_active_section'], ) courseware_context['fragment'] = self.section.render( STUDENT_VIEW, section_context) # fasttrac addition: dropdown menu for sections section_list = [{ "display_id": slugify(section.display_name_with_default_escaped), "display_name": str(section.display_name) } for section in self.course.get_display_items()] courseware_context['section_list'] = section_list return courseware_context