Exemple #1
0
def send_account_recovery_email_for_user(user, request, email=None):
    """
    Send out a account recovery email for the given user.

    Arguments:
        user (User): Django User object
        request (HttpRequest): Django request object
        email (str): Send email to this address.
    """
    site = get_current_site()
    message_context = get_base_template_context(site)
    message_context.update({
        'request': request,  # Used by google_analytics_tracking_pixel
        'email': email,
        'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
        'reset_link': '{protocol}://{site}{link}?is_account_recovery=true'.format(
            protocol='https' if request.is_secure() else 'http',
            site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME),
            link=reverse('password_reset_confirm', kwargs={
                'uidb36': int_to_base36(user.id),
                'token': default_token_generator.make_token(user),
            }),
        )
    })

    msg = AccountRecoveryMessage().personalize(
        recipient=Recipient(user.username, email),
        language=get_user_preference(user, LANGUAGE_KEY),
        user_context=message_context,
    )
    ace.send(msg)
Exemple #2
0
def send_password_reset_email_for_user(user, request, preferred_email=None):
    """
    Send out a password reset email for the given user.

    Arguments:
        user (User): Django User object
        request (HttpRequest): Django request object
        preferred_email (str): Send email to this address if present, otherwise fallback to user's email address.
    """
    site = get_current_site()
    message_context = get_base_template_context(site)
    message_context.update({
        'request': request,  # Used by google_analytics_tracking_pixel
        # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes
        'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
        'reset_link': '{protocol}://{site}{link}'.format(
            protocol='https' if request.is_secure() else 'http',
            site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME),
            link=reverse('password_reset_confirm', kwargs={
                'uidb36': int_to_base36(user.id),
                'token': default_token_generator.make_token(user),
            }),
        )
    })

    msg = PasswordReset().personalize(
        recipient=Recipient(user.username, preferred_email or user.email),
        language=get_user_preference(user, LANGUAGE_KEY),
        user_context=message_context,
    )
    ace.send(msg)
Exemple #3
0
    def save(self,  # pylint: disable=arguments-differ
             use_https=False,
             token_generator=default_token_generator,
             request=None,
             **_kwargs):
        """
        Generates a one-use only link for resetting password and sends to the
        user.
        """
        for user in self.users_cache:
            site = get_current_site()
            message_context = get_base_template_context(site)

            message_context.update({
                'request': request,  # Used by google_analytics_tracking_pixel
                # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes
                'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
                'reset_link': '{protocol}://{site}{link}'.format(
                    protocol='https' if use_https else 'http',
                    site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME),
                    link=reverse('password_reset_confirm', kwargs={
                        'uidb36': int_to_base36(user.id),
                        'token': token_generator.make_token(user),
                    }),
                )
            })

            msg = PasswordReset().personalize(
                recipient=Recipient(user.username, user.email),
                language=get_user_preference(user, LANGUAGE_KEY),
                user_context=message_context,
            )
            ace.send(msg)
Exemple #4
0
def send_discussion_email_notification(sender, user, post, **kwargs):
    if not waffle().is_enabled(FORUM_RESPONSE_NOTIFICATIONS):
        log.debug('Discussion: Response notifications waffle switch not enabled')
        return

    if not SEND_NOTIFICATIONS_FOR_COURSE.is_enabled(CourseKey.from_string(post.thread.course_id)):
        log.debug('Discussion: Response notifications not enabled for course: %s.', post.thread.course_id)
        return

    current_site = get_current_site()
    if current_site is None:
        log.info('Discussion: No current site, not sending notification about post: %s.', post.id)
        return

    try:
        if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False):
            log_message = 'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.'
            log.info(log_message, current_site, post.id)
            return
    except SiteConfiguration.DoesNotExist:
        log_message = 'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.'
        log.info(log_message, current_site, post.id)
        return

    send_message(post, current_site)
