Пример #1
0
def get_feedback_form_context(request):
    """
    Extract the submitted form fields to be used as a context for
    feedback submission.
    """
    context = {}

    context["subject"] = request.POST["subject"]
    context["details"] = request.POST["details"]
    context["tags"] = dict(
        [(tag, request.POST[tag]) for tag in ["issue_type", "course_id"] if request.POST.get(tag)]
    )

    context["additional_info"] = {}

    if UserProfile.has_registered(request.user):
        context["realname"] = request.user.profile.name
        context["email"] = request.user.email
        context["additional_info"]["username"] = request.user.username
    else:
        context["realname"] = request.POST["name"]
        context["email"] = request.POST["email"]

    for header, pretty in [("HTTP_REFERER", "Page"), ("HTTP_USER_AGENT", "Browser"), ("REMOTE_ADDR", "Client IP"),
                           ("SERVER_NAME", "Host")]:
        context["additional_info"][pretty] = request.META.get(header)

    context["support_email"] = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)

    return context
Пример #2
0
def get_course_tab_list(request, course):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user = request.user
    is_user_enrolled = user.is_authenticated() and CourseEnrollment.is_enrolled(user, course.id)
    xmodule_tab_list = CourseTabList.iterate_displayable(
        course,
        user=user,
        settings=settings,
        is_user_authenticated=user.is_authenticated(),
        is_user_staff=has_access(user, 'staff', course, course.id),
        is_user_enrolled=is_user_enrolled,
        is_user_sneakpeek=not UserProfile.has_registered(user),
    )

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work.
    # If the user has to take an entrance exam, we'll need to hide away all but the
    # "Courseware" tab. The tab is then renamed as "Entrance Exam".
    course_tab_list = []
    must_complete_ee = user_must_complete_entrance_exam(request, user, course)
    for tab in xmodule_tab_list:
        if must_complete_ee:
            # Hide all of the tabs except for 'Courseware'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type is not 'courseware':
                continue
            tab.name = _("Entrance Exam")
        course_tab_list.append(tab)

    # Add in any dynamic tabs, i.e. those that are not persisted
    course_tab_list += _get_dynamic_tabs(course, user)
    return course_tab_list
Пример #3
0
    def can_load():
        """
        NOTE: This does not check that the student is enrolled in the course
        that contains this module.  We may or may not want to allow non-enrolled
        students to see modules.  If not, views should check the course, so we
        don't have to hit the enrollments table on every module load.
        """
        if user.is_authenticated():
            if not UserProfile.has_registered(user):
                if not _can_load_descriptor_nonregistered(descriptor):
                    return ACCESS_DENIED
        response = (
            _visible_to_nonstaff_users(descriptor)
            and _has_group_access(descriptor, user, course_key)
            and
            (
                _has_detached_class_tag(descriptor)
                or _can_access_descriptor_with_start_date(user, descriptor, course_key)
            )
        )

        return (
            ACCESS_GRANTED if (response or _has_staff_access_to_descriptor(user, descriptor, course_key))
            else response
        )
Пример #4
0
    def can_load():
        """
        NOTE: This does not check that the student is enrolled in the course
        that contains this module.  We may or may not want to allow non-enrolled
        students to see modules.  If not, views should check the course, so we
        don't have to hit the enrollments table on every module load.
        """
        # Stanford Sneak Peek permissions
        if user.is_authenticated():
            if not UserProfile.has_registered(user):
                if not _can_load_descriptor_nonregistered(descriptor):
                    return ACCESS_DENIED
        # / Stanford Sneak Peek permissions

        if _has_staff_access_to_descriptor(user, descriptor, course_key):
            return ACCESS_GRANTED

        # if the user has staff access, they can load the module so this code doesn't need to run
        return (
            _visible_to_nonstaff_users(descriptor) and
            _can_access_descriptor_with_milestones(user, descriptor, course_key) and
            _has_group_access(descriptor, user, course_key) and
            (
                _has_detached_class_tag(descriptor) or
                _can_access_descriptor_with_start_date(user, descriptor, course_key)
            )
        )
Пример #5
0
    def can_load():
        """
        NOTE: This does not check that the student is enrolled in the course
        that contains this module.  We may or may not want to allow non-enrolled
        students to see modules.  If not, views should check the course, so we
        don't have to hit the enrollments table on every module load.
        """
        # Stanford Sneak Peek permissions
        if user.is_authenticated():
            if not UserProfile.has_registered(user):
                if not _can_load_descriptor_nonregistered(descriptor):
                    return ACCESS_DENIED
        # / Stanford Sneak Peek permissions

        if _has_staff_access_to_descriptor(user, descriptor, course_key):
            return ACCESS_GRANTED

        # if the user has staff access, they can load the module so this code doesn't need to run
        return (_visible_to_nonstaff_users(descriptor)
                and _can_access_descriptor_with_milestones(
                    user, descriptor, course_key)
                and _has_group_access(descriptor, user, course_key)
                and (_has_detached_class_tag(descriptor)
                     or _can_access_descriptor_with_start_date(
                         user, descriptor, course_key)))
