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()
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()
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.")
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')
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')
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')
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))
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.')
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')
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
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()