Exemple #5
0
def _create_schedule(enrollment, enrollment_created):
    """
    Checks configuration and creates Schedule with ScheduleExperience for this enrollment.
    """
    if not enrollment_created:
        # only create schedules when enrollment records are created
        return

    current_site = get_current_site()
    if current_site is None:
        log.debug('Schedules: No current site')
        return

    schedule_config = ScheduleConfig.current(current_site)
    if (
        not schedule_config.create_schedules and
        not CREATE_SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id)
    ):
        log.debug('Schedules: Creation not enabled for this course or for this site')
        return

    if not enrollment.course_overview.self_paced:
        log.debug('Schedules: Creation only enabled for self-paced courses')
        return

    # This represents the first date at which the learner can access the content. This will be the latter of
    # either the enrollment date or the course's start date.
    content_availability_date = max(enrollment.created, enrollment.course_overview.start)
    upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date)
    experience_type = _get_experience_type(enrollment)

    if _should_randomly_suppress_schedule_creation(
            schedule_config,
            enrollment,
            upgrade_deadline,
            experience_type,
            content_availability_date,
    ):
        return

    schedule = Schedule.objects.create(
        enrollment=enrollment,
        start=content_availability_date,
        upgrade_deadline=upgrade_deadline
    )

    ScheduleExperience(schedule=schedule, experience_type=experience_type).save()

    return {
        'content_availability_date': content_availability_date,
        'upgrade_deadline': upgrade_deadline,
        'experience_type': experience_type,
    }
Exemple #6
0
def get_programs(uuid=None):
    """Read programs from the cache.

    The cache is populated by a management command, cache_programs.

    Keyword Arguments:
        uuid (string): UUID identifying a specific program to read from the cache.

    Returns:
        list of dict, representing programs.
        dict, if a specific program is requested.
    """
    missing_details_msg_tpl = 'Failed to get details for program {uuid} from the cache.'

    if uuid:
        program = cache.get(PROGRAM_CACHE_KEY_TPL.format(uuid=uuid))
        if not program:
            logger.warning(missing_details_msg_tpl.format(uuid=uuid))

        return program
    if waffle.switch_is_active('get-multitenant-programs'):
        uuids = cache.get(SITE_PROGRAM_UUIDS_CACHE_KEY_TPL.format(domain=get_current_site().domain), [])
    else:
        uuids = cache.get(PROGRAM_UUIDS_CACHE_KEY, [])
    if not uuids:
        logger.warning('Failed to get program UUIDs from the cache.')

    programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=uuid) for uuid in uuids])
    programs = list(programs.values())

    # The get_many above sometimes fails to bring back details cached on one or
    # more Memcached nodes. It doesn't look like these keys are being evicted.
    # 99% of the time all keys come back, but 1% of the time all the keys stored
    # on one or more nodes are missing from the result of the get_many. One
    # get_many may fail to bring these keys back, but a get_many occurring
    # immediately afterwards will succeed in bringing back all the keys. This
    # behavior can be mitigated by trying again for the missing keys, which is
    # what we do here. Splitting the get_many into smaller chunks may also help.
    missing_uuids = set(uuids) - set(program['uuid'] for program in programs)
    if missing_uuids:
        logger.info(
            'Failed to get details for {count} programs. Retrying.'.format(count=len(missing_uuids))
        )

        retried_programs = cache.get_many([PROGRAM_CACHE_KEY_TPL.format(uuid=uuid) for uuid in missing_uuids])
        programs += list(retried_programs.values())

        still_missing_uuids = set(uuids) - set(program['uuid'] for program in programs)
        for uuid in still_missing_uuids:
            logger.warning(missing_details_msg_tpl.format(uuid=uuid))

    return programs
