def check_course_access(course, user, action, check_if_enrolled=False): """ Check that the user has the access to perform the specified action on the course (CourseDescriptor|CourseOverview). check_if_enrolled: If true, additionally verifies that the user is enrolled. """ # Allow staff full access to the course even if not enrolled if has_access(user, 'staff', course.id): return access_response = has_access(user, action, course, course.id) if not access_response: # Redirect if StartDateError if isinstance(access_response, StartDateError): start_date = strftime_localized(course.start, 'SHORT_DATE') params = QueryDict(mutable=True) params['notlive'] = start_date raise CourseAccessRedirect('{dashboard_url}?{params}'.format( dashboard_url=reverse('dashboard'), params=params.urlencode())) # Deliberately return a non-specific error message to avoid # leaking info about access control settings raise CoursewareAccessException(access_response) if check_if_enrolled: # If the user is not enrolled, redirect them to the about page if not CourseEnrollment.is_enrolled(user, course.id): raise CourseAccessRedirect( reverse('about_course', args=[unicode(course.id)]))
def check_course_access(course, user, action, check_if_enrolled=False, check_survey_complete=True): """ Check that the user has the access to perform the specified action on the course (CourseDescriptor|CourseOverview). check_if_enrolled: If true, additionally verifies that the user is enrolled. check_survey_complete: If true, additionally verifies that the user has completed the survey. """ # Allow staff full access to the course even if not enrolled if has_access(user, 'staff', course.id): return request = get_current_request() check_content_start_date_for_masquerade_user(course.id, user, request, course.start) access_response = has_access(user, action, course, course.id) if not access_response: # Redirect if StartDateError if isinstance(access_response, StartDateError): start_date = strftime_localized(course.start, 'SHORT_DATE') params = QueryDict(mutable=True) params['notlive'] = start_date raise CourseAccessRedirect('{dashboard_url}?{params}'.format( dashboard_url=reverse('dashboard'), params=params.urlencode() ), access_response) # Redirect if AuditExpiredError if isinstance(access_response, AuditExpiredError): params = QueryDict(mutable=True) params['access_response_error'] = access_response.additional_context_user_message raise CourseAccessRedirect('{dashboard_url}?{params}'.format( dashboard_url=reverse('dashboard'), params=params.urlencode() ), access_response) # Redirect if the user must answer a survey before entering the course. if isinstance(access_response, MilestoneAccessError): raise CourseAccessRedirect('{dashboard_url}'.format( dashboard_url=reverse('dashboard'), ), access_response) # Deliberately return a non-specific error message to avoid # leaking info about access control settings raise CoursewareAccessException(access_response) if check_if_enrolled: # If the user is not enrolled, redirect them to the about page if not CourseEnrollment.is_enrolled(user, course.id): raise CourseAccessRedirect(reverse('about_course', args=[six.text_type(course.id)])) # Redirect if the user must answer a survey before entering the course. if check_survey_complete and action == 'load': if is_survey_required_and_unanswered(user, course): raise CourseAccessRedirect(reverse('course_survey', args=[six.text_type(course.id)]))
def _redirect_if_needed_to_pay_for_course(self): """ Redirect to dashboard if the course is blocked due to non-payment. """ redeemed_registration_codes = [] if self.request.user.is_authenticated: self.real_user = User.objects.prefetch_related("groups").get( id=self.real_user.id) redeemed_registration_codes = CourseRegistrationCode.objects.filter( course_id=self.course_key, registrationcoderedemption__redeemed_by=self.real_user) if is_course_blocked(self.request, redeemed_registration_codes, self.course_key): # registration codes may be generated via Bulk Purchase Scenario # we have to check only for the invoice generated registration codes # that their invoice is valid or not # TODO Update message to account for the fact that the user is not authenticated. log.warning( u'User %s cannot access the course %s because payment has not yet been received', self.real_user, unicode(self.course_key), ) raise CourseAccessRedirect(reverse('dashboard'))
def render_to_fragment(self, request, course_id=None, **kwargs): """ Renders the course's home page as a fragment. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) # Render the course dates as a fragment dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) # Render the full content to enrolled users, as well as to course and global staff. # Unenrolled users who are not course or global staff are given only a subset. is_enrolled = CourseEnrollment.is_enrolled(request.user, course_key) is_staff = has_access(request.user, 'staff', course_key) if is_enrolled or is_staff: outline_fragment = CourseOutlineFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) welcome_message_fragment = WelcomeMessageFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) course_sock_fragment = CourseSockFragmentView().render_to_fragment(request, course=course, **kwargs) has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id) else: # Redirect the user to the dashboard if they are not enrolled and # this is a course that does not support direct enrollment. if not can_self_enroll_in_course(course_key): raise CourseAccessRedirect(reverse('dashboard')) # Set all the fragments outline_fragment = None welcome_message_fragment = None course_sock_fragment = None has_visited_course = None resume_course_url = None # Get the handouts handouts_html = self._get_course_handouts(request, course) # Get the course tools enabled for this user and course course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key) # Render the course home fragment context = { 'request': request, 'csrf': csrf(request)['csrf_token'], 'course': course, 'course_key': course_key, 'outline_fragment': outline_fragment, 'handouts_html': handouts_html, 'has_visited_course': has_visited_course, 'resume_course_url': resume_course_url, 'course_tools': course_tools, 'dates_fragment': dates_fragment, 'welcome_message_fragment': welcome_message_fragment, 'course_sock_fragment': course_sock_fragment, 'disable_courseware_js': True, 'uses_pattern_library': True, } html = render_to_string('course_experience/course-home-fragment.html', context) return Fragment(html)
def _redirect_if_needed_to_enter_university_id(self): # pylint: disable=invalid-name """ Redirect to University ID view if the user has to have a valid university ID before continuing to the course. """ if university_id_is_required(self.request.user, self.course): raise CourseAccessRedirect( reverse('edraak_university:id', args=[unicode(self.course.id)]))
def check_course_access_with_redirect(course, user, action, check_if_enrolled=False, check_survey_complete=True, check_if_authenticated=False): # lint-amnesty, pylint: disable=line-too-long """ Check that the user has the access to perform the specified action on the course (CourseBlock|CourseOverview). check_if_enrolled: If true, additionally verifies that the user is enrolled. check_survey_complete: If true, additionally verifies that the user has completed the survey. """ request = get_current_request() check_content_start_date_for_masquerade_user(course.id, user, request, course.start) access_response = check_course_access(course, user, action, check_if_enrolled, check_survey_complete, check_if_authenticated) # lint-amnesty, pylint: disable=line-too-long if not access_response: # Redirect if StartDateError if isinstance(access_response, StartDateError): start_date = strftime_localized(course.start, 'SHORT_DATE') params = QueryDict(mutable=True) params['notlive'] = start_date raise CourseAccessRedirect( '{dashboard_url}?{params}'.format( dashboard_url=reverse('dashboard'), params=params.urlencode()), access_response) # Redirect if AuditExpiredError if isinstance(access_response, AuditExpiredError): params = QueryDict(mutable=True) params[ 'access_response_error'] = access_response.additional_context_user_message raise CourseAccessRedirect( '{dashboard_url}?{params}'.format( dashboard_url=reverse('dashboard'), params=params.urlencode()), access_response) # Redirect if the user must answer a survey before entering the course. if isinstance(access_response, MilestoneAccessError): raise CourseAccessRedirect( '{dashboard_url}'.format(dashboard_url=reverse('dashboard'), ), access_response) # Redirect if the user is not enrolled and must be to see content if isinstance(access_response, EnrollmentRequiredAccessError): raise CourseAccessRedirect( reverse('about_course', args=[str(course.id)])) # Redirect if user must be authenticated to view the content if isinstance(access_response, AuthenticationRequiredAccessError): raise CourseAccessRedirect( reverse('about_course', args=[str(course.id)])) # Redirect if the user must answer a survey before entering the course. if isinstance(access_response, SurveyRequiredAccessError): raise CourseAccessRedirect( reverse('course_survey', args=[str(course.id)])) # Deliberately return a non-specific error message to avoid # leaking info about access control settings raise CoursewareAccessException(access_response)
def _redirect_if_not_requested_section(self): """ If the resulting section and chapter are different from what was initially requested, redirect back to the index page, but with an updated URL that includes the correct section and chapter values. We do this so that our analytics events and error logs have the appropriate URLs. """ if (self.chapter.url_name != self.original_chapter_url_name or (self.original_section_url_name and self.section.url_name != self.original_section_url_name)): raise CourseAccessRedirect( reverse( 'courseware_section', kwargs={ 'course_id': unicode(self.course_key), 'chapter': self.chapter.url_name, 'section': self.section.url_name, }, ))
def check_course_access(course, user, action, check_if_enrolled=False): """ Check that the user has the access to perform the specified action on the course (CourseDescriptor|CourseOverview). check_if_enrolled: If true, additionally verifies that the user is either enrolled in the course or has staff access. """ access_response = has_access(user, action, course, course.id) if not access_response: # Deliberately return a non-specific error message to avoid # leaking info about access control settings raise CoursewareAccessException(access_response) if check_if_enrolled: # Verify that the user is either enrolled in the course or a staff # member. If the user is not enrolled, raise a Redirect exception # that will be handled by middleware. if not ((user.id and CourseEnrollment.is_enrolled(user, course.id)) or has_access(user, 'staff', course)): raise CourseAccessRedirect(reverse('about_course', args=[unicode(course.id)]))
def render_to_fragment(self, request, course_id=None, **kwargs): # lint-amnesty, pylint: disable=arguments-differ, too-many-statements """ Renders the course's home page as a fragment. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) # Render the course dates as a fragment dates_fragment = CourseDatesFragmentView().render_to_fragment( request, course_id=course_id, **kwargs) # Render the full content to enrolled users, as well as to course and global staff. # Unenrolled users who are not course or global staff are given only a subset. enrollment = CourseEnrollment.get_enrollment(request.user, course_key) user_access = { 'is_anonymous': request.user.is_anonymous, 'is_enrolled': enrollment and enrollment.is_active, 'is_staff': has_access(request.user, 'staff', course_key), } allow_anonymous = COURSE_ENABLE_UNENROLLED_ACCESS_FLAG.is_enabled( course_key) allow_public = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC allow_public_outline = allow_anonymous and course.course_visibility == COURSE_VISIBILITY_PUBLIC_OUTLINE # Set all the fragments outline_fragment = None update_message_fragment = None course_sock_fragment = None offer_banner_fragment = None course_expiration_fragment = None has_visited_course = None resume_course_url = None handouts_html = None course_overview = CourseOverview.get_from_id(course.id) if user_access['is_enrolled'] or user_access['is_staff']: outline_fragment = CourseOutlineFragmentView().render_to_fragment( request, course_id=course_id, **kwargs) if LATEST_UPDATE_FLAG.is_enabled(course_key): update_message_fragment = LatestUpdateFragmentView( ).render_to_fragment(request, course_id=course_id, **kwargs) else: update_message_fragment = WelcomeMessageFragmentView( ).render_to_fragment(request, course_id=course_id, **kwargs) course_sock_fragment = CourseSockFragmentView().render_to_fragment( request, course=course, **kwargs) has_visited_course, resume_course_url = self._get_resume_course_info( request, course_id) handouts_html = self._get_course_handouts(request, course) offer_banner_fragment = get_first_purchase_offer_banner_fragment( request.user, course_overview) course_expiration_fragment = generate_course_expired_fragment( request.user, course_overview) elif allow_public_outline or allow_public: outline_fragment = CourseOutlineFragmentView().render_to_fragment( request, course_id=course_id, user_is_enrolled=False, **kwargs) course_sock_fragment = CourseSockFragmentView().render_to_fragment( request, course=course, **kwargs) if allow_public: handouts_html = self._get_course_handouts(request, course) else: # Redirect the user to the dashboard if they are not enrolled and # this is a course that does not support direct enrollment. if not can_self_enroll_in_course(course_key): raise CourseAccessRedirect(reverse('dashboard')) # Get the course tools enabled for this user and course course_tools = CourseToolsPluginManager.get_enabled_course_tools( request, course_key) # Check if the user can access the course goal functionality has_goal_permission = has_course_goal_permission( request, course_id, user_access) # Grab the current course goal and the acceptable course goal keys mapped to translated values current_goal = get_course_goal(request.user, course_key) goal_options = get_course_goal_options() # Get the course goals api endpoint goal_api_url = get_goal_api_url(request) # Grab the course home messages fragment to render any relevant django messages course_home_message_fragment = CourseHomeMessageFragmentView( ).render_to_fragment(request, course_id=course_id, user_access=user_access, **kwargs) # Get info for upgrade messaging upgrade_price = None upgrade_url = None has_discount = False # TODO Add switch to control deployment if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled( course_key) and can_show_verified_upgrade( request.user, enrollment, course): upgrade_url = verified_upgrade_deadline_link(request.user, course_id=course_key) upgrade_price, has_discount = format_strikeout_price( request.user, course_overview) show_search = ( settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH') or (settings.FEATURES.get('ENABLE_COURSEWARE_SEARCH_FOR_COURSE_STAFF') and user_access['is_staff'])) # Render the course home fragment context = { 'request': request, 'csrf': csrf(request)['csrf_token'], 'course': course, 'course_key': course_key, 'outline_fragment': outline_fragment, 'handouts_html': handouts_html, 'course_home_message_fragment': course_home_message_fragment, 'offer_banner_fragment': offer_banner_fragment, 'course_expiration_fragment': course_expiration_fragment, 'has_visited_course': has_visited_course, 'resume_course_url': resume_course_url, 'course_tools': course_tools, 'dates_fragment': dates_fragment, 'username': request.user.username, 'goal_api_url': goal_api_url, 'has_goal_permission': has_goal_permission, 'goal_options': goal_options, 'current_goal': current_goal, 'update_message_fragment': update_message_fragment, 'course_sock_fragment': course_sock_fragment, 'disable_courseware_js': True, 'uses_bootstrap': True, 'upgrade_price': upgrade_price, 'upgrade_url': upgrade_url, 'has_discount': has_discount, 'show_search': show_search, } html = render_to_string('course_experience/course-home-fragment.html', context) return Fragment(html)
def render_to_fragment(self, request, course_id=None, **kwargs): """ Renders the course's home page as a fragment. """ course_key = CourseKey.from_string(course_id) course = get_course_with_access(request.user, 'load', course_key) # Render the course dates as a fragment dates_fragment = CourseDatesFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) # Render the full content to enrolled users, as well as to course and global staff. # Unenrolled users who are not course or global staff are given only a subset. enrollment = CourseEnrollment.get_enrollment(request.user, course_key) user_access = { 'is_anonymous': request.user.is_anonymous(), 'is_enrolled': enrollment is not None, 'is_staff': has_access(request.user, 'staff', course_key), } if user_access['is_enrolled'] or user_access['is_staff']: outline_fragment = CourseOutlineFragmentView().render_to_fragment(request, course_id=course_id, **kwargs) if LATEST_UPDATE_FLAG.is_enabled(course_key): update_message_fragment = LatestUpdateFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) else: update_message_fragment = WelcomeMessageFragmentView().render_to_fragment( request, course_id=course_id, **kwargs ) course_sock_fragment = CourseSockFragmentView().render_to_fragment(request, course=course, **kwargs) has_visited_course, resume_course_url = self._get_resume_course_info(request, course_id) else: # Redirect the user to the dashboard if they are not enrolled and # this is a course that does not support direct enrollment. if not can_self_enroll_in_course(course_key): raise CourseAccessRedirect(reverse('dashboard')) # Set all the fragments outline_fragment = None update_message_fragment = None course_sock_fragment = None has_visited_course = None resume_course_url = None # Get the handouts handouts_html = self._get_course_handouts(request, course) # Get the course tools enabled for this user and course course_tools = CourseToolsPluginManager.get_enabled_course_tools(request, course_key) # Check if the user can access the course goal functionality has_goal_permission = has_course_goal_permission(request, course_id, user_access) # Grab the current course goal and the acceptable course goal keys mapped to translated values current_goal = get_course_goal(request.user, course_key) goal_options = get_course_goal_options() # Get the course goals api endpoint goal_api_url = get_goal_api_url(request) # Grab the course home messages fragment to render any relevant django messages course_home_message_fragment = CourseHomeMessageFragmentView().render_to_fragment( request, course_id=course_id, user_access=user_access, **kwargs ) # Get info for upgrade messaging upgrade_price = None upgrade_url = None # TODO Add switch to control deployment if SHOW_UPGRADE_MSG_ON_COURSE_HOME.is_enabled(course_key) and enrollment and enrollment.upgrade_deadline: upgrade_url = EcommerceService().upgrade_url(request.user, course_key) upgrade_price = get_cosmetic_verified_display_price(course) # Render the course home fragment context = { 'request': request, 'csrf': csrf(request)['csrf_token'], 'course': course, 'course_key': course_key, 'outline_fragment': outline_fragment, 'handouts_html': handouts_html, 'course_home_message_fragment': course_home_message_fragment, 'has_visited_course': has_visited_course, 'resume_course_url': resume_course_url, 'course_tools': course_tools, 'dates_fragment': dates_fragment, 'username': request.user.username, 'goal_api_url': goal_api_url, 'has_goal_permission': has_goal_permission, 'goal_options': goal_options, 'current_goal': current_goal, 'update_message_fragment': update_message_fragment, 'course_sock_fragment': course_sock_fragment, 'disable_courseware_js': True, 'uses_pattern_library': True, 'upgrade_price': upgrade_price, 'upgrade_url': upgrade_url, } html = render_to_string('course_experience/course-home-fragment.html', context) return Fragment(html)
def get(self, request, course_id, chapter=None, section=None, position=None): """ Displays courseware accordion and associated content. If course, chapter, and section are all specified, renders the page, or returns an error if they are invalid. If section is not specified, displays the accordion opened to the right chapter. If neither chapter or section are specified, displays the user's most recent chapter, or the first chapter if this is the user's first visit. Arguments: request: HTTP request course_id (unicode): course id chapter (unicode): chapter url_name section (unicode): section url_name position (unicode): position in module, eg of <sequential> module """ self.course_key = CourseKey.from_string(course_id) if not (request.user.is_authenticated or self.enable_unenrolled_access): return redirect_to_login(request.get_full_path()) self.original_chapter_url_name = chapter self.original_section_url_name = section self.chapter_url_name = chapter self.section_url_name = section self.position = position self.chapter, self.section = None, None self.course = None self.url = request.path try: set_custom_metrics_for_course_key(self.course_key) self._clean_position() with modulestore().bulk_operations(self.course_key): self.course = get_course_with_access( request.user, 'load', self.course_key, depth=CONTENT_DEPTH, check_if_enrolled=False, ) is_enrolled = CourseEnrollment.is_enrolled( request.user, self.course_key) if is_enrolled: self.view = STUDENT_VIEW elif self.enable_unenrolled_access and self.course.course_visibility == COURSE_VISIBILITY_PUBLIC: self.view = PUBLIC_VIEW else: raise CourseAccessRedirect( reverse('about_course', args=[unicode(self.course_key)])) self.is_staff = has_access(request.user, 'staff', self.course) self._setup_masquerade_for_effective_user() register_course_expired_message(request, self.course) return self.render(request) except Exception as exception: # pylint: disable=broad-except return CourseTabView.handle_exceptions(request, self.course, exception)