Ejemplo n.º 1
0
def forgot_password(request):
    """
    Generate a new password and send an email to the email specified in the request. For security purposes, whether
    the email exists in the system or not, the same response "success" will be shown the user.

    :param request: the request being processed
    :return: a 200 Response upon success
    """
    if 'email' not in request.data:
        raise ValidationError("'email' is required")

    try:
        user = get_user_model().objects.get(email=request.data['email'])

        # Generate a random password for the user
        password = get_user_model().objects.make_random_password()
        user.set_password(password)
        user.save()

        logger.info(f'Reset password for user with email {user.email}')

        metricutils.increment('action.user.password-reset', request)

        send_password_reset_email.delay(user.email, password)

        request.session.modified = True
    except get_user_model().DoesNotExist:
        logger.info(
            'A visitor tried to reset the password for an unknown email address of {}'
            .format(request.data['email']))

    return Response()
Ejemplo n.º 2
0
def process_text_reminders():
    for reminder in Reminder.objects.with_type(
            enums.TEXT).unsent().for_today().iterator():
        timezone.activate(pytz.timezone(
            reminder.get_user().settings.time_zone))

        if reminder.get_user().profile.phone and reminder.get_user(
        ).profile.phone_verified:
            subject = get_subject(reminder)
            message = f'({subject}) {reminder.message}'

            if not subject:
                logger.warning(
                    f'Reminder {reminder.pk} was not processed, as it appears to be orphaned'
                )
                continue

            logger.info(
                f'Sending text reminder {reminder.pk} for user {reminder.get_user().pk}'
            )

            metricutils.increment('task.reminder.queue.text')

            send_text.delay(reminder.get_user().profile.phone, message)

            reminder.sent = True
            reminder.save()
        else:
            logger.warning(
                'Reminder {} was not processed, as the phone and carrier are no longer set for user {}'
                .format(reminder.pk,
                        reminder.get_user().pk))

        timezone.deactivate()
Ejemplo n.º 3
0
def recalculate_course_grade(course_id, retries=0):
    metricutils.increment('task.grading.recalculate.course')

    # The instance may no longer exist by the time this request is processed, in which case we can simply and safely
    # skip it
    try:
        course = Course.objects.get(pk=course_id)

        gradingservice.recalculate_course_grade(course)

        recalculate_course_group_grade(course.course_group.pk)
    except IntegrityError as ex:  # pragma: no cover
        if retries < settings.DB_INTEGRITY_RETRIES:
            # This error is common when importing schedules, as async tasks may come in different orders
            logger.warning(
                "Integrity error occurred, delaying before retrying `recalculate_course_grade` task"
            )

            recalculate_course_grade.apply_async(
                (course_id, retries + 1),
                countdown=settings.INTEGRITY_RETRY_BACKOFF)
        else:
            raise ex
    except Course.DoesNotExist:
        logger.info(f"Course {course_id} does not exist. Nothing to do.")
Ejemplo n.º 4
0
def import_example_schedule(user_id):
    try:
        user = get_user_model().objects.get(pk=user_id)
    except get_user_model().DoesNotExist:
        logger.info(f'User {user_id} does not exist. Nothing to do.')

        return

    importservice.import_example_schedule(user)

    metricutils.increment('task.user.example-imported')
Ejemplo n.º 5
0
def send_text(phone, message):
    if settings.DISABLE_EMAILS:
        logger.warning(
            f'Emails disabled. Text with message "{message}" to {phone} not sent.'
        )
        return

    logger.info(f'Sending text with message "{message}" to {phone}')

    send_sms(phone, message)

    metricutils.increment('task.text.sent')
Ejemplo n.º 6
0
def send_text(phone, message):
    if settings.DISABLE_EMAILS:
        logger.warning(
            'Emails disabled. Text with message "{}" to {} not sent.'.format(
                message, phone))
        return

    logger.info('Sending text with message "{}" to {}'.format(message, phone))

    send_sms(phone, message)

    metricutils.increment('task.text.sent')
Ejemplo n.º 7
0
def process_email_reminders():
    from helium.planner.tasks import send_email_reminder

    for reminder in Reminder.objects.with_type(
            enums.EMAIL).unsent().for_today().iterator():
        if reminder.get_user().email and reminder.get_user().is_active:
            subject = get_subject(reminder)

            if not subject:
                logger.warning(
                    f'Reminder {reminder.pk} was not processed, as it appears to be orphaned.'
                )
                continue

            if reminder.event:
                calendar_item_id = reminder.event.pk
                calendar_item_type = enums.EVENT
            elif reminder.homework:
                calendar_item_id = reminder.homework.pk
                calendar_item_type = enums.HOMEWORK
            else:
                logger.warning(
                    f'Reminder {reminder.pk} was not for a homework or event. Nothing to do.'
                )
                continue

            logger.info(
                f'Sending email reminder {reminder.pk} for user {reminder.get_user().pk}'
            )

            metricutils.increment('task.reminder.queue.email')

            send_email_reminder.delay(reminder.get_user().email, subject,
                                      reminder.pk, calendar_item_id,
                                      calendar_item_type)

            reminder.sent = True
            reminder.save()
        else:
            logger.warning(
                'Reminder {} was not processed, as the account appears to be inactive for user {}'
                .format(reminder.pk,
                        reminder.get_user().pk))