Exemple #7
0
def create_schedule(sender, **kwargs):
    if not kwargs['created']:
        # only create schedules when enrollment records are created
        return

    current_site = get_current_site()
    if current_site is None:
        log.debug('Schedules: No current site')
        return

    enrollment = kwargs['instance']
    schedule_config = ScheduleConfig.current(current_site)
    if not schedule_config.create_schedules:
        log.debug('Schedules: Creation not enabled for this course or for this site')
        return

    if not enrollment.course_overview.self_paced:
        log.debug('Schedules: Creation only enabled for self-paced courses')
        return

    # This represents the first date at which the learner can access the content. This will be the latter of
    # either the enrollment date or the course's start date.
    content_availability_date = max(enrollment.created, enrollment.course_overview.start)

    upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date)

    if course_has_highlights(enrollment.course_id):
        experience_type = ScheduleExperience.EXPERIENCES.course_updates
    else:
        experience_type = ScheduleExperience.EXPERIENCES.default

    if _should_randomly_suppress_schedule_creation(
        schedule_config,
        enrollment,
        upgrade_deadline,
        experience_type,
        content_availability_date,
    ):
        return

    schedule = Schedule.objects.create(
        enrollment=enrollment,
        start=content_availability_date,
        upgrade_deadline=upgrade_deadline
    )

    ScheduleExperience(schedule=schedule, experience_type=experience_type).save()

    log.debug('Schedules: created a new schedule starting at %s with an upgrade deadline of %s and experience type: %s',
              content_availability_date, upgrade_deadline, ScheduleExperience.EXPERIENCES[experience_type])
Exemple #8
0
def get_current_site_configuration():
    """
    Return configuration for the current site.

    Returns:
         (openedx.core.djangoapps.site_configuration.models.SiteConfiguration): SiteConfiguration instance associated
         with the current site.
    """

    # Import is placed here to avoid circular import
    from openedx.core.djangoapps.theming.helpers import get_current_site
    site = get_current_site()

    try:
        return getattr(site, "configuration", None)
    except SiteConfiguration.DoesNotExist:
        return None
def send_discussion_email_notification(sender, user, post, **kwargs):
    current_site = get_current_site()
    if current_site is None:
        log.info(u'Discussion: No current site, not sending notification about post: %s.', post.id)
        return

    try:
        if not current_site.configuration.get_value(ENABLE_FORUM_NOTIFICATIONS_FOR_SITE_KEY, False):
            log_message = u'Discussion: notifications not enabled for site: %s. Not sending message about post: %s.'
            log.info(log_message, current_site, post.id)
            return
    except SiteConfiguration.DoesNotExist:
        log_message = u'Discussion: No SiteConfiguration for site %s. Not sending message about post: %s.'
        log.info(log_message, current_site, post.id)
        return

    send_message(post, current_site)
Exemple #10
0
def create_schedule(sender, **kwargs):
    if not kwargs['created']:
        # only create schedules when enrollment records are created
        return

    current_site = get_current_site()
    if current_site is None:
        log.debug('Schedules: No current site')
        return

    enrollment = kwargs['instance']
    schedule_config = ScheduleConfig.current(current_site)
    if (
        not schedule_config.create_schedules
        and not CREATE_SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id)
    ):
        log.debug('Schedules: Creation not enabled for this course or for this site')
        return

    if not enrollment.course_overview.self_paced:
        log.debug('Schedules: Creation only enabled for self-paced courses')
        return

    # This represents the first date at which the learner can access the content. This will be the latter of
    # either the enrollment date or the course's start date.
    content_availability_date = max(enrollment.created, enrollment.course_overview.start)

    upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date)

    schedule = Schedule.objects.create(
        enrollment=enrollment,
        start=content_availability_date,
        upgrade_deadline=upgrade_deadline
    )

    try:
        get_week_highlights(enrollment.course_id, 1)
        experience_type = ScheduleExperience.EXPERIENCES.course_updates
    except CourseUpdateDoesNotExist:
        experience_type = ScheduleExperience.EXPERIENCES.default

    ScheduleExperience(schedule=schedule, experience_type=experience_type).save()

    log.debug('Schedules: created a new schedule starting at %s with an upgrade deadline of %s and experience type: %s',
              content_availability_date, upgrade_deadline, ScheduleExperience.EXPERIENCES[experience_type])
