def get_dates_banner_info(self, _): """ Serializer mixin for returning date banner info. Gets its input from the views course_key_string url parameter and the request's user object. """ info = { 'missed_deadlines': False, 'content_type_gating_enabled': False, } course_key_string = self.context['view'].kwargs.get( 'course_key_string') if course_key_string: course_key = CourseKey.from_string(course_key_string) request = self.context['request'] missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, request.user) info['missed_deadlines'] = missed_deadlines info['missed_gated_content'] = missed_gated_content info[ 'content_type_gating_enabled'] = ContentTypeGatingConfig.enabled_for_enrollment( user=request.user, course_key=course_key, ) info['verified_upgrade_link'] = verified_upgrade_deadline_link( request.user, course_id=course_key) return info
def reset_course_deadlines(request): """ Set the start_date of a schedule to today, which in turn will adjust due dates for sequentials belonging to a self paced course """ from lms.urls import RENDER_XBLOCK_NAME from openedx.features.course_experience.urls import COURSE_HOME_VIEW_NAME detail_id_dict = ast.literal_eval( request.POST.get('reset_deadlines_redirect_url_id_dict')) redirect_url = request.POST.get('reset_deadlines_redirect_url_base', COURSE_HOME_VIEW_NAME) course_key = CourseKey.from_string(detail_id_dict['course_id']) masquerade_details, masquerade_user = setup_masquerade( request, course_key, has_access(request.user, 'staff', course_key)) if masquerade_details and masquerade_details.role == 'student' and masquerade_details.user_name and ( redirect_url == COURSE_HOME_VIEW_NAME): # Masquerading as a specific student, so reset that student's schedule user = masquerade_user else: user = request.user missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, user) if missed_deadlines and not missed_gated_content: reset_self_paced_schedule(user, course_key) if redirect_url == RENDER_XBLOCK_NAME: detail_id_dict.pop('course_id') return redirect(reverse(redirect_url, kwargs=detail_id_dict))
def get_ctas(self, xblock, category, completed): """ Return the calls to action associated with the specified category for the given xblock. Look at CallToActionService docstring to see what will be returned. """ ctas = [] request = get_current_request() course_key = xblock.scope_ids.usage_id.context_key missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user) # Not showing in the missed_gated_content case because those learners are not eligible # to shift due dates. if not missed_deadlines or missed_gated_content: return [] # Some checks to disable PLS calls to action until these environments (mobile and MFE) support them natively if request and is_request_from_mobile_app(request): return [] is_learning_mfe = request and is_request_from_learning_mfe(request) if category == self.CAPA_SUBMIT_DISABLED: # xblock is a capa problem, and the submit button is disabled. Check if it's because of a personalized # schedule due date being missed, and if so, we can offer to shift it. if self._is_block_shiftable(xblock, category): ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe)) elif category == self.VERTICAL_BANNER and not completed: # xblock is a vertical, so we'll check all the problems inside it. If there are any that will show a # a "shift dates" CTA under CAPA_SUBMIT_DISABLED, then we'll also show the same CTA as a vertical banner. if any(self._is_block_shiftable(item, category) for item in xblock.get_display_items()): ctas.append(self._make_reset_deadlines_cta(xblock, category, is_learning_mfe)) return ctas
def get(self, request, *args, **kwargs): course_key_string = kwargs.get('course_key_string') course_key = CourseKey.from_string(course_key_string) if not course_home_mfe_dates_tab_is_active(course_key): return Response(status=status.HTTP_404_NOT_FOUND) # Enable NR tracing for this view based on course monitoring_utils.set_custom_metric('course_id', course_key_string) monitoring_utils.set_custom_metric('user_id', request.user.id) monitoring_utils.set_custom_metric('is_staff', request.user.is_staff) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False) blocks = get_course_date_blocks(course, request.user, request, include_access=True, include_past_dates=True) missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, request.user) learner_is_full_access = not ContentTypeGatingConfig.enabled_for_enrollment( user=request.user, course_key=course_key, ) # User locale settings user_timezone_locale = user_timezone_locale_prefs(request) user_timezone = user_timezone_locale['user_timezone'] data = { 'has_ended': course.has_ended(), 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, 'learner_is_full_access': learner_is_full_access, 'user_timezone': user_timezone, 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), } context = self.get_serializer_context() context['learner_is_full_access'] = learner_is_full_access serializer = self.get_serializer_class()(data, context=context) return Response(serializer.data)
def render_to_fragment(self, request, course_id, user_is_enrolled=True, **kwargs): # pylint: disable=arguments-differ """ Renders the course outline as a fragment. """ from lms.urls import RESET_COURSE_DEADLINES_NAME course_key = CourseKey.from_string(course_id) course_overview = get_course_overview_with_access( request.user, 'load', course_key, check_if_enrolled=user_is_enrolled ) course = modulestore().get_course(course_key) course_block_tree = get_course_outline_block_tree( request, course_id, request.user if user_is_enrolled else None ) if not course_block_tree: return None resume_block = get_resume_block(course_block_tree) if user_is_enrolled else None if not resume_block: self.mark_first_unit_to_resume(course_block_tree) xblock_display_names = self.create_xblock_id_and_name_dict(course_block_tree) gated_content = self.get_content_milestones(request, course_key) missed_deadlines, missed_gated_content = dates_banner_should_display(course_key, request.user) reset_deadlines_url = reverse(RESET_COURSE_DEADLINES_NAME) context = { 'csrf': csrf(request)['csrf_token'], 'course': course_overview, 'due_date_display_format': course.due_date_display_format, 'blocks': course_block_tree, 'enable_links': user_is_enrolled or course.course_visibility == COURSE_VISIBILITY_PUBLIC, 'course_key': course_key, 'gated_content': gated_content, 'xblock_display_names': xblock_display_names, 'self_paced': course.self_paced, # We're using this flag to prevent old self-paced dates from leaking out on courses not # managed by edx-when. 'in_edx_when': edx_when_api.is_enabled_for_course(course_key), 'reset_deadlines_url': reset_deadlines_url, 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), 'on_course_outline_page': True, 'missed_deadlines': missed_deadlines, 'missed_gated_content': missed_gated_content, 'has_ended': course.has_ended(), } html = render_to_string('course_experience/course-outline-fragment.html', context) return Fragment(html)
def reset_course_deadlines(request): """ Set the start_date of a schedule to today, which in turn will adjust due dates for sequentials belonging to a self paced course IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines` function in common/djangoapps/util/views.py as well. """ course_key = request.data.get('course_key', None) # If body doesnt contain 'course_key', return 400 to client. if not course_key: raise ParseError(_("'course_key' is required.")) # If body contains params other than 'course_key', return 400 to client. if len(request.data) > 1: raise ParseError(_("Only 'course_key' is expected.")) try: course_key = CourseKey.from_string(course_key) _course_masquerade, user = setup_masquerade( request, course_key, has_access(request.user, 'staff', course_key)) missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, user) if missed_deadlines and not missed_gated_content: reset_self_paced_schedule(user, course_key) if course_home_mfe_dates_tab_is_active(course_key): body_link = get_microfrontend_url(course_key=str(course_key), view_name='dates') else: body_link = '{}{}'.format(settings.LMS_ROOT_URL, reverse('dates', args=[str(course_key)])) return Response({ 'body': format_html('<a href="{}">{}</a>', body_link, _('View all dates')), 'header': _('Your due dates have been successfully shifted to help you stay on track.' ), 'link': body_link, 'link_text': _('View all dates'), 'message': _('Deadlines successfully reset.'), }) except Exception as e: log.exception(e) raise UnableToResetDeadlines
def reset_course_deadlines(request): """ Set the start_date of a schedule to today, which in turn will adjust due dates for sequentials belonging to a self paced course """ course_key = CourseKey.from_string(request.POST.get('course_id')) _course_masquerade, user = setup_masquerade( request, course_key, has_access(request.user, 'staff', course_key)) missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, user) if missed_deadlines and not missed_gated_content: reset_self_paced_schedule(user, course_key) referrer = request.META.get('HTTP_REFERER') return redirect(referrer) if referrer else HttpResponse()
def get(self, request, *args, **kwargs): course_key_string = kwargs.get('course_key_string') # Enable NR tracing for this view based on course monitoring_utils.set_custom_metric('course_id', course_key_string) monitoring_utils.set_custom_metric('user_id', request.user.id) monitoring_utils.set_custom_metric('is_staff', request.user.is_staff) course_key = CourseKey.from_string(course_key_string) course = get_course_with_access(request.user, 'load', course_key, check_if_enrolled=False) blocks = get_course_date_blocks(course, request.user, request, include_access=True, include_past_dates=True) display_reset_dates_text, _ = dates_banner_should_display( course_key, request) learner_is_verified = False enrollment = get_enrollment(request.user.username, course_key_string) if enrollment: learner_is_verified = enrollment.get('mode') == 'verified' # User locale settings user_timezone_locale = user_timezone_locale_prefs(request) user_timezone = user_timezone_locale['user_timezone'] data = { 'course_date_blocks': [block for block in blocks if not isinstance(block, TodaysDate)], 'display_reset_dates_text': display_reset_dates_text, 'learner_is_verified': learner_is_verified, 'user_timezone': user_timezone, 'verified_upgrade_link': verified_upgrade_deadline_link(request.user, course=course), } context = self.get_serializer_context() context['learner_is_verified'] = learner_is_verified serializer = self.get_serializer_class()(data, context=context) return Response(serializer.data)
def reset_course_deadlines(request): """ Set the start_date of a schedule to today, which in turn will adjust due dates for sequentials belonging to a self paced course IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines` function in openedx/features/course_experience/api/v1/views.py as well. """ course_key = CourseKey.from_string(request.POST.get('course_id')) _course_masquerade, user = setup_masquerade( request, course_key, has_access(request.user, 'staff', course_key)) missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, user) if missed_deadlines and not missed_gated_content: reset_self_paced_schedule(user, course_key) referrer = request.META.get('HTTP_REFERER') return redirect(referrer) if referrer else HttpResponse()
def reset_course_deadlines(request): """ Set the start_date of a schedule to today, which in turn will adjust due dates for sequentials belonging to a self paced course IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines` function in openedx/features/course_experience/api/v1/views.py as well. """ course_key = CourseKey.from_string(request.POST.get('course_id')) _course_masquerade, user = setup_masquerade( request, course_key, has_access(request.user, 'staff', course_key)) # We ignore the missed_deadlines because this endpoint could be used for # learners who have remaining attempts on a problem and reset their due dates in order to # submit additional attempts. This can apply for 'completed' (submitted) content that would # not be marked as past_due _missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, user) if not missed_gated_content: reset_self_paced_schedule(user, course_key) referrer = request.META.get('HTTP_REFERER') return redirect(referrer) if referrer else HttpResponse()
def reset_course_deadlines(request): """ Set the start_date of a schedule to today, which in turn will adjust due dates for sequentials belonging to a self paced course Request Parameters: course_key: course key research_event_data: any data that should be included in the research tracking event Example: sending the location of where the reset deadlines banner (i.e. outline-tab) IMPORTANT NOTE: If updates are happening to the logic here, ALSO UPDATE the `reset_course_deadlines` function in common/djangoapps/util/views.py as well. """ course_key = request.data.get('course_key', None) research_event_data = request.data.get('research_event_data', {}) # If body doesnt contain 'course_key', return 400 to client. if not course_key: raise ParseError(_("'course_key' is required.")) try: course_key = CourseKey.from_string(course_key) course_masquerade, user = setup_masquerade( request, course_key, has_access(request.user, 'staff', course_key)) # We ignore the missed_deadlines because this endpoint is used in the Learning MFE for # learners who have remaining attempts on a problem and reset their due dates in order to # submit additional attempts. This can apply for 'completed' (submitted) content that would # not be marked as past_due _missed_deadlines, missed_gated_content = dates_banner_should_display( course_key, user) if not missed_gated_content: reset_self_paced_schedule(user, course_key) course_overview = course_detail(request, user.username, course_key) # For context here, research_event_data should already contain `location` indicating # the page/location dates were reset from and could also contain `block_id` if reset # within courseware. research_event_data.update({ 'courserun_key': str(course_key), 'is_masquerading': is_masquerading(user, course_key, course_masquerade), 'is_staff': has_access(user, 'staff', course_key).has_access, 'org_key': course_overview.display_org_with_default, 'user_id': user.id, }) tracker.emit('edx.ui.lms.reset_deadlines.clicked', research_event_data) if course_home_legacy_is_active(course_key): body_link = '{}{}'.format(settings.LMS_ROOT_URL, reverse('dates', args=[str(course_key)])) else: body_link = get_learning_mfe_home_url(course_key=str(course_key), view_name='dates') return Response({ 'body': format_html('<a href="{}">{}</a>', body_link, _('View all dates')), 'header': _('Your due dates have been successfully shifted to help you stay on track.' ), 'link': body_link, 'link_text': _('View all dates'), 'message': _('Deadlines successfully reset.'), }) except Exception as reset_deadlines_exception: log.exception('Error occurred while trying to reset deadlines!') raise UnableToResetDeadlines from reset_deadlines_exception