Пример #6
0
def get_feedback_form_context(request):
    """
    Extract the submitted form fields to be used as a context for
    feedback submission.
    """
    context = {}

    context["subject"] = request.POST["subject"]
    context["details"] = request.POST["details"]
    context["tags"] = dict(
        [(tag, request.POST[tag]) for tag in ["issue_type", "course_id"] if tag in request.POST]
    )

    context["additional_info"] = {}

    if UserProfile.has_registered(request.user):
        context["realname"] = request.user.profile.name
        context["email"] = request.user.email
        context["additional_info"]["username"] = request.user.username
    else:
        context["realname"] = request.POST["name"]
        context["email"] = request.POST["email"]

    for header, pretty in [("HTTP_REFERER", "Page"), ("HTTP_USER_AGENT", "Browser"), ("REMOTE_ADDR", "Client IP"),
                           ("SERVER_NAME", "Host")]:
        context["additional_info"][pretty] = request.META.get(header)

    context["support_email"] = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL)

    return context
Пример #7
0
    def can_load():
        """
        NOTE: This does not check that the student is enrolled in the course
        that contains this module.  We may or may not want to allow non-enrolled
        students to see modules.  If not, views should check the course, so we
        don't have to hit the enrollments table on every module load.
        """
        if user.is_authenticated():
            if not UserProfile.has_registered(user):
                if not _can_load_descriptor_nonregistered(descriptor):
                    return ACCESS_DENIED

        # If the user (or the role the user is currently masquerading as) does not have
        # access to this content, then deny access. The problem with calling _has_staff_access_to_descriptor
        # before this method is that _has_staff_access_to_descriptor short-circuits and returns True
        # for staff users in preview mode.
        if not _has_group_access(descriptor, user, course_key):
            return ACCESS_DENIED

        # If the user has staff access, they can load the module and checks below are not needed.
        if _has_staff_access_to_descriptor(user, descriptor, course_key):
            return ACCESS_GRANTED

        return (_visible_to_nonstaff_users(descriptor)
                and _can_access_descriptor_with_milestones(
                    user, descriptor, course_key)
                and (_has_detached_class_tag(descriptor)
                     or _can_access_descriptor_with_start_date(
                         user, descriptor, course_key)))
Пример #8
0
def get_course_tab_list(course, user):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user_is_enrolled = user.is_authenticated() and CourseEnrollment.is_enrolled(user, course.id)
    xmodule_tab_list = CourseTabList.iterate_displayable(
        course,
        settings,
        user.is_authenticated(),
        has_access(user, 'staff', course, course.id),
        user_is_enrolled,
        not UserProfile.has_registered(user),
    )

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work
    # If the user has to take an entrance exam, we'll need to hide away all of the tabs
    # except for the Courseware and Instructor tabs (latter is only viewed if applicable)
    # We don't have access to the true request object in this context, but we can use a mock
    request = RequestFactory().request()
    request.user = user
    course_tab_list = []
    for tab in xmodule_tab_list:
        if user_must_complete_entrance_exam(request, user, course):
            # Hide all of the tabs except for 'Courseware' and 'Instructor'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type not in ['courseware', 'instructor']:
                continue
            if tab.type == 'courseware':
                tab.name = _("Entrance Exam")
        course_tab_list.append(tab)
    return course_tab_list
Пример #9
0
 def can_load_forum():
     """
     Can this user access the forums in this course?
     """
     return (
         can_load()
         and
         UserProfile.has_registered(user)
     )
Пример #10
0
 def process_request(self, request):
     """
     Log out all sneakpeek users and redirect the same URL
     """
     if request.user.is_anonymous():
         return None
     if UserProfile.has_registered(request.user):
         return None
     logout(request)
     return redirect(request.get_full_path())
Пример #11
0
 def can_load_forum():
     """
     Can this user access the forums in this course?
     """
     return (
         can_load() and
         UserProfile.has_registered(user) and
         (
             CourseEnrollment.is_enrolled(user, course.id) or
             _has_staff_access_to_descriptor(user, course, course.id)
         )
     )
