def activate(self, *args, **kwargs): username = self.validate_key(kwargs.get('activation_key')) if not username: return False # protect against activating an alternate casing of the email user = User.get_for_email(username) if user and user.is_active: if username != user.email: logger.warning( "Attempted to activate alternate-cased username with already active user" ) return False else: return user user = super(UserActivationView, self).activate(*args, **kwargs) if settings.SEND_USER_ACTIVATION_NOTIFICATION_EMAIL and user: # Send email regarding new user information subject = render_to_string( 'registration/custom_email_subject.txt', {"subject": "New Kolibri Studio Registration"}) message = render_to_string( 'registration/registration_information_email.txt', { "user": user, "information": dict(user.information) }) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [settings.REGISTRATION_INFORMATION_EMAIL]) return user
def save(self, request=None, extra_email_context=None, **kwargs): """ Generate a one-use only link for resetting password and send it to the user. """ email = self.cleaned_data["email"] user = User.get_for_email(email) if user and user.is_active: super(ForgotPasswordForm, self).save(request=request, extra_email_context=extra_email_context, **kwargs) elif user: # For users who were invited but hadn't registered yet if not user.password: context = { 'site': extra_email_context.get('site'), 'user': user, 'domain': extra_email_context.get('domain'), } subject = render_to_string('registration/password_reset_subject.txt', context) subject = ''.join(subject.splitlines()) message = render_to_string('registration/registration_needed_email.txt', context) user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL, ) else: activation_key = self.get_activation_key(user) context = { 'activation_key': activation_key, 'expiration_days': settings.ACCOUNT_ACTIVATION_DAYS, 'site': extra_email_context.get('site'), 'user': user, 'domain': extra_email_context.get('domain'), } subject = render_to_string('registration/password_reset_subject.txt', context) subject = ''.join(subject.splitlines()) message = render_to_string('registration/activation_needed_email.txt', context) user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL, )
def post(self, request): data = json.loads(request.body) form = self.form_class(data) try: # Registration is valid or user hasn't set account up (invitation workflow) if form.is_valid(): self.register(form) return HttpResponse() # Legacy handle invitations where users haven't activated their accounts inactive_user = User.get_for_email(data['email'], is_active=False, password='') if inactive_user: form.errors.clear() user = form.save(commit=False) inactive_user.set_password(form.cleaned_data['password1']) inactive_user.first_name = user.first_name inactive_user.last_name = user.last_name inactive_user.information = user.information inactive_user.policies = user.policies inactive_user.save() self.send_activation_email(inactive_user) return HttpResponse() elif form._errors['email']: return HttpResponseBadRequest( status=405, reason="Account hasn't been activated") return HttpResponseBadRequest() except UserWarning: return HttpResponseForbidden()
def test_get_for_email(self): user1 = self._create_user("*****@*****.**", is_active=False) user2 = self._create_user("*****@*****.**", is_active=False) user3 = self._create_user("*****@*****.**", is_active=True) # active should be returned first self.assertEqual(user3, User.get_for_email("*****@*****.**")) # then the most recent inactive User.objects.filter(id=user3.id).delete() self.assertEqual(user2, User.get_for_email("*****@*****.**")) User.objects.filter(id=user2.id).delete() self.assertEqual(user1, User.get_for_email("*****@*****.**")) User.objects.filter(id=user1.id).delete() # ensure nothing found doesn't error self.assertIsNone(User.get_for_email("*****@*****.**"))
def setUp(self): super(CheckPoliciesTestCase, self).setUp() self.unsaved_user = User( email="*****@*****.**", first_name="Mr.", last_name="Test", is_admin=False, is_staff=False, date_joined=datetime.datetime.now(), policies=None, )
def request_activation_link(request): if request.method != 'POST': return HttpResponseBadRequest( "Only POST requests are allowed on this endpoint.") data = json.loads(request.body) try: user = User.get_for_email(data['email']) if user and not user.is_active: registration_view = UserRegistrationView() registration_view.request = request registration_view.send_activation_email(user) except User.DoesNotExist: pass return HttpResponse( ) # Return success no matter what so people can't try to look up emails
def new_user_redirect(request, email): # If user is accepting an invitation when they were invited without an account user = User.get_for_email(email) # User has been activated since the invitation was sent if user and user.is_active: return redirect(reverse_lazy("base")) logout(request) # User has created an account, but hasn't activated it yet if user and not user.is_active and user.password: return redirect('/accounts/#/account-not-active') # User needs to create an account return redirect('/accounts/#/create?email={}'.format(email))
def login(request): if request.method != "POST": return redirect(reverse_lazy("accounts")) data = json.loads(request.body) user = User.get_for_email(data["username"]) password = data["password"] # User not found if not user: return HttpResponseForbidden() # User is not activated elif not user.is_active and user.check_password(password): return HttpResponseBadRequest(status=405, reason="Account hasn't been activated") user = authenticate(username=user.email, password=password) if user is not None: djangologin(request, user) return redirect(reverse_lazy("channels")) # Return an 'invalid login' error message. return HttpResponseForbidden()
def send_invitation_email(request): try: user_email = request.data["user_email"].lower() channel_id = request.data["channel_id"] share_mode = request.data["share_mode"] channel = Channel.objects.get(id=channel_id) recipient = User.get_for_email(user_email) request.user.can_edit(channel_id) fields = { "invited": recipient, "email": user_email, "channel_id": channel_id, "first_name": recipient.first_name if recipient else '', "last_name": recipient.last_name if recipient else '', } # Need to break into two steps to avoid MultipleObjectsReturned error invitation = Invitation.objects.filter(channel_id=channel_id, email=user_email, revoked=False, accepted=False, declined=False).first() if not invitation: invitation = Invitation.objects.create(**fields) # Handle these values separately as different users might invite the same user again invitation.share_mode = share_mode invitation.sender = invitation.sender or request.user invitation.save() ctx_dict = { 'sender': request.user, 'site': get_current_site(request), 'user': recipient, 'email': user_email, 'first_name': recipient.first_name if recipient else user_email, 'share_mode': share_mode, 'channel_id': channel_id, 'invitation_key': invitation.id, 'channel': channel.name, 'domain': request.META.get('HTTP_ORIGIN') or "https://{}".format( request.get_host() or Site.objects.get_current().domain), } subject = render_to_string('permissions/permissions_email_subject.txt', ctx_dict) message = render_to_string('permissions/permissions_email.txt', ctx_dict) send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [user_email]) except KeyError: return HttpResponseBadRequest("Missing attribute from data: {}".format( request.data)) return Response(InvitationSerializer(invitation).data)
def get_user(self, username): return User.get_for_email(username, is_active=False)