Exemple #11
0
def create_schedule(sender, **kwargs):
    if not kwargs['created']:
        # only create schedules when enrollment records are created
        return

    current_site = get_current_site()
    if current_site is None:
        log.debug('Schedules: No current site')
        return

    enrollment = kwargs['instance']
    schedule_config = ScheduleConfig.current(current_site)
    if (
        not schedule_config.create_schedules
        and not SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id)
    ):
        log.debug('Schedules: Creation not enabled for this course or for this site')
        return

    if not enrollment.course_overview.self_paced:
        log.debug('Schedules: Creation only enabled for self-paced courses')
        return

    # This represents the first date at which the learner can access the content. This will be the latter of
    # either the enrollment date or the course's start date.
    content_availability_date = max(enrollment.created, enrollment.course_overview.start)

    upgrade_deadline = _calculate_upgrade_deadline(enrollment.course_id, content_availability_date)

    Schedule.objects.create(
        enrollment=enrollment,
        start=content_availability_date,
        upgrade_deadline=upgrade_deadline
    )

    log.debug('Schedules: created a new schedule starting at %s with an upgrade deadline of %s',
              content_availability_date, upgrade_deadline)
Exemple #12
0
def send_password_reset_email_for_user(user, request, preferred_email=None):
    """
    Send out a password reset email for the given user.

    Arguments:
        user (User): Django User object
        request (HttpRequest): Django request object
        preferred_email (str): Send email to this address if present, otherwise fallback to user's email address.
    """
    site = get_current_site()
    message_context = get_base_template_context(site)
    message_context.update({
        'request':
        request,  # Used by google_analytics_tracking_pixel
        # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes
        'platform_name':
        configuration_helpers.get_value('PLATFORM_NAME',
                                        settings.PLATFORM_NAME),
        'reset_link':
        '{protocol}://{site}{link}?track=pwreset'.format(
            protocol='https' if request.is_secure() else 'http',
            site=configuration_helpers.get_value('SITE_NAME',
                                                 settings.SITE_NAME),
            link=reverse('password_reset_confirm',
                         kwargs={
                             'uidb36': int_to_base36(user.id),
                             'token': default_token_generator.make_token(user),
                         }),
        )
    })

    msg = PasswordReset().personalize(
        recipient=Recipient(user.username, preferred_email or user.email),
        language=get_user_preference(user, LANGUAGE_KEY),
        user_context=message_context,
    )
    ace.send(msg)
Exemple #13
0
def send_account_recovery_email_for_user(user, request, email=None):
    """
    Send out a account recovery email for the given user.

    Arguments:
        user (User): Django User object
        request (HttpRequest): Django request object
        email (str): Send email to this address.
    """
    site = get_current_site()
    message_context = get_base_template_context(site)
    message_context.update({
        'request':
        request,  # Used by google_analytics_tracking_pixel
        'platform_name':
        configuration_helpers.get_value('PLATFORM_NAME',
                                        settings.PLATFORM_NAME),
        'reset_link':
        '{protocol}://{site}{link}'.format(
            protocol='https' if request.is_secure() else 'http',
            site=configuration_helpers.get_value('SITE_NAME',
                                                 settings.SITE_NAME),
            link=reverse('account_recovery_confirm',
                         kwargs={
                             'uidb36': int_to_base36(user.id),
                             'token': default_token_generator.make_token(user),
                         }),
        )
    })

    msg = AccountRecoveryMessage().personalize(
        recipient=Recipient(user.username, email),
        language=get_user_preference(user, LANGUAGE_KEY),
        user_context=message_context,
    )
    ace.send(msg)