Пример #12
0
def login_and_registration_form(request, initial_mode="login"):
    """Render the combined login/registration form, defaulting to login

    This relies on the JS to asynchronously load the actual form from
    the user_api.

    Keyword Args:
        initial_mode (string): Either "login" or "register".

    """
    # If we're already logged in, redirect to the dashboard
    if UserProfile.has_registered(request.user):
        return redirect(reverse("dashboard"))

    # Retrieve the form descriptions from the user API
    form_descriptions = _get_form_descriptions(request)

    # If this is a microsite, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    if microsite.is_request_in_microsite():
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # Otherwise, render the combined login/registration page
    context = {
        "disable_courseware_js": True,
        "initial_mode": initial_mode,
        "third_party_auth": json.dumps(_third_party_auth_context(request)),
        "platform_name": settings.PLATFORM_NAME,
        "account_name": settings.ACCOUNT_NAME,
        "responsive": True,
        # Include form descriptions retrieved from the user API.
        # We could have the JS client make these requests directly,
        # but we include them in the initial page load to avoid
        # the additional round-trip to the server.
        "login_form_desc": form_descriptions["login"],
        "registration_form_desc": form_descriptions["registration"],
        "password_reset_form_desc": form_descriptions["password_reset"],
        # We need to pass these parameters so that the header's
        # "Sign In" button preserves the querystring params.
        "enrollment_action": request.GET.get("enrollment_action"),
        "course_id": request.GET.get("course_id"),
        "course_mode": request.GET.get("course_mode"),
    }

    return render_to_response("student_account/login_and_register.html", context)
Пример #13
0
    def process_request(self, request):
        """
        logs out all sneakpeek users and then retries (redirects) the same URL
        """
        #Do nothing with AnonymousUser
        if request.user.is_anonymous():
            return None

        #Do nothing with non-sneakpeek user
        if UserProfile.has_registered(request.user):
            return None

        logout(request)
        return redirect(request.get_full_path())
Пример #14
0
def index(request):
    '''
    Redirects to main page -- info page if user authenticated, or marketing if not
    '''

    if UserProfile.has_registered(request.user):
        # Only redirect to dashboard if user has
        # courses in his/her dashboard. Otherwise UX is a bit cryptic.
        # In this case, we want to have the user stay on a course catalog
        # page to make it easier to browse for courses (and register)
        if configuration_helpers.get_value(
                'ALWAYS_REDIRECT_HOMEPAGE_TO_DASHBOARD_FOR_AUTHENTICATED_USER',
                settings.FEATURES.get('ALWAYS_REDIRECT_HOMEPAGE_TO_DASHBOARD_FOR_AUTHENTICATED_USER', True)):
            return redirect(reverse('dashboard'))

    if settings.FEATURES.get('AUTH_USE_CERTIFICATES'):
        from openedx.core.djangoapps.external_auth.views import ssl_login
        # Set next URL to dashboard if it isn't set to avoid
        # caching a redirect to / that causes a redirect loop on logout
        if not request.GET.get('next'):
            req_new = request.GET.copy()
            req_new['next'] = reverse('dashboard')
            request.GET = req_new
        return ssl_login(request)

    enable_mktg_site = configuration_helpers.get_value(
        'ENABLE_MKTG_SITE',
        settings.FEATURES.get('ENABLE_MKTG_SITE', False)
    )

    if enable_mktg_site:
        marketing_urls = configuration_helpers.get_value(
            'MKTG_URLS',
            settings.MKTG_URLS
        )
        return redirect(marketing_urls.get('ROOT'))

    domain = request.META.get('HTTP_HOST')

    # keep specialized logic for Edge until we can migrate over Edge to fully use
    # configuration.
    if domain and 'edge.edx.org' in domain:
        return redirect(reverse("signin_user"))

    #  we do not expect this case to be reached in cases where
    #  marketing and edge are enabled
    return student.views.index(request, user=request.user)