Ejemplo n.º 8
0
def verify_email(request):
    """
    Process the code for the given user, verifying their email address and marking them as active (if not already).

    :param request: the request being processed
    :return: a 200 Response upon success
    """
    if 'username' not in request.GET or 'code' not in request.GET:
        raise ValidationError(
            "'username' and 'password' must be given as query parameters")

    try:
        user = get_user_model().objects.get(
            username=request.GET['username'],
            verification_code=request.GET['code'])

        if not user.is_active:
            user.is_active = True
            user.save()

            metricutils.increment('action.user.verified', request)

            logger.info(
                f'Completed registration and verification for user {user.username}'
            )

            if request.GET.get('welcome-email', 'true') == 'true':
                send_registration_email.delay(user.email)
            else:
                logger.info('Welcome email not sent, flag disabled')
        elif user.email_changing:
            user.email = user.email_changing
            user.email_changing = None
            user.save()

            metricutils.increment('action.user.email-changed', request)

            logger.info(f'Verified new email for user {user.username}')

        return Response()
    except get_user_model().DoesNotExist:
        raise NotFound('User not found.')
Ejemplo n.º 9
0
def send_multipart_email(template_name, context, subject, to, bcc=None):
    """
    Send a multipart text/html email.

    :param template_name: The path to the template (no extension), assuming both a .txt and .html version are present
    :param context: A dictionary of context elements to pass to the email templates
    :param subject: The subject of the email
    :param to: A list of email addresses to which to send
    :param bcc: A list of email addresses to which to BCC
    :return:
    """
    plaintext = get_template(f'{template_name}.txt')
    html = get_template(f'{template_name}.html')
    text_content = plaintext.render(context)
    html_content = html.render(context)

    msg = EmailMultiAlternatives(subject, text_content, settings.DEFAULT_FROM_EMAIL, to, bcc)
    msg.attach_alternative(html_content, "text/html")
    msg.send()

    metricutils.increment('action.email.sent')
Ejemplo n.º 10
0
def recalculate_course_group_grade(course_group_id, retries=0):
    metricutils.increment('task.grading.recalculate.course-group')

    # The instance may no longer exist by the time this request is processed, in which case we can simply and safely
    # skip it
    try:
        gradingservice.recalculate_course_group_grade(
            CourseGroup.objects.get(pk=course_group_id))
    except IntegrityError as ex:
        if retries < _INTEGRITY_RETRIES:
            # This error is common when importing schedules, as async tasks may come in different orders
            logger.warning(
                "Integrity error occurred, delaying before retrying `recalculate_course_group_grade` task"
            )

            recalculate_course_group_grade.apply_async(
                (course_group_id, retries + 1),
                countdown=_INTEGRITY_RETRY_DELAY)
        else:
            raise ex
    except CourseGroup.DoesNotExist:
        pass
Ejemplo n.º 11
0
def send_email_reminder(email, subject, reminder_id, calendar_item_id,
                        calendar_item_type):
    # The instance may no longer exist by the time this request is processed, in which case we can simply and safely
    # skip it
    try:
        reminder = Reminder.objects.get(pk=reminder_id)
    except Reminder.DoesNotExist:
        logger.info(f'Reminder {reminder_id} does not exist. Nothing to do.')

        return

    if settings.DISABLE_EMAILS:
        logger.warning(
            f'Emails disabled. Reminder {reminder.pk} not being sent.')
        return

    try:
        if calendar_item_type == enums.EVENT:
            calendar_item = Event.objects.get(pk=calendar_item_id)
        elif calendar_item_type == enums.HOMEWORK:
            calendar_item = Homework.objects.get(pk=calendar_item_id)
        else:
            logger.info(
                f'Nothing to do here, as a calendar_item_type of {calendar_item_type} does not exist.'
            )

            return
    except (Event.DoesNotExist, Homework.DoesNotExist):
        logger.info(
            f'calendar_item_id {calendar_item_id} does not exist. Nothing to do.'
        )

        return

    timezone.activate(pytz.timezone(reminder.user.settings.time_zone))

    start = timezone.localtime(calendar_item.start).strftime(
        settings.NORMALIZED_DATE_FORMAT if calendar_item.all_day else settings.
        NORMALIZED_DATE_TIME_FORMAT)
    end = timezone.localtime(calendar_item.end).strftime(
        settings.NORMALIZED_DATE_FORMAT if calendar_item.all_day else settings.
        NORMALIZED_DATE_TIME_FORMAT)
    normalized_datetime = f'{start} to {end}' if calendar_item.show_end_time else start

    normalized_materials = None
    if reminder.homework:
        normalized_materials = calendar_item.materials.values_list('title',
                                                                   flat=True)
        normalized_materials = ', '.join(normalized_materials)

    comments = calendar_item.comments if calendar_item.comments.strip(
    ) != '' else None

    commonutils.send_multipart_email(
        'email/reminder', {
            'PROJECT_NAME': settings.PROJECT_NAME,
            'reminder': reminder,
            'calendar_item': calendar_item,
            'normalized_datetime': normalized_datetime,
            'normalized_materials': normalized_materials,
            'comments': comments,
        }, subject, [email])

    metricutils.increment('action.reminder.sent.email')

    timezone.deactivate()