Exemple #14
0
def retrieve_last_sitewide_block_completed(username):
    """
    Completion utility
    From a string 'username' or object User retrieve
    the last course block marked as 'completed' and construct a URL

    :param username: str(username) or obj(User)
    :return: block_lms_url

    """
    if not completion_waffle.waffle().is_enabled(
            completion_waffle.ENABLE_COMPLETION_TRACKING):
        return

    if not isinstance(username, User):
        userobj = User.objects.get(username=username)
    else:
        userobj = username
    latest_completions_by_course = BlockCompletion.latest_blocks_completed_all_courses(
        userobj)

    known_site_configs = [
        other_site_config.get_value('course_org_filter')
        for other_site_config in SiteConfiguration.objects.all()
        if other_site_config.get_value('course_org_filter')
    ]

    current_site_configuration = get_config_value_from_site_or_settings(
        name='course_org_filter', site=get_current_site())

    # courses.edx.org has no 'course_org_filter'
    # however the courses within DO, but those entries are not found in
    # known_site_configs, which are White Label sites
    # This is necessary because the WL sites and courses.edx.org
    # have the same AWS RDS mySQL instance
    candidate_course = None
    candidate_block_key = None
    latest_date = None
    # Go through dict, find latest
    for course, [modified_date,
                 block_key] in latest_completions_by_course.items():
        if not current_site_configuration:
            # This is a edx.org
            if course.org in known_site_configs:
                continue
            if not latest_date or modified_date > latest_date:
                candidate_course = course
                candidate_block_key = block_key
                latest_date = modified_date

        else:
            # This is a White Label site, and we should find candidates from the same site
            if course.org not in current_site_configuration:
                # Not the same White Label, or a edx.org course
                continue
            if not latest_date or modified_date > latest_date:
                candidate_course = course
                candidate_block_key = block_key
                latest_date = modified_date

    if not candidate_course:
        return

    lms_root = SiteConfiguration.get_value_for_org(candidate_course.org,
                                                   "LMS_ROOT_URL",
                                                   settings.LMS_ROOT_URL)

    try:
        item = modulestore().get_item(candidate_block_key, depth=1)
    except ItemNotFoundError:
        item = None

    if not (lms_root and item):
        return

    return u"{lms_root}/courses/{course_key}/jump_to/{location}".format(
        lms_root=lms_root,
        course_key=text_type(item.location.course_key),
        location=text_type(item.location),
    )
Exemple #15
0
def create_schedule(sender, **kwargs):
    if not kwargs['created']:
        # only create schedules when enrollment records are created
        return

    current_site = get_current_site()
    if current_site is None:
        log.debug('Schedules: No current site')
        return

    enrollment = kwargs['instance']
    schedule_config = ScheduleConfig.current(current_site)
    if (not schedule_config.create_schedules
            and not SCHEDULE_WAFFLE_FLAG.is_enabled(enrollment.course_id)):
        log.debug(
            'Schedules: Creation not enabled for this course or for this site')
        return

    delta = None
    if enrollment.course_overview.self_paced:
        global_config = DynamicUpgradeDeadlineConfiguration.current()
        if global_config.enabled:
            # Use the default from this model whether or not the feature is enabled
            delta = global_config.deadline_days

        # Check if the course has a deadline override
        course_config = CourseDynamicUpgradeDeadlineConfiguration.current(
            enrollment.course_id)
        if course_config.enabled:
            delta = course_config.deadline_days

    upgrade_deadline = None

    # This represents the first date at which the learner can access the content. This will be the latter of
    # either the enrollment date or the course's start date.
    content_availability_date = max(enrollment.created,
                                    enrollment.course_overview.start)

    if delta is not None:
        upgrade_deadline = content_availability_date + datetime.timedelta(
            days=delta)

        course_upgrade_deadline = None
        try:
            verified_mode = CourseMode.verified_mode_for_course(
                enrollment.course_id)
        except CourseMode.DoesNotExist:
            pass
        else:
            if verified_mode:
                course_upgrade_deadline = verified_mode.expiration_datetime

        if course_upgrade_deadline is not None and upgrade_deadline is not None:
            # The content availability-based deadline should never occur after the verified mode's
            # expiration date, if one is set.
            upgrade_deadline = min(upgrade_deadline, course_upgrade_deadline)

    Schedule.objects.create(enrollment=enrollment,
                            start=content_availability_date,
                            upgrade_deadline=upgrade_deadline)

    log.debug(
        'Schedules: created a new schedule starting at %s with an upgrade deadline of %s',
        content_availability_date, upgrade_deadline)