Пример #15
0
def request_certificate(request):
    """Request the on-demand creation of a certificate for some user, course.

    A request doesn't imply a guarantee that such a creation will take place.
    We intentionally use the same machinery as is used for doing certification
    at the end of a course run, so that we can be sure users get graded and
    then if and only if they pass, do they get a certificate issued.
    """
    # Memoize user information; return error if it's invalid
    user = None
    username = ''
    try:
        user = request.user
        username = user.username
    except AttributeError:
        return HttpResponse(json.dumps({'add_status': 'error', 'error': 'ERRORBADREQUEST'}), mimetype='application/json')

    # It is an error to hit this endpoint with anything but a POST
    if request.method != "POST":
        return HttpResponse(json.dumps({'add_status': 'error', 'error': 'ERRORNOPOST'}), mimetype='application/json')

    # It is an error to hit this endpoint as an anonymous/nonregistered user
    if not (user.is_authenticated() and UserProfile.has_registered(user)):
        return HttpResponse(json.dumps({'add_status': 'error', 'error': 'ERRORANONYMOUSUSER'}), mimetype='application/json')

    xq = XQueueCertInterface()
    student = User.objects.get(username=username)
    course_key = SlashSeparatedCourseKey.from_deprecated_string(request.POST.get('course_id'))
    course = modulestore().get_course(course_key, depth=2)
    title = 'None'
    if use_cme:
        titlelist = CmeUserProfile.objects.filter(user=student).values('professional_designation')
        if len(titlelist):
            title = titlelist[0]['professional_designation']

    status = certificate_status_for_student(student, course_key)['status']
    if status in [CertificateStatuses.unavailable, CertificateStatuses.notpassing, CertificateStatuses.error]:
        log_msg = u'Grading and certification requested for user %s in course %s via /request_certificate call'
        logger.info(log_msg, username, course_key)
        status = xq.add_cert(student, course_key, course=course, title=title)
    return HttpResponse(json.dumps({'add_status': status, 'error': ''}), mimetype='application/json')
Пример #16
0
    def can_load():
        """
        NOTE: This does not check that the student is enrolled in the course
        that contains this module.  We may or may not want to allow non-enrolled
        students to see modules.  If not, views should check the course, so we
        don't have to hit the enrollments table on every module load.
        """
        if descriptor.visible_to_staff_only and not _has_staff_access_to_descriptor(user, descriptor, course_key):
            return False

        # enforce group access
        if not _has_group_access(descriptor, user, course_key):
            # if group_access check failed, deny access unless the requestor is staff,
            # in which case immediately grant access.
            return _has_staff_access_to_descriptor(user, descriptor, course_key)

        # If start dates are off, can always load
        if settings.FEATURES['DISABLE_START_DATES'] and not is_masquerading_as_student(user, course_key):
            debug("Allow: DISABLE_START_DATES")
            return True

        # Check start date
        if 'detached' not in descriptor._class_tags and descriptor.start is not None:
            now = datetime.now(UTC())
            effective_start = _adjust_start_date_for_beta_testers(
                user,
                descriptor,
                course_key=course_key
            )
            if now > effective_start:
                # after start date, all registered users can see it
                # nonregistered users shouldn't be able to access certain descriptor types
                debug("Allow: now > effective start date")
                return UserProfile.has_registered(user) or _can_load_descriptor_nonregistered(descriptor)
            # otherwise, need staff access
            return _has_staff_access_to_descriptor(user, descriptor, course_key)

        # No start date, so can always load.
        debug("Allow: no start date")
        return True
Пример #17
0
def get_course_tab_list(request, course):
    """
    Retrieves the course tab list from xmodule.tabs and manipulates the set as necessary
    """
    user = request.user
    is_user_enrolled = user.is_authenticated(
    ) and CourseEnrollment.is_enrolled(user, course.id)
    xmodule_tab_list = CourseTabList.iterate_displayable(
        course,
        user=user,
        settings=settings,
        is_user_authenticated=user.is_authenticated(),
        is_user_staff=has_access(user, 'staff', course, course.id),
        is_user_enrolled=is_user_enrolled,
        is_user_sneakpeek=not UserProfile.has_registered(user),
    )

    # Now that we've loaded the tabs for this course, perform the Entrance Exam work.
    # If the user has to take an entrance exam, we'll need to hide away all but the
    # "Courseware" tab. The tab is then renamed as "Entrance Exam".
    course_tab_list = []
    must_complete_ee = not user_can_skip_entrance_exam(user, course)
    for tab in xmodule_tab_list:
        if must_complete_ee:
            # Hide all of the tabs except for 'Courseware'
            # Rename 'Courseware' tab to 'Entrance Exam'
            if tab.type != 'courseware':
                continue
            tab.name = _("Entrance Exam")
        if tab.type == 'static_tab' and tab.course_staff_only and \
                not bool(user and has_access(user, 'staff', course, course.id)):
            continue
        course_tab_list.append(tab)

    # Add in any dynamic tabs, i.e. those that are not persisted
    course_tab_list += _get_dynamic_tabs(course, user)
    return course_tab_list
Пример #18
0
 def assertSuccessfulSneakPeek(self, request, course):
     self.assertTrue(request.user.is_authenticated())
     self.assertFalse(UserProfile.has_registered(request.user))
     self.assertTrue(CourseEnrollment.is_enrolled(request.user, course.id))
