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
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
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 )
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) ) )
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)))
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
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)))
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
def can_load_forum(): """ Can this user access the forums in this course? """ return ( can_load() and UserProfile.has_registered(user) )
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())
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) ) )
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)
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())
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)
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')
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
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
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))
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)
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))
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)
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)
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))
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))
def can_load_forum(): """ Can this user access the forums in this course? """ return (can_load() and UserProfile.has_registered(user))