def password_change_request_handler(request):
    """Handle password change requests originating from the account page.

    Uses the Account API to email the user a link to the password reset page.

    Note:
        The next step in the password reset process (confirmation) is currently handled
        by student.views.password_reset_confirm_wrapper, a custom wrapper around Django's
        password reset confirmation view.

    Args:
        request (HttpRequest)

    Returns:
        HttpResponse: 200 if the email was sent successfully
        HttpResponse: 400 if there is no 'email' POST parameter
        HttpResponse: 403 if the client has been rate limited
        HttpResponse: 405 if using an unsupported HTTP method

    Example usage:

        POST /account/password

    """

    limiter = BadRequestRateLimiter()
    if limiter.is_rate_limit_exceeded(request):
        AUDIT_LOG.warning("Password reset rate limit exceeded")
        return HttpResponseForbidden()

    user = request.user
    # Prefer logged-in user's email
    email = user.email if user.is_authenticated else request.POST.get('email')

    if email:
        try:
            from openedx.core.djangoapps.user_api.accounts.api import request_password_change
            request_password_change(email, request.is_secure())
            user = user if user.is_authenticated else User.objects.get(
                email=email)
            destroy_oauth_tokens(user)
        except UserNotFound:
            AUDIT_LOG.info("Invalid password reset attempt")
            # Increment the rate limit counter
            limiter.tick_bad_request_counter(request)

            # If enabled, send an email saying that a password reset was attempted, but that there is
            # no user associated with the email
            if configuration_helpers.get_value(
                    'ENABLE_PASSWORD_RESET_FAILURE_EMAIL',
                    settings.FEATURES['ENABLE_PASSWORD_RESET_FAILURE_EMAIL']):

                site = get_current_site()
                message_context = get_base_template_context(site)

                message_context.update({
                    'failed': True,
                    'request':
                    request,  # Used by google_analytics_tracking_pixel
                    'email_address': email,
                })

                msg = PasswordReset().personalize(
                    recipient=Recipient(username='', email_address=email),
                    language=settings.LANGUAGE_CODE,
                    user_context=message_context,
                )

                ace.send(msg)
        except UserAPIInternalError as err:
            log.exception(
                'Error occured during password change for user {email}: {error}'
                .format(email=email, error=err))
            return HttpResponse(_(
                "Some error occured during password change. Please try again"),
                                status=500)

        return HttpResponse(status=200)
    else:
        return HttpResponseBadRequest(_("No email address provided."))
Exemple #17
0
def password_change_request_handler(request):
    """Handle password change requests originating from the account page.

    Uses the Account API to email the user a link to the password reset page.

    Note:
        The next step in the password reset process (confirmation) is currently handled
        by student.views.password_reset_confirm_wrapper, a custom wrapper around Django's
        password reset confirmation view.

    Args:
        request (HttpRequest)

    Returns:
        HttpResponse: 200 if the email was sent successfully
        HttpResponse: 400 if there is no 'email' POST parameter
        HttpResponse: 403 if the client has been rate limited
        HttpResponse: 405 if using an unsupported HTTP method

    Example usage:

        POST /account/password

    """

    limiter = BadRequestRateLimiter()
    if limiter.is_rate_limit_exceeded(request):
        AUDIT_LOG.warning("Password reset rate limit exceeded")
        return HttpResponseForbidden()

    user = request.user
    # Prefer logged-in user's email
    email = user.email if user.is_authenticated else request.POST.get('email')

    if email:
        try:
            request_password_change(email, request.is_secure())
            user = user if user.is_authenticated else User.objects.get(email=email)
            destroy_oauth_tokens(user)
        except UserNotFound:
            AUDIT_LOG.info("Invalid password reset attempt")
            # Increment the rate limit counter
            limiter.tick_bad_request_counter(request)

            # If enabled, send an email saying that a password reset was attempted, but that there is
            # no user associated with the email
            if configuration_helpers.get_value('ENABLE_PASSWORD_RESET_FAILURE_EMAIL',
                                               settings.FEATURES['ENABLE_PASSWORD_RESET_FAILURE_EMAIL']):

                site = get_current_site()
                message_context = get_base_template_context(site)

                message_context.update({
                    'failed': True,
                    'request': request,  # Used by google_analytics_tracking_pixel
                    'email_address': email,
                })

                msg = PasswordReset().personalize(
                    recipient=Recipient(username='', email_address=email),
                    language=settings.LANGUAGE_CODE,
                    user_context=message_context,
                )

                ace.send(msg)
        except UserAPIInternalError as err:
            log.exception('Error occured during password change for user {email}: {error}'
                          .format(email=email, error=err))
            return HttpResponse(_("Some error occured during password change. Please try again"), status=500)

        return HttpResponse(status=200)
    else:
        return HttpResponseBadRequest(_("No email address provided."))