Пример #19
0
def login_and_registration_form(request, initial_mode="login"):
    """Render the combined login/registration form, defaulting to login

    This relies on the JS to asynchronously load the actual form from
    the user_api.

    Keyword Args:
        initial_mode (string): Either "login" or "register".

    """
    # Determine the URL to redirect to following login/registration/third_party_auth
    redirect_to = get_next_url_for_login_page(request)

    # If we're already logged in, redirect to the dashboard
    if UserProfile.has_registered(request.user):
        return redirect(redirect_to)

    # Retrieve the form descriptions from the user API
    form_descriptions = _get_form_descriptions(request)

    # If this is a microsite, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Microsites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their microsites configuration file.
    if microsite.is_request_in_microsite() and not microsite.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check.
    # If present, we display a login page focused on third-party auth with that provider.
    third_party_auth_hint = None
    if '?' in redirect_to:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            if third_party_auth.provider.Registry.get(provider_id=provider_id):
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    # Otherwise, render the combined login/registration page
    context = {
        'login_redirect_url': redirect_to,  # This gets added to the query string of the "Sign In" button in the header
        'disable_courseware_js': True,
        'initial_mode': initial_mode,
        'third_party_auth': json.dumps(_third_party_auth_context(request, redirect_to)),
        'third_party_auth_hint': third_party_auth_hint or '',
        'platform_name': settings.PLATFORM_NAME,
        'account_name': settings.ACCOUNT_NAME,
        'responsive': True,

        # Include form descriptions retrieved from the user API.
        # We could have the JS client make these requests directly,
        # but we include them in the initial page load to avoid
        # the additional round-trip to the server.
        'login_form_desc': form_descriptions['login'],
        'registration_form_desc': form_descriptions['registration'],
        'password_reset_form_desc': form_descriptions['password_reset'],
    }

    return render_to_response('student_account/login_and_register.html', context)
Пример #20
0
def submit_feedback(request):
    """
    Create a Zendesk ticket or if not available, send an email with the
    feedback form fields.

    If feedback submission is not enabled, any request will raise `Http404`.
    If any configuration parameter (`ZENDESK_URL`, `ZENDESK_USER`, or
    `ZENDESK_API_KEY`) is missing, any request will raise an `Exception`.
    The request must be a POST request specifying `subject` and `details`.
    If the user is not authenticated, the request must also specify `name` and
    `email`. If the user is authenticated, the `name` and `email` will be
    populated from the user's information. If any required parameter is
    missing, a 400 error will be returned indicating which field is missing and
    providing an error message. If Zendesk ticket creation fails, 500 error
    will be returned with no body; if ticket creation succeeds, an empty
    successful response (200) will be returned.
    """
    if not settings.FEATURES.get('ENABLE_FEEDBACK_SUBMISSION', False):
        raise Http404()
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    def build_error_response(status_code, field, err_msg):
        return HttpResponse(json.dumps({"field": field, "error": err_msg}), status=status_code)

    required_fields = ["subject", "details"]

    if not UserProfile.has_registered(request.user):
        required_fields += ["name", "email"]

    required_field_errs = {
        "subject": "Please provide a subject.",
        "details": "Please provide details.",
        "name": "Please provide your name.",
        "email": "Please provide a valid e-mail.",
    }
    for field in required_fields:
        if field not in request.POST or not request.POST[field]:
            return build_error_response(400, field, required_field_errs[field])

    if not UserProfile.has_registered(request.user):
        try:
            validate_email(request.POST["email"])
        except ValidationError:
            return build_error_response(400, "email", required_field_errs["email"])

    success = False
    context = get_feedback_form_context(request)
    support_backend = configuration_helpers.get_value('CONTACT_FORM_SUBMISSION_BACKEND', SUPPORT_BACKEND_ZENDESK)

    if support_backend == SUPPORT_BACKEND_EMAIL:
        try:
            send_mail(
                subject=render_to_string('emails/contact_us_feedback_email_subject.txt', context),
                message=render_to_string('emails/contact_us_feedback_email_body.txt', context),
                from_email=context["support_email"],
                recipient_list=[context["support_email"]],
                fail_silently=False
            )
            success = True
        except SMTPException:
            log.exception('Error sending feedback to contact_us email address.')
            success = False

    else:
        if not settings.ZENDESK_URL or not settings.ZENDESK_USER or not settings.ZENDESK_API_KEY:
            raise Exception("Zendesk enabled but not configured")

        success = _record_feedback_in_zendesk(
            context["realname"],
            context["email"],
            context["subject"],
            context["details"],
            context["tags"],
            context["additional_info"],
            support_email=context["support_email"]
        )

    _record_feedback_in_datadog(context["tags"])

    return HttpResponse(status=(200 if success else 500))
