def _upgrade_reminder_schedule_send(site_id, msg_str): site = Site.objects.get(pk=site_id) if not ScheduleConfig.current(site).deliver_upgrade_reminder: return msg = Message.from_string(msg_str) ace.send(msg)
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)
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)
def _course_update_schedule_send(site_id, msg_str): site = Site.objects.get(pk=site_id) if not ScheduleConfig.current(site).deliver_course_update: return msg = Message.from_string(msg_str) ace.send(msg)
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)
def send_mail_to_student(student, param_dict, language=None): """ Construct the email using templates and then send it. `student` is the student's email address (a `str`), `param_dict` is a `dict` with keys [ `site_name`: name given to edX instance (a `str`) `registration_url`: url for registration (a `str`) `display_name` : display name of a course (a `str`) `course_id`: id of course (a `str`) `auto_enroll`: user input option (a `str`) `course_url`: url of course (a `str`) `email_address`: email of student (a `str`) `full_name`: student full name (a `str`) `message_type`: type of email to send and template to use (a `str`) `is_shib_course`: (a `boolean`) ] `language` is the language used to render the email. If None the language of the currently-logged in user (that is, the user sending the email) will be used. Returns a boolean indicating whether the email was sent successfully. """ # Add some helpers and microconfig subsitutions if 'display_name' in param_dict: param_dict['course_name'] = param_dict['display_name'] elif 'course' in param_dict: param_dict['course_name'] = Text(param_dict['course'].display_name_with_default) param_dict['site_name'] = configuration_helpers.get_value( 'SITE_NAME', param_dict['site_name'] ) # see if there is an activation email template definition available as configuration, # if so, then render that message_type = param_dict['message_type'] ace_emails_dict = { 'account_creation_and_enrollment': AccountCreationAndEnrollment, 'add_beta_tester': AddBetaTester, 'allowed_enroll': AllowedEnroll, 'allowed_unenroll': AllowedUnenroll, 'enrolled_enroll': EnrollEnrolled, 'enrolled_unenroll': EnrolledUnenroll, 'remove_beta_tester': RemoveBetaTester, } message_class = ace_emails_dict[message_type] message = message_class().personalize( recipient=Recipient(username='', email_address=student), language=language, user_context=param_dict, ) ace.send(message)
def _recurring_nudge_schedule_send(site_id, msg_str): site = Site.objects.get(pk=site_id) if not ScheduleConfig.current(site).deliver_recurring_nudge: LOG.debug('Recurring Nudge: Message delivery disabled for site %s', site.domain) return msg = Message.from_string(msg_str) LOG.debug('Recurring Nudge: Sending message = %s', msg_str) ace.send(msg)
def post(self, request): """ POST /api/user/v1/accounts/deactivate_logout/ Marks the user as having no password set for deactivation purposes, and logs the user out. """ user_model = get_user_model() try: # Get the username from the request and check that it exists verify_user_password_response = self._verify_user_password(request) if verify_user_password_response.status_code != status.HTTP_204_NO_CONTENT: return verify_user_password_response with transaction.atomic(): UserRetirementStatus.create_retirement(request.user) # Unlink LMS social auth accounts UserSocialAuth.objects.filter(user_id=request.user.id).delete() # Change LMS password & email user_email = request.user.email request.user.email = get_retired_email_by_email(request.user.email) request.user.save() _set_unusable_password(request.user) # TODO: Unlink social accounts & change password on each IDA. # Remove the activation keys sent by email to the user for account activation. Registration.objects.filter(user=request.user).delete() # Add user to retirement queue. # Delete OAuth tokens associated with the user. retire_dop_oauth2_models(request.user) retire_dot_oauth2_models(request.user) try: # Send notification email to user site = Site.objects.get_current() notification_context = get_base_template_context(site) notification_context.update({'full_name': request.user.profile.name}) notification = DeletionNotificationMessage().personalize( recipient=Recipient(username='', email_address=user_email), language=request.user.profile.language, user_context=notification_context, ) ace.send(notification) except Exception as exc: log.exception('Error sending out deletion notification email') raise # Log the user out. logout(request) return Response(status=status.HTTP_204_NO_CONTENT) except KeyError: return Response(u'Username not specified.', status=status.HTTP_404_NOT_FOUND) except user_model.DoesNotExist: return Response( u'The user "{}" does not exist.'.format(request.user.username), status=status.HTTP_404_NOT_FOUND ) except Exception as exc: # pylint: disable=broad-except return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def _schedule_send(msg_str, site_id, delivery_config_var, log_prefix): site = Site.objects.select_related('configuration').get(pk=site_id) if _is_delivery_enabled(site, delivery_config_var, log_prefix): msg = Message.from_string(msg_str) user = User.objects.get(username=msg.recipient.username) with emulate_http_request(site=site, user=user): _annonate_send_task_for_monitoring(msg) LOG.debug('%s: Sending message = %s', log_prefix, msg_str) ace.send(msg) _track_message_sent(site, user, msg)
def send(self, msg_type): for (user, language, context) in self.build_email_context(): msg = msg_type.personalize( Recipient( user.username, user.email, ), language, context ) ace.send(msg)
def _recurring_nudge_schedule_send(site_id, msg_str): site = Site.objects.get(pk=site_id) if not ScheduleConfig.current(site).deliver_recurring_nudge: LOG.debug('Recurring Nudge: Message delivery disabled for site %s', site.domain) return msg = Message.from_string(msg_str) # A unique identifier for this batch of messages being sent. set_custom_metric('send_uuid', msg.send_uuid) # A unique identifier for this particular message. set_custom_metric('uuid', msg.uuid) LOG.debug('Recurring Nudge: Sending message = %s', msg_str) ace.send(msg)
def send_ace_message(context): context['course_id'] = CourseKey.from_string(context['course_id']) if _should_send_message(context): context['site'] = Site.objects.get(id=context['site_id']) thread_author = User.objects.get(id=context['thread_author_id']) with emulate_http_request(site=context['site'], user=thread_author): message_context = _build_message_context(context) message = ResponseNotification().personalize( Recipient(thread_author.username, thread_author.email), _get_course_language(context['course_id']), message_context ) log.info('Sending forum comment email notification with context %s', message_context) ace.send(message)
def send_activation_email(self, msg, from_address=None): """ Sending an activation email to the user. """ max_retries = settings.RETRY_ACTIVATION_EMAIL_MAX_ATTEMPTS retries = self.request.retries if from_address is None: from_address = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL) from_address = configuration_helpers.get_value('ACTIVATION_EMAIL_FROM_ADDRESS') or from_address msg.options['from_address'] = from_address dest_addr = msg.recipient.email_address try: ace.send(msg) # Log that the Activation Email has been sent to user without an exception log.info("Activation Email has been sent to User {user_email}".format( user_email=dest_addr )) except RecoverableChannelDeliveryError: log.info('Retrying sending email to user {dest_addr}, attempt # {attempt} of {max_attempts}'.format( dest_addr=dest_addr, attempt=retries, max_attempts=max_retries )) try: self.retry(countdown=settings.RETRY_ACTIVATION_EMAIL_TIMEOUT, max_retries=max_retries) except MaxRetriesExceededError: log.error( 'Unable to send activation email to user from "%s" to "%s"', from_address, dest_addr, exc_info=True ) except Exception: # pylint: disable=bare-except log.exception( 'Unable to send activation email to user from "%s" to "%s"', from_address, dest_addr, exc_info=True ) raise Exception
def send_verification_expiry_email(batch_verifications, dry_run=False): """ Spins a task to send verification expiry email to the learners in the batch using edx_ace If the email is successfully sent change the expiry_email_date to reflect when the email was sent """ if dry_run: logger.info( u"This was a dry run, no email was sent. For the actual run email would have been sent " u"to {} learner(s)".format(len(batch_verifications)) ) return site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'platform_name': settings.PLATFORM_NAME, 'lms_verification_link': '{}{}'.format(settings.LMS_ROOT_URL, reverse("verify_student_reverify")), 'help_center_link': settings.ID_VERIFICATION_SUPPORT_LINK }) expiry_email = VerificationExpiry(context=message_context) users = User.objects.filter(pk__in=[verification.user_id for verification in batch_verifications]) for verification in batch_verifications: user = users.get(pk=verification.user_id) with emulate_http_request(site=site, user=user): msg = expiry_email.personalize( recipient=Recipient(user.username, user.email), language=get_user_preference(user, LANGUAGE_KEY), user_context={ 'full_name': user.profile.name, } ) ace.send(msg) verification_qs = SoftwareSecurePhotoVerification.objects.filter(pk=verification.pk) verification_qs.update(expiry_email_date=now())
def send_ace_message(goal): """ Send an email reminding users to stay on track for their learning goal in this course Arguments: goal (CourseGoal): Goal object """ user = goal.user try: course = CourseOverview.get_from_id(goal.course_key) except CourseOverview.DoesNotExist: log.error("Goal Reminder course not found.") course_name = course.display_name site = Site.objects.get_current() message_context = get_base_template_context(site) course_home_url = get_learning_mfe_home_url(course_key=goal.course_key, url_fragment='home') goals_unsubscribe_url = f'{settings.LEARNING_MICROFRONTEND_URL}/goal-unsubscribe/{goal.unsubscribe_token}' language = get_user_preference(user, LANGUAGE_KEY) # Code to allow displaying different banner images for different languages # However, we'll likely want to develop a better way to do this within edx-ace image_url = settings.STATIC_URL if image_url: # If the image url is a relative url prepend the LMS ROOT if 'http' not in image_url: image_url = settings.LMS_ROOT_URL + settings.STATIC_URL image_url += 'images/' if language and language in ['es', 'es-419']: image_url += 'spanish-' message_context.update({ 'email': user.email, 'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME), 'course_name': course_name, 'days_per_week': goal.days_per_week, 'course_url': course_home_url, 'goals_unsubscribe_url': goals_unsubscribe_url, 'image_url': image_url, 'unsubscribe_url': None, # We don't want to include the default unsubscribe link 'omit_unsubscribe_link': True, 'courses_url': getattr(settings, 'ACE_EMAIL_COURSES_URL', None), 'programs_url': getattr(settings, 'ACE_EMAIL_PROGRAMS_URL', None), }) msg = Message( name="goalreminder", app_label="course_goals", recipient=Recipient(user.id, user.email), language=language, context=message_context, options={'transactional': True}, ) with emulate_http_request(site, user): ace.send(msg)
def _schedule_send(msg_str, site_id, delivery_config_var, log_prefix): if _is_delivery_enabled(site_id, delivery_config_var, log_prefix): msg = Message.from_string(msg_str) _annonate_send_task_for_monitoring(msg) LOG.debug('%s: Sending message = %s', log_prefix, msg_str) ace.send(msg)
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."))
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", })
def do_email_change_request(user, new_email, activation_key=None, secondary_email_change_request=False): """ Given a new email for a user, does some basic verification of the new address and sends an activation message to the new address. If any issues are encountered with verification or sending the message, a ValueError will be thrown. """ # if activation_key is not passing as an argument, generate a random key if not activation_key: activation_key = uuid.uuid4().hex confirm_link = reverse('confirm_email_change', kwargs={'key': activation_key, }) if secondary_email_change_request: PendingSecondaryEmailChange.objects.update_or_create( user=user, defaults={ 'new_secondary_email': new_email, 'activation_key': activation_key, } ) confirm_link = reverse('activate_secondary_email', kwargs={'key': activation_key}) else: PendingEmailChange.objects.update_or_create( user=user, defaults={ 'new_email': new_email, 'activation_key': activation_key, } ) use_https = theming_helpers.get_current_request().is_secure() site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'old_email': user.email, 'new_email': new_email, 'confirm_link': '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=confirm_link, ), }) if secondary_email_change_request: msg = RecoveryEmailCreate().personalize( recipient=Recipient(user.username, new_email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) else: msg = EmailChange().personalize( recipient=Recipient(user.username, new_email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) try: ace.send(msg) except Exception: from_address = configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL) log.error(u'Unable to send email activation link to user from "%s"', from_address, exc_info=True) raise ValueError(_('Unable to send email activation link. Please try again later.')) if not secondary_email_change_request: # When the email address change is complete, a "edx.user.settings.changed" event will be emitted. # But because changing the email address is multi-step, we also emit an event here so that we can # track where the request was initiated. tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": message_context['old_email'], "new": message_context['new_email'], "user_id": user.id, } )
def confirm_email_change(request, key): """ User requested a new e-mail. This is called when the activation link is clicked. We confirm with the old e-mail, and update """ with transaction.atomic(): try: pec = PendingEmailChange.objects.get(activation_key=key) except PendingEmailChange.DoesNotExist: response = render_to_response("invalid_email_key.html", {}) transaction.set_rollback(True) return response user = pec.user address_context = { 'old_email': user.email, 'new_email': pec.new_email } if len(User.objects.filter(email=pec.new_email)) != 0: response = render_to_response("email_exists.html", {}) transaction.set_rollback(True) return response use_https = request.is_secure() if settings.FEATURES['ENABLE_MKTG_SITE']: contact_link = marketing_link('CONTACT') else: contact_link = '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('contact'), ) site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'old_email': user.email, 'new_email': pec.new_email, 'contact_link': contact_link, 'from_address': configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL), }) msg = EmailChangeConfirmation().personalize( recipient=Recipient(user.id, user.email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) u_prof = UserProfile.objects.get(user=user) meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] meta['old_emails'].append([user.email, datetime.datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to old address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': user.email}) transaction.set_rollback(True) return response user.email = pec.new_email user.save() pec.delete() # And send it to the new email... msg.recipient = Recipient(user.id, pec.new_email) try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to new address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': pec.new_email}) transaction.set_rollback(True) return response response = render_to_response("email_change_successful.html", address_context) return response
def confirm_email_change(request, key): # pylint: disable=unused-argument """ User requested a new e-mail. This is called when the activation link is clicked. We confirm with the old e-mail, and update """ if waffle().is_enabled(PREVENT_AUTH_USER_WRITES): return render_to_response('email_change_failed.html', {'err_msg': SYSTEM_MAINTENANCE_MSG}) with transaction.atomic(): try: pec = PendingEmailChange.objects.get(activation_key=key) except PendingEmailChange.DoesNotExist: response = render_to_response("invalid_email_key.html", {}) transaction.set_rollback(True) return response user = pec.user address_context = { 'old_email': user.email, 'new_email': pec.new_email } if len(User.objects.filter(email=pec.new_email)) != 0: response = render_to_response("email_exists.html", {}) transaction.set_rollback(True) return response use_https = request.is_secure() if settings.FEATURES['ENABLE_MKTG_SITE']: contact_link = marketing_link('CONTACT') else: contact_link = '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('contact'), ) site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'old_email': user.email, 'new_email': pec.new_email, 'contact_link': contact_link, 'from_address': configuration_helpers.get_value('email_from_address', settings.DEFAULT_FROM_EMAIL), }) msg = EmailChangeConfirmation().personalize( recipient=Recipient(user.username, user.email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) u_prof = UserProfile.objects.get(user=user) meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] meta['old_emails'].append([user.email, datetime.datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to old address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': user.email}) transaction.set_rollback(True) return response user.email = pec.new_email user.save() pec.delete() # And send it to the new email... msg.recipient = Recipient(user.username, pec.new_email) try: ace.send(msg) except Exception: # pylint: disable=broad-except log.warning('Unable to send confirmation email to new address', exc_info=True) response = render_to_response("email_change_failed.html", {'email': pec.new_email}) transaction.set_rollback(True) return response response = render_to_response("email_change_successful.html", address_context) return response
def post(self, request, **kwargs): body_unicode = request.body.decode('utf-8') body = json.loads(body_unicode) username = body['username'] pathway_id = body['pathway_id'] program_uuid = kwargs['uuid'] # verify that the user or an admin is making the request if username != request.user.get_username( ) and not request.user.is_staff: return JsonResponse({'error': 'Permission denied'}, status=403) credential = UserCredential.objects.filter( username=username, status=UserCredential.AWARDED, program_credentials__program_uuid=program_uuid) program = get_object_or_404(Program, uuid=program_uuid, site=request.site) pathway = get_object_or_404( Pathway, id=pathway_id, programs__uuid=program_uuid, pathway_type=PathwayType.CREDIT.value, ) certificate = get_object_or_404(ProgramCertificate, program_uuid=program_uuid, site=request.site) user = get_object_or_404(User, username=username) public_record, _ = ProgramCertRecord.objects.get_or_create( user=user, program=program) # Make sure we haven't already sent an email with a 'sent' status if UserCreditPathway.objects.filter( user=user, pathway=pathway, status=UserCreditPathwayStatus.SENT).exists(): return JsonResponse({'error': 'Pathway email already sent'}, status=400) record_path = reverse('records:public_programs', kwargs={'uuid': public_record.uuid.hex}) record_link = request.build_absolute_uri(record_path) csv_link = urllib.parse.urljoin(record_link, "csv") msg = ProgramCreditRequest(request.site).personalize( recipient=Recipient(username=None, email_address=pathway.email), language=certificate.language, user_context={ 'pathway_name': pathway.name, 'program_name': program.title, 'record_link': record_link, 'user_full_name': request.user.get_full_name() or request.user.username, 'program_completed': credential.exists(), 'previously_sent': False, 'csv_link': csv_link, }, ) ace.send(msg) # Create a record of this email so that we can't send multiple times # If the status was previously changed, we want to reset it to SENT UserCreditPathway.objects.update_or_create( user=user, pathway=pathway, defaults={'status': UserCreditPathwayStatus.SENT}, ) return http.HttpResponse(status=200)
def do_email_change_request(user, new_email, activation_key=None): """ Given a new email for a user, does some basic verification of the new address and sends an activation message to the new address. If any issues are encountered with verification or sending the message, a ValueError will be thrown. """ pec_list = PendingEmailChange.objects.filter(user=user) if len(pec_list) == 0: pec = PendingEmailChange() pec.user = user else: pec = pec_list[0] # if activation_key is not passing as an argument, generate a random key if not activation_key: activation_key = uuid.uuid4().hex pec.new_email = new_email pec.activation_key = activation_key pec.save() use_https = theming_helpers.get_current_request().is_secure() site = Site.objects.get_current() message_context = get_base_template_context(site) message_context.update({ 'old_email': user.email, 'new_email': pec.new_email, 'confirm_link': '{protocol}://{site}{link}'.format( protocol='https' if use_https else 'http', site=configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME), link=reverse('confirm_email_change', kwargs={ 'key': pec.activation_key, }), ), }) msg = EmailChange().personalize( recipient=Recipient(user.username, pec.new_email), language=preferences_api.get_user_preference(user, LANGUAGE_KEY), user_context=message_context, ) try: ace.send(msg) except Exception: from_address = configuration_helpers.get_value( 'email_from_address', settings.DEFAULT_FROM_EMAIL) log.error(u'Unable to send email activation link to user from "%s"', from_address, exc_info=True) raise ValueError( _('Unable to send email activation link. Please try again later.')) # When the email address change is complete, a "edx.user.settings.changed" event will be emitted. # But because changing the email address is multi-step, we also emit an event here so that we can # track where the request was initiated. tracker.emit( SETTING_CHANGE_INITIATED, { "setting": "email", "old": message_context['old_email'], "new": message_context['new_email'], "user_id": user.id, })
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."))
def post(self, request): """ POST /api/user/v1/accounts/deactivate_logout/ Marks the user as having no password set for deactivation purposes, and logs the user out. """ user_model = get_user_model() try: # Get the username from the request and check that it exists verify_user_password_response = self._verify_user_password(request) if verify_user_password_response.status_code != status.HTTP_204_NO_CONTENT: return verify_user_password_response with transaction.atomic(): # Add user to retirement queue. UserRetirementStatus.create_retirement(request.user) # Unlink LMS social auth accounts UserSocialAuth.objects.filter(user_id=request.user.id).delete() # Change LMS password & email user_email = request.user.email request.user.email = get_retired_email_by_email( request.user.email) request.user.save() _set_unusable_password(request.user) # TODO: Unlink social accounts & change password on each IDA. # Remove the activation keys sent by email to the user for account activation. Registration.objects.filter(user=request.user).delete() # Delete OAuth tokens associated with the user. retire_dop_oauth2_models(request.user) retire_dot_oauth2_models(request.user) AccountRecovery.retire_recovery_email(request.user.id) try: # Send notification email to user site = Site.objects.get_current() notification_context = get_base_template_context(site) notification_context.update( {'full_name': request.user.profile.name}) language_code = request.user.preferences.model.get_value( request.user, LANGUAGE_KEY, default=settings.LANGUAGE_CODE) notification = DeletionNotificationMessage().personalize( recipient=Recipient(username='', email_address=user_email), language=language_code, user_context=notification_context, ) ace.send(notification) except Exception as exc: log.exception( 'Error sending out deletion notification email') raise # Log the user out. logout(request) return Response(status=status.HTTP_204_NO_CONTENT) except KeyError: return Response(u'Username not specified.', status=status.HTTP_404_NOT_FOUND) except user_model.DoesNotExist: return Response(u'The user "{}" does not exist.'.format( request.user.username), status=status.HTTP_404_NOT_FOUND) except Exception as exc: # pylint: disable=broad-except return Response(text_type(exc), status=status.HTTP_500_INTERNAL_SERVER_ERROR)