Exemple #18
0
def retrieve_last_sitewide_block_completed(user):
    """
    Completion utility
    From a string 'username' or object User retrieve
    the last course block marked as 'completed' and construct a URL

    :param user: obj(User)
    :return: block_lms_url

    """
    if not completion_waffle.waffle().is_enabled(completion_waffle.ENABLE_COMPLETION_TRACKING):
        return

    latest_completions_by_course = BlockCompletion.latest_blocks_completed_all_courses(user)

    known_site_configs = [
        other_site_config.get_value('course_org_filter') for other_site_config in SiteConfiguration.objects.all()
        if other_site_config.get_value('course_org_filter')
    ]

    current_site_configuration = get_config_value_from_site_or_settings(
        name='course_org_filter',
        site=get_current_site()
    )

    # courses.edx.org has no 'course_org_filter'
    # however the courses within DO, but those entries are not found in
    # known_site_configs, which are White Label sites
    # This is necessary because the WL sites and courses.edx.org
    # have the same AWS RDS mySQL instance
    candidate_course = None
    candidate_block_key = None
    latest_date = None
    # Go through dict, find latest
    for course, [modified_date, block_key] in latest_completions_by_course.items():
        if not current_site_configuration:
            # This is a edx.org
            if course.org in known_site_configs:
                continue
            if not latest_date or modified_date > latest_date:
                candidate_course = course
                candidate_block_key = block_key
                latest_date = modified_date

        else:
            # This is a White Label site, and we should find candidates from the same site
            if course.org not in current_site_configuration:
                # Not the same White Label, or a edx.org course
                continue
            if not latest_date or modified_date > latest_date:
                candidate_course = course
                candidate_block_key = block_key
                latest_date = modified_date

    if not candidate_course:
        return

    lms_root = SiteConfiguration.get_value_for_org(candidate_course.org, "LMS_ROOT_URL", settings.LMS_ROOT_URL)

    try:
        item = modulestore().get_item(candidate_block_key, depth=1)
    except ItemNotFoundError:
        item = None

    if not (lms_root and item):
        return

    return u"{lms_root}/courses/{course_key}/jump_to/{location}".format(
        lms_root=lms_root,
        course_key=text_type(item.location.course_key),
        location=text_type(item.location),
    )