Пример #21
0
def login_and_registration_form(request, initial_mode="login"):
    """Render the combined login/registration form, defaulting to login

    This relies on the JS to asynchronously load the actual form from
    the user_api.

    Keyword Args:
        initial_mode (string): Either "login" or "register".

    """
    # Determine the URL to redirect to following login/registration/third_party_auth
    redirect_to = get_next_url_for_login_page(request)
    # If we're already logged in, redirect to the dashboard
    if UserProfile.has_registered(request.user):
        return redirect(redirect_to)

    if third_party_auth.is_enabled():
        force_provider_id = settings.FORCED_TPA_PROVIDER_ID
        if force_provider_id:
            force_provider = third_party_auth.provider.Registry.get(
                provider_id=force_provider_id, )
            if force_provider and force_provider.display_for_login:
                running_pipeline = third_party_auth.pipeline.get(request)
                if not running_pipeline:
                    if initial_mode in [
                            pipeline.AUTH_ENTRY_LOGIN,
                            pipeline.AUTH_ENTRY_REGISTER
                    ]:
                        tpa_url = pipeline.get_login_url(
                            force_provider_id,
                            initial_mode,
                            redirect_url=redirect_to,
                        )
                        return redirect(tpa_url)

    # Retrieve the form descriptions from the user API
    form_descriptions = _get_form_descriptions(request)

    # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check.
    # If present, we display a login page focused on third-party auth with that provider.
    third_party_auth_hint = None
    if '?' in redirect_to:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            if third_party_auth.provider.Registry.get(provider_id=provider_id):
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    set_enterprise_branding_filter_param(request=request,
                                         provider_id=third_party_auth_hint)

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their
    # configuration settings.
    if is_request_in_themed_site() and not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # Otherwise, render the combined login/registration page
    context = {
        'data': {
            'login_redirect_url':
            redirect_to,
            'initial_mode':
            initial_mode,
            'third_party_auth':
            _third_party_auth_context(request, redirect_to),
            'third_party_auth_hint':
            third_party_auth_hint or '',
            'platform_name':
            configuration_helpers.get_value('PLATFORM_NAME',
                                            settings.PLATFORM_NAME),
            'support_link':
            configuration_helpers.get_value('SUPPORT_SITE_LINK',
                                            settings.SUPPORT_SITE_LINK),
            'privacy_policy_url':
            marketing_link('PRIVACY'),

            # Include form descriptions retrieved from the user API.
            # We could have the JS client make these requests directly,
            # but we include them in the initial page load to avoid
            # the additional round-trip to the server.
            'login_form_desc':
            json.loads(form_descriptions['login']),
            'registration_form_desc':
            json.loads(form_descriptions['registration']),
            'password_reset_form_desc':
            json.loads(form_descriptions['password_reset']),
        },
        'login_redirect_url':
        redirect_to,  # This gets added to the query string of the "Sign In" button in header
        'responsive':
        True,
        'allow_iframing':
        True,
        'disable_courseware_js':
        True,
        'disable_footer':
        not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER',
            settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER']),
    }

    return render_to_response('student_account/login_and_register.html',
                              context)
Пример #22
0
def login_and_registration_form(request, initial_mode="login"):
    """Render the combined login/registration form, defaulting to login

    This relies on the JS to asynchronously load the actual form from
    the user_api.

    Keyword Args:
        initial_mode (string): Either "login" or "register".

    """
    # Determine the URL to redirect to following login/registration/third_party_auth
    redirect_to = get_next_url_for_login_page(request)
    # If we're already logged in, redirect to the dashboard
    if UserProfile.has_registered(request.user):
        return redirect(redirect_to)

    if third_party_auth.is_enabled():
        force_provider_id = settings.FORCED_TPA_PROVIDER_ID
        if force_provider_id:
            force_provider = third_party_auth.provider.Registry.get(
                provider_id=force_provider_id,
            )
            if force_provider and force_provider.display_for_login:
                running_pipeline = third_party_auth.pipeline.get(request)
                if not running_pipeline:
                    if initial_mode in [pipeline.AUTH_ENTRY_LOGIN, pipeline.AUTH_ENTRY_REGISTER]:
                        tpa_url = pipeline.get_login_url(
                            force_provider_id,
                            initial_mode,
                            redirect_url=redirect_to,
                        )
                        return redirect(tpa_url)

    # Retrieve the form descriptions from the user API
    form_descriptions = _get_form_descriptions(request)

    # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check.
    # If present, we display a login page focused on third-party auth with that provider.
    third_party_auth_hint = None
    if '?' in redirect_to:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            tpa_hint_provider = third_party_auth.provider.Registry.get(provider_id=provider_id)
            if tpa_hint_provider:
                if tpa_hint_provider.skip_hinted_login_dialog:
                    # Forward the user directly to the provider's login URL when the provider is configured
                    # to skip the dialog.
                    if initial_mode == "register":
                        auth_entry = pipeline.AUTH_ENTRY_REGISTER
                    else:
                        auth_entry = pipeline.AUTH_ENTRY_LOGIN
                    return redirect(
                        pipeline.get_login_url(provider_id, auth_entry, redirect_url=redirect_to)
                    )
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError) as ex:
            log.error("Unknown tpa_hint provider: %s", ex)

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their
    # configuration settings.
    if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # Account activation message
    account_activation_messages = [
        {
            'message': message.message, 'tags': message.tags
        } for message in messages.get_messages(request) if 'account-activation' in message.tags
    ]

    # Otherwise, render the combined login/registration page
    context = {
        'data': {
            'login_redirect_url': redirect_to,
            'initial_mode': initial_mode,
            'third_party_auth': _third_party_auth_context(request, redirect_to, third_party_auth_hint),
            'third_party_auth_hint': third_party_auth_hint or '',
            'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
            'support_link': configuration_helpers.get_value('SUPPORT_SITE_LINK', settings.SUPPORT_SITE_LINK),
            'password_reset_support_link': configuration_helpers.get_value(
                'PASSWORD_RESET_SUPPORT_LINK', settings.PASSWORD_RESET_SUPPORT_LINK
            ) or settings.SUPPORT_SITE_LINK,
            'account_activation_messages': account_activation_messages,

            # Include form descriptions retrieved from the user API.
            # We could have the JS client make these requests directly,
            # but we include them in the initial page load to avoid
            # the additional round-trip to the server.
            'login_form_desc': json.loads(form_descriptions['login']),
            'registration_form_desc': json.loads(form_descriptions['registration']),
            'password_reset_form_desc': json.loads(form_descriptions['password_reset']),
            'account_creation_allowed': configuration_helpers.get_value(
                'ALLOW_PUBLIC_ACCOUNT_CREATION', settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True))
        },
        'login_redirect_url': redirect_to,  # This gets added to the query string of the "Sign In" button in header
        'responsive': True,
        'allow_iframing': True,
        'disable_courseware_js': True,
        'combined_login_and_register': True,
        'disable_footer': not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER',
            settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER']
        ),
    }

    context = update_context_for_enterprise(request, context)

    return render_to_response('student_account/login_and_register.html', context)
Пример #23
0
def submit_feedback(request):
    """
    Create a Zendesk ticket or if not available, send an email with the
    feedback form fields.

    If feedback submission is not enabled, any request will raise `Http404`.
    If any configuration parameter (`ZENDESK_URL`, `ZENDESK_USER`, or
    `ZENDESK_API_KEY`) is missing, any request will raise an `Exception`.
    The request must be a POST request specifying `subject` and `details`.
    If the user is not authenticated, the request must also specify `name` and
    `email`. If the user is authenticated, the `name` and `email` will be
    populated from the user's information. If any required parameter is
    missing, a 400 error will be returned indicating which field is missing and
    providing an error message. If Zendesk ticket creation fails, 500 error
    will be returned with no body; if ticket creation succeeds, an empty
    successful response (200) will be returned.
    """
    if not settings.FEATURES.get('ENABLE_FEEDBACK_SUBMISSION', False):
        raise Http404()
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])

    def build_error_response(status_code, field, err_msg):
        return HttpResponse(json.dumps({"field": field, "error": err_msg}), status=status_code)

    required_fields = ["subject", "details"]

    if not UserProfile.has_registered(request.user):
        required_fields += ["name", "email"]

    required_field_errs = {
        "subject": "Please provide a subject.",
        "details": "Please provide details.",
        "name": "Please provide your name.",
        "email": "Please provide a valid e-mail.",
    }
    for field in required_fields:
        if field not in request.POST or not request.POST[field]:
            return build_error_response(400, field, required_field_errs[field])

    if not UserProfile.has_registered(request.user):
        try:
            validate_email(request.POST["email"])
        except ValidationError:
            return build_error_response(400, "email", required_field_errs["email"])

    success = False
    context = get_feedback_form_context(request)

    #Update the tag info with 'enterprise_learner' if the user belongs to an enterprise customer.
    enterprise_learner_data = enterprise_api.get_enterprise_learner_data(site=request.site, user=request.user)
    if enterprise_learner_data:
        context["tags"]["learner_type"] = "enterprise_learner"

    support_backend = configuration_helpers.get_value('CONTACT_FORM_SUBMISSION_BACKEND', SUPPORT_BACKEND_ZENDESK)

    if support_backend == SUPPORT_BACKEND_EMAIL:
        try:
            send_mail(
                subject=render_to_string('emails/contact_us_feedback_email_subject.txt', context),
                message=render_to_string('emails/contact_us_feedback_email_body.txt', context),
                from_email=context["support_email"],
                recipient_list=[context["support_email"]],
                fail_silently=False
            )
            success = True
        except SMTPException:
            log.exception('Error sending feedback to contact_us email address.')
            success = False

    else:
        if not settings.ZENDESK_URL or not settings.ZENDESK_USER or not settings.ZENDESK_API_KEY:
            raise Exception("Zendesk enabled but not configured")

        custom_fields = None
        if settings.ZENDESK_CUSTOM_FIELDS:
            custom_field_context = _get_zendesk_custom_field_context(request, learner_data=enterprise_learner_data)
            custom_fields = _format_zendesk_custom_fields(custom_field_context)

        success = _record_feedback_in_zendesk(
            context["realname"],
            context["email"],
            context["subject"],
            context["details"],
            context["tags"],
            context["additional_info"],
            support_email=context["support_email"],
            custom_fields=custom_fields
        )

    _record_feedback_in_datadog(context["tags"])

    return HttpResponse(status=(200 if success else 500))