Exemple #19
0
    def wharf_url(self, force=False):
        """Determine which site we're on, then get the Wharf URL that said
        site has configured."""

        # The complexities of Tahoe require that we check several places
        # for the site configuration, which itself contains the URL
        # of the AVL cluster associated with this site.
        #
        # If we are in Tahoe studio, the Site object associated with this request
        # will not be the one used within Tahoe. To get the proper domain
        # we rely on the "organization", which always equals `Site.name`.
        # If the organization value does not return a site object, we are probably on
        # the LMS side. In this case, we use `get_current_site()`, which _does_
        # return the incorrect site object. If all this fails, we fallback
        # to the DEFAULT_WHARF_URL.
        try:
            # The name of the Site object will always match self.course_id.org.
            # See: https://git.io/vpilS
            site = Site.objects.get(name=self.course_id.org)
        except (Site.DoesNotExist, AttributeError):  # Probably on the lms side.
            if get_current_site:
                site = get_current_site()  # From the request.
            else:
                site = Site.objects.all().order_by('domain').first()

        url = cache.get(make_cache_key(site.domain))
        if url:
            return url

        # Nothing in the cache. Go find the URL.
        site_wharf_url = None
        if hasattr(site, 'configuration'):
            site_wharf_url = site.configuration.get_value(WHARF_URL_KEY)
        elif siteconfig_helpers:
            # Rely on edX's helper, which will fall back to the microsites app.
            site_wharf_url = siteconfig_helpers.get_value(WHARF_URL_KEY)

        urls = (
            # A SiteConfig object: this is the preferred implementation.
            (
                'SiteConfiguration',
                site_wharf_url
            ),
            # A string: the currently supported implementation.
            (
                "ENV_TOKENS[{}]".format(WHARF_URL_KEY),
                settings.ENV_TOKENS.get(WHARF_URL_KEY)
            ),
            # A dict: the deprecated version.
            (
                "ENV_TOKENS['LAUNCHCONTAINER_API_CONF']",
                settings.ENV_TOKENS.get('LAUNCHCONTAINER_API_CONF', {}).get('default')
            ),
        )

        try:
            url = next((x[1] for x in urls if is_valid(x[1])))
        except StopIteration:
            raise ImproperlyConfigured("No Virtual Labs URL was found, "
                                       "please contact your site administrator.")

        if not url:
            raise AssertionError("You must set a valid url for the launchcontainer XBlock. "
                                 "URLs attempted: {}".format(urls)
                                 )

        cache.set(make_cache_key(site), url, CACHE_KEY_TIMEOUT)

        logger.debug("XBlock-launchcontainer urls attempted: {}".format(urls))

        return url
Exemple #20
0
    def post(self, request, **kwargs):
        #from student.forms import send_password_reset_email_for_user
        from openedx.core.djangoapps.ace_common.template_context import get_base_template_context
        from openedx.core.djangoapps.theming.helpers import get_current_site
        from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
        from student.message_types import PasswordReset
        from django.contrib.auth.tokens import default_token_generator
        from django.utils.http import int_to_base36
        from edx_ace.recipient import Recipient
        from openedx.core.djangoapps.user_api.preferences.api import get_user_preference
        from openedx.core.djangoapps.lang_pref import LANGUAGE_KEY
        from edx_ace import ace
        self.data = request.POST.dict()
        if not ('uservalue' and 'sendotptype' in self.data):
            return JsonResponse({
                "status": 400,
                "message": "Please enter Valid Mobile Number or Email Address or password",
            })
        if self.data.get('sendotptype') == "mobile":
            mobile = self.data.get('uservalue')
            user = User.objects.get(extrafields__phone=mobile)
            email = user.email
        else:
            email = self.data.get('uservalue')
        if not email:
            return JsonResponse({
                "status": 400,
                "message": "Email id can not be blank",
            })

        user = User.objects.get(email=email)
        try:
            site = get_current_site()
            message_context = get_base_template_context(site)
            message_context.update({
                'request': request,  # Used by google_analytics_tracking_pixel
                # TODO: This overrides `platform_name` from `get_base_template_context` to make the tests passes
                'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),
                'reset_link': '{protocol}://{site}{link}'.format(
                    protocol='https',
                    site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME),
                    link=reverse('password_reset_confirm', kwargs={
                        'uidb36': int_to_base36(user.id),
                        'token': default_token_generator.make_token(user),
                    }),
                )
            })
            msg = PasswordReset().personalize(
                recipient=Recipient(user.username, user.email),
                language=get_user_preference(user, LANGUAGE_KEY),
               user_context=message_context,
            )
            ace.send(msg)
            return JsonResponse({
                "status": 200,
                "message": "We sent mail in you email",
           })

        except Exception as e:
            return JsonResponse({
                "status": 400,
                "message": "Something error in sending mail",
                "error": "err2",
            })