Пример #24
0
def submit_feedback(request):
    """
    Create a new user-requested ticket, currently implemented with Zendesk.

    If feedback submission is not enabled, any request will raise `Http404`.
    If any configuration parameter (`ZENDESK_URL`, `ZENDESK_USER`, or
    `ZENDESK_API_KEY`) is missing, any request will raise an `Exception`.
    The request must be a POST request specifying `subject` and `details`.
    If the user is not authenticated, the request must also specify `name` and
    `email`. If the user is authenticated, the `name` and `email` will be
    populated from the user's information. If any required parameter is
    missing, a 400 error will be returned indicating which field is missing and
    providing an error message. If Zendesk ticket creation fails, 500 error
    will be returned with no body; if ticket creation succeeds, an empty
    successful response (200) will be returned.
    """
    if not settings.FEATURES.get('ENABLE_FEEDBACK_SUBMISSION', False):
        raise Http404()
    if request.method != "POST":
        return HttpResponseNotAllowed(["POST"])
    if (
        not settings.ZENDESK_URL or
        not settings.ZENDESK_USER or
        not settings.ZENDESK_API_KEY
    ):
        raise Exception("Zendesk enabled but not configured")

    def build_error_response(status_code, field, err_msg):
        return HttpResponse(json.dumps({"field": field, "error": err_msg}), status=status_code)

    additional_info = {}

    required_fields = ["subject", "details"]
    if not UserProfile.has_registered(request.user):
        required_fields += ["name", "email"]
    required_field_errs = {
        "subject": "Please provide a subject.",
        "details": "Please provide details.",
        "name": "Please provide your name.",
        "email": "Please provide a valid e-mail.",
    }

    for field in required_fields:
        if field not in request.POST or not request.POST[field]:
            return build_error_response(400, field, required_field_errs[field])

    subject = request.POST["subject"]
    details = request.POST["details"]
    tags = dict(
        [(tag, request.POST[tag]) for tag in ["issue_type", "course_id"] if tag in request.POST]
    )

    if UserProfile.has_registered(request.user):
        realname = request.user.profile.name
        email = request.user.email
        additional_info["username"] = request.user.username
    else:
        realname = request.POST["name"]
        email = request.POST["email"]
        try:
            validate_email(email)
        except ValidationError:
            return build_error_response(400, "email", required_field_errs["email"])

    for header, pretty in [
        ("HTTP_REFERER", "Page"),
        ("HTTP_USER_AGENT", "Browser"),
        ("REMOTE_ADDR", "Client IP"),
        ("SERVER_NAME", "Host")
    ]:
        additional_info[pretty] = request.META.get(header)

    success = _record_feedback_in_zendesk(realname, email, subject, details, tags, additional_info)
    _record_feedback_in_datadog(tags)

    return HttpResponse(status=(200 if success else 500))
Пример #25
0
 def can_load_forum():
     """
     Can this user access the forums in this course?
     """
     return (can_load() and UserProfile.has_registered(user))