def consume(self, data: Mapping[str, Any]) -> None: if "email" in data: # When upgrading from a version up through 1.7.1, there may be # existing items in the queue with `email` instead of `prereg_id`. invitee = PreregistrationUser.objects.filter( email__iexact=data["email"].strip()).latest("invited_at") else: invitee = PreregistrationUser.objects.filter(id=data["prereg_id"]).first() if invitee is None: # The invitation could have been revoked return referrer = get_user_profile_by_id(data["referrer_id"]) logger.info("Sending invitation for realm %s to %s" % (referrer.realm.string_id, invitee.email)) do_send_confirmation_email(invitee, referrer) # queue invitation reminder for two days from now. link = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION) context = common_context(referrer) context.update({ 'activate_url': link, 'referrer_name': referrer.full_name, 'referrer_email': referrer.email, 'referrer_realm_name': referrer.realm.name, }) send_future_email( "zerver/emails/invitation_reminder", referrer.realm, to_emails=[invitee.email], from_address=FromAddress.tokenized_no_reply_address(), language=referrer.realm.default_language, context=context, delay=datetime.timedelta(days=2))
def maybe_send_to_registration(request, email, full_name='', password_required=True): # type: (HttpRequest, Text, Text, bool) -> HttpResponse form = HomepageForm({'email': email}, realm=get_realm_from_request(request)) request.verified_email = None if form.is_valid(): # Construct a PreregistrationUser object and send the user over to # the confirmation view. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter(email__iexact=email).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user(email, request, password_required=password_required) else: prereg_user = create_preregistration_user(email, request, password_required=password_required) return redirect("".join(( create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION), '?full_name=', # urllib does not handle Unicode, so coerece to encoded byte string # Explanation: http://stackoverflow.com/a/5605354/90777 urllib.parse.quote_plus(full_name.encode('utf8'))))) else: url = reverse('register') return render(request, 'zerver/accounts_home.html', context={'form': form, 'current_url': lambda: url}, )
def handle(self, *args: Any, **options: Any) -> None: duplicates = False realm = self.get_realm(options) assert realm is not None # Should be ensured by parser if not options['emails']: self.print_help("./manage.py", "generate_invite_links") exit(1) for email in options['emails']: try: self.get_user(email, realm) print(email + ": There is already a user registered with that address.") duplicates = True continue except CommandError: pass if duplicates: return for email in options['emails']: try: email_allowed_for_realm(email, realm) except DomainNotAllowedForRealmError: if not options["force"]: print("You've asked to add an external user '%s' to a closed realm '%s'." % ( email, realm.string_id)) print("Are you sure? To do this, pass --force.") exit(1) prereg_user = PreregistrationUser(email=email, realm=realm) prereg_user.save() print(email + ": " + create_confirmation_link(prereg_user, realm.host, Confirmation.INVITATION))
def one_click_unsubscribe_link(user_profile: UserProfile, email_type: str) -> str: """ Generate a unique link that a logged-out user can visit to unsubscribe from Zulip e-mails without having to first log in. """ return create_confirmation_link(user_profile, user_profile.realm.host, Confirmation.UNSUBSCRIBE, url_args = {'email_type': email_type})
def test_realm_reactivation_link(self) -> None: realm = get_realm('zulip') do_deactivate_realm(realm) self.assertTrue(realm.deactivated) confirmation_url = create_confirmation_link(realm, realm.host, Confirmation.REALM_REACTIVATION) response = self.client_get(confirmation_url) self.assert_in_success_response(['Your organization has been successfully reactivated'], response) realm = get_realm('zulip') self.assertFalse(realm.deactivated)
def maybe_send_to_registration(request: HttpRequest, email: str, full_name: str='', is_signup: bool=False, password_required: bool=True, multiuse_object_key: str='') -> HttpResponse: realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None invited_as = PreregistrationUser.INVITE_AS['MEMBER'] if multiuse_object_key: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get(confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() invited_as = multiuse_obj.invited_as form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # Construct a PreregistrationUser object and send the user over to # the confirmation view. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user(email, request, password_required=password_required) else: prereg_user = create_preregistration_user(email, request, password_required=password_required) if multiuse_object_key: request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() confirmation_link = create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = {'email': email, 'continue_link': confirmation_link, 'full_name': full_name} return render(request, 'zerver/confirm_continue_registration.html', context=context) else: url = reverse('register') return render(request, 'zerver/accounts_home.html', context={'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite, 'multiuse_object_key': multiuse_object_key}, )
def maybe_send_to_registration(request: HttpRequest, email: str, full_name: str='', is_signup: bool=False, password_required: bool=True) -> HttpResponse: realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None multiuse_object_key = request.session.get("multiuse_object_key", None) if multiuse_object_key is not None: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get(confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # Construct a PreregistrationUser object and send the user over to # the confirmation view. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user(email, request, password_required=password_required) else: prereg_user = create_preregistration_user(email, request, password_required=password_required) if multiuse_object_key is not None: del request.session["multiuse_object_key"] request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) confirmation_link = "".join(( create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION), '?full_name=', # urllib does not handle Unicode, so coerece to encoded byte string # Explanation: http://stackoverflow.com/a/5605354/90777 urllib.parse.quote_plus(full_name.encode('utf8')))) if is_signup: return redirect(confirmation_link) context = {'email': email, 'continue_link': confirmation_link} return render(request, 'zerver/confirm_continue_registration.html', context=context) else: url = reverse('register') return render(request, 'zerver/accounts_home.html', context={'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite}, )
def send_registration_completion_email(email, request, realm_creation=False): # type: (str, HttpRequest, bool) -> None """ Send an email with a confirmation link to the provided e-mail so the user can complete their registration. """ prereg_user = create_preregistration_user(email, request, realm_creation) activation_url = create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION) send_email('zerver/emails/confirm_registration', to_email=email, from_address=FromAddress.NOREPLY, context={'activate_url': activation_url}) if settings.DEVELOPMENT and realm_creation: request.session['confirmation_key'] = {'confirmation_key': activation_url.split('/')[-1]}
def prepare_activation_url(email: str, request: HttpRequest, realm_creation: bool=False, streams: Optional[List[Stream]]=None) -> str: """ Send an email with a confirmation link to the provided e-mail so the user can complete their registration. """ prereg_user = create_preregistration_user(email, request, realm_creation) if streams is not None: prereg_user.streams.set(streams) confirmation_type = Confirmation.USER_REGISTRATION if realm_creation: confirmation_type = Confirmation.REALM_CREATION activation_url = create_confirmation_link(prereg_user, request.get_host(), confirmation_type) if settings.DEVELOPMENT and realm_creation: request.session['confirmation_key'] = {'confirmation_key': activation_url.split('/')[-1]} return activation_url
def handle(self, *args: Any, **options: Any) -> None: realm = self.get_realm(options) assert realm is not None # Should be ensured by parser streams = [] if options["streams"]: stream_names = set([stream.strip() for stream in options["streams"].split(",")]) for stream_name in set(stream_names): stream, _ = create_stream_if_needed(realm, stream_name) streams.append(stream) referred_by = self.get_user(options['referred_by'], realm) invite = MultiuseInvite.objects.create(realm=realm, referred_by=referred_by) if streams: invite.streams = streams invite.save() invite_link = create_confirmation_link(invite, realm.host, Confirmation.MULTIUSE_INVITE) print("You can use %s to invite as many number of people to the organization." % (invite_link,))
def consume(self, data): # type: (Mapping[str, Any]) -> None invitee = get_prereg_user_by_email(data["email"]) referrer = get_user_profile_by_id(data["referrer_id"]) body = data["email_body"] do_send_confirmation_email(invitee, referrer, body) # queue invitation reminder for two days from now. link = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION) context = common_context(referrer) context.update({ 'activate_url': link, 'referrer_name': referrer.full_name, 'referrer_email': referrer.email, 'referrer_realm_name': referrer.realm.name, }) send_future_email( "zerver/emails/invitation_reminder", to_email=data["email"], from_address=FromAddress.NOREPLY, context=context, delay=datetime.timedelta(days=2))
def send_registration_completion_email(email: str, request: HttpRequest, realm_creation: bool=False, streams: Optional[List[Stream]]=None) -> None: """ Send an email with a confirmation link to the provided e-mail so the user can complete their registration. """ prereg_user = create_preregistration_user(email, request, realm_creation) if streams is not None: prereg_user.streams = streams prereg_user.save() confirmation_type = Confirmation.USER_REGISTRATION if realm_creation: confirmation_type = Confirmation.REALM_CREATION activation_url = create_confirmation_link(prereg_user, request.get_host(), confirmation_type) send_email('zerver/emails/confirm_registration', to_email=email, from_address=FromAddress.NOREPLY, context={'activate_url': activation_url}) if settings.DEVELOPMENT and realm_creation: request.session['confirmation_key'] = {'confirmation_key': activation_url.split('/')[-1]}
def test_change_delivery_email_end_to_end_with_admins_visibility( self) -> None: user_profile = self.example_user("hamlet") do_set_realm_property( user_profile.realm, "email_address_visibility", Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS, acting_user=None, ) self.login_user(user_profile) old_email = user_profile.delivery_email new_email = "*****@*****.**" obj = EmailChangeStatus.objects.create( new_email=new_email, old_email=old_email, user_profile=user_profile, realm=user_profile.realm, ) url = create_confirmation_link(obj, Confirmation.EMAIL_CHANGE) response = self.client_get(url) self.assertEqual(response.status_code, 200) self.assert_in_success_response( ["This confirms that the email address for your Zulip"], response) user_profile = get_user_profile_by_id(user_profile.id) self.assertEqual(user_profile.delivery_email, new_email) self.assertEqual(user_profile.email, f"user{user_profile.id}@zulip.testserver") obj.refresh_from_db() self.assertEqual(obj.status, 1) with self.assertRaises(UserProfile.DoesNotExist): get_user(old_email, user_profile.realm) with self.assertRaises(UserProfile.DoesNotExist): get_user_by_delivery_email(old_email, user_profile.realm) self.assertEqual( get_user_by_delivery_email(new_email, user_profile.realm), user_profile)
def handle(self, *args: Any, **options: Any) -> None: duplicates = False realm = self.get_realm(options) assert realm is not None # Should be ensured by parser if not options['emails']: self.print_help("./manage.py", "generate_invite_links") raise CommandError for email in options['emails']: try: self.get_user(email, realm) print( email + ": There is already a user registered with that address.") duplicates = True continue except CommandError: pass if duplicates: return for email in options['emails']: try: email_allowed_for_realm(email, realm) except DomainNotAllowedForRealmError: if not options["force"]: raise CommandError( "You've asked to add an external user '{}' to a " "closed realm '{}'.\nAre you sure? To do this, " "pass --force.".format(email, realm.string_id)) prereg_user = PreregistrationUser(email=email, realm=realm) prereg_user.save() print( email + ": " + create_confirmation_link(prereg_user, Confirmation.INVITATION))
def consume(self, data): # type: (Mapping[str, Any]) -> None invitee = get_prereg_user_by_email(data["email"]) referrer = get_user_profile_by_id(data["referrer_id"]) body = data["email_body"] logging.info("Sending invitation for realm %s to %s" % (referrer.realm.string_id, invitee.email)) do_send_confirmation_email(invitee, referrer, body) # queue invitation reminder for two days from now. link = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION) context = common_context(referrer) context.update({ 'activate_url': link, 'referrer_name': referrer.full_name, 'referrer_email': referrer.email, 'referrer_realm_name': referrer.realm.name, }) send_future_email( "zerver/emails/invitation_reminder", to_email=data["email"], from_address=FromAddress.NOREPLY, context=context, delay=datetime.timedelta(days=2))
def do_send_realm_reactivation_email( realm: Realm, *, acting_user: Optional[UserProfile]) -> None: url = create_confirmation_link(realm, Confirmation.REALM_REACTIVATION) RealmAuditLog.objects.create( realm=realm, acting_user=acting_user, event_type=RealmAuditLog.REALM_REACTIVATION_EMAIL_SENT, event_time=timezone_now(), ) context = { "confirmation_url": url, "realm_uri": realm.uri, "realm_name": realm.name } language = realm.default_language send_email_to_admins( "zerver/emails/realm_reactivation", realm, from_address=FromAddress.tokenized_no_reply_address(), from_name=FromAddress.security_email_from_name(language=language), language=language, context=context, )
def handle(self, *args, **options): # type: (*Any, **Any) -> None duplicates = False realm = self.get_realm(options) assert realm is not None # Should be ensured by parser if not options['emails']: self.print_help("./manage.py", "generate_invite_links") exit(1) for email in options['emails']: try: self.get_user(email, realm) print( email + ": There is already a user registered with that address.") duplicates = True continue except CommandError: pass if duplicates: return for email in options['emails']: if not email_allowed_for_realm(email, realm) and not options["force"]: print( "You've asked to add an external user '%s' to a closed realm '%s'." % (email, realm.string_id)) print("Are you sure? To do this, pass --force.") exit(1) prereg_user = PreregistrationUser(email=email, realm=realm) prereg_user.save() print(email + ": " + create_confirmation_link( prereg_user, realm.host, Confirmation.INVITATION))
def prepare_activation_url(email: str, request: HttpRequest, realm_creation: bool = False, streams: Optional[List[Stream]] = None) -> str: """ Send an email with a confirmation link to the provided e-mail so the user can complete their registration. """ prereg_user = create_preregistration_user(email, request, realm_creation) if streams is not None: prereg_user.streams.set(streams) confirmation_type = Confirmation.USER_REGISTRATION if realm_creation: confirmation_type = Confirmation.REALM_CREATION activation_url = create_confirmation_link(prereg_user, request.get_host(), confirmation_type) if settings.DEVELOPMENT and realm_creation: request.session['confirmation_key'] = { 'confirmation_key': activation_url.split('/')[-1] } return activation_url
def consume(self, data: Mapping[str, Any]) -> None: if "email" in data: # When upgrading from a version up through 1.7.1, there may be # existing items in the queue with `email` instead of `prereg_id`. invitee = PreregistrationUser.objects.filter( email__iexact=data["email"].strip()).latest("invited_at") else: invitee = PreregistrationUser.objects.filter( id=data["prereg_id"]).first() if invitee is None: # The invitation could have been revoked return referrer = get_user_profile_by_id(data["referrer_id"]) logger.info("Sending invitation for realm %s to %s" % (referrer.realm.string_id, invitee.email)) do_send_confirmation_email(invitee, referrer) # queue invitation reminder for two days from now. link = create_confirmation_link(invitee, referrer.realm.host, Confirmation.INVITATION) context = common_context(referrer) context.update({ 'activate_url': link, 'referrer_name': referrer.full_name, 'referrer_email': referrer.email, 'referrer_realm_name': referrer.realm.name, }) send_future_email( "zerver/emails/invitation_reminder", referrer.realm, to_emails=[invitee.email], from_address=FromAddress.tokenized_no_reply_address(), language=referrer.realm.default_language, context=context, delay=datetime.timedelta(days=2))
def register_development_realm(request: HttpRequest) -> HttpResponse: count = UserProfile.objects.count() name = f"user-{count}" email = f"{name}@zulip.com" realm_name = f"realm-{count}" prereg = create_preregistration_user(email, request, realm_creation=True, password_required=False) activation_url = create_confirmation_link(prereg, Confirmation.REALM_CREATION) key = activation_url.split("/")[-1] # Need to add test data to POST request as it doesn't originally contain the required parameters modify_postdata( request, key=key, realm_name=realm_name, full_name=name, password="******", realm_subdomain=realm_name, terms="true", ) return accounts_register(request)
def maybe_send_to_registration(request: HttpRequest, email: str, full_name: str = '', is_signup: bool = False, password_required: bool = True, multiuse_object_key: str = '') -> HttpResponse: """Given a successful authentication for an email address (i.e. we've confirmed the user controls the email address) that does not currently have a Zulip account in the target realm, send them to the registration flow or the "continue to registration" flow, depending on is_signup, whether the email address can join the organization (checked in HomepageForm), and similar details. """ realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None invited_as = PreregistrationUser.INVITE_AS['MEMBER'] if multiuse_object_key: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get( confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() invited_as = multiuse_obj.invited_as form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # If the email address is allowed to sign up for an account in # this organization, construct a PreregistrationUser and # Confirmation objects, and then send the user to account # creation or confirm-continue-registration depending on # is_signup. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required) else: prereg_user = create_preregistration_user( email, request, password_required=password_required) if multiuse_object_key: request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() confirmation_link = create_confirmation_link( prereg_user, request.get_host(), Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = { 'email': email, 'continue_link': confirmation_link, 'full_name': full_name } return render(request, 'zerver/confirm_continue_registration.html', context=context) # This email address it not allowed to join this organization, so # just send the user back to the registration page. url = reverse('register') context = login_context(request) extra_context = { 'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite, 'multiuse_object_key': multiuse_object_key } # type: Mapping[str, Any] context.update(extra_context) return render(request, 'zerver/accounts_home.html', context=context)
def maybe_send_to_registration(request: HttpRequest, email: str, full_name: str = '', is_signup: bool = False, password_required: bool = True) -> HttpResponse: realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None multiuse_object_key = request.session.get("multiuse_object_key", None) invited_as = PreregistrationUser.INVITE_AS['MEMBER'] if multiuse_object_key is not None: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get( confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() invited_as = multiuse_obj.invited_as form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # Construct a PreregistrationUser object and send the user over to # the confirmation view. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required) else: prereg_user = create_preregistration_user( email, request, password_required=password_required) if multiuse_object_key is not None: del request.session["multiuse_object_key"] request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() confirmation_link = create_confirmation_link( prereg_user, request.get_host(), Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = { 'email': email, 'continue_link': confirmation_link, 'full_name': full_name } return render(request, 'zerver/confirm_continue_registration.html', context=context) else: url = reverse('register') return render( request, 'zerver/accounts_home.html', context={ 'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite }, )
def maybe_send_to_registration(request: HttpRequest, email: str, full_name: str='', is_signup: bool=False, password_required: bool=True, multiuse_object_key: str='') -> HttpResponse: """Given a successful authentication for an email address (i.e. we've confirmed the user controls the email address) that does not currently have a Zulip account in the target realm, send them to the registration flow or the "continue to registration" flow, depending on is_signup, whether the email address can join the organization (checked in HomepageForm), and similar details. """ realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None invited_as = PreregistrationUser.INVITE_AS['MEMBER'] if multiuse_object_key: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get(confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() invited_as = multiuse_obj.invited_as form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # If the email address is allowed to sign up for an account in # this organization, construct a PreregistrationUser and # Confirmation objects, and then send the user to account # creation or confirm-continue-registration depending on # is_signup. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user(email, request, password_required=password_required) else: prereg_user = create_preregistration_user(email, request, password_required=password_required) if multiuse_object_key: request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() confirmation_link = create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = {'email': email, 'continue_link': confirmation_link, 'full_name': full_name} return render(request, 'zerver/confirm_continue_registration.html', context=context) # This email address it not allowed to join this organization, so # just send the user back to the registration page. url = reverse('register') return render(request, 'zerver/accounts_home.html', context={'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite, 'multiuse_object_key': multiuse_object_key})
def maybe_send_to_registration(request: HttpRequest, email: str, full_name: str = '', is_signup: bool = False, password_required: bool = True) -> HttpResponse: realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None multiuse_object_key = request.session.get("multiuse_object_key", None) if multiuse_object_key is not None: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get( confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # Construct a PreregistrationUser object and send the user over to # the confirmation view. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required) else: prereg_user = create_preregistration_user( email, request, password_required=password_required) if multiuse_object_key is not None: del request.session["multiuse_object_key"] request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) confirmation_link = "".join(( create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION), '?full_name=', # urllib does not handle Unicode, so coerece to encoded byte string # Explanation: http://stackoverflow.com/a/5605354/90777 urllib.parse.quote_plus(full_name.encode('utf8')))) if is_signup: return redirect(confirmation_link) context = {'email': email, 'continue_link': confirmation_link} return render(request, 'zerver/confirm_continue_registration.html', context=context) else: url = reverse('register') return render( request, 'zerver/accounts_home.html', context={ 'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite }, )
def maybe_send_to_registration(request: HttpRequest, email: Text, full_name: Text = '', is_signup: bool = False, password_required: bool = True) -> HttpResponse: if not is_signup: # If the user isn't trying to sign up, we take them to a # special page asking them whether that's their intent; this # helps prevent accidental account creation when users pick # the wrong Google account. try: validate_email(email) invalid_email = False except ValidationError: # If email address is invalid, we can't send the user # PreregistrationUser flow. invalid_email = True context = { 'full_name': full_name, 'email': email, 'invalid_email': invalid_email } return render(request, 'zerver/confirm_continue_registration.html', context=context) realm = get_realm(get_subdomain(request)) from_multiuse_invite = False multiuse_obj = None streams_to_subscribe = None multiuse_object_key = request.session.get("multiuse_object_key", None) if multiuse_object_key is not None: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get( confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm streams_to_subscribe = multiuse_obj.streams.all() form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # Construct a PreregistrationUser object and send the user over to # the confirmation view. prereg_user = None if settings.ONLY_SSO: try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required) else: prereg_user = create_preregistration_user( email, request, password_required=password_required) if multiuse_object_key is not None: del request.session["multiuse_object_key"] request.session.modified = True if streams_to_subscribe is not None: prereg_user.streams.set(streams_to_subscribe) confirmation_link = "".join(( create_confirmation_link(prereg_user, request.get_host(), Confirmation.USER_REGISTRATION), '?full_name=', # urllib does not handle Unicode, so coerece to encoded byte string # Explanation: http://stackoverflow.com/a/5605354/90777 urllib.parse.quote_plus(full_name.encode('utf8')))) return redirect(confirmation_link) else: url = reverse('register') return render( request, 'zerver/accounts_home.html', context={ 'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite }, )
def maybe_send_to_registration( request: HttpRequest, email: str, full_name: str = '', is_signup: bool = False, password_required: bool = True, multiuse_object_key: str = '', full_name_validated: bool = False) -> HttpResponse: """Given a successful authentication for an email address (i.e. we've confirmed the user controls the email address) that does not currently have a Zulip account in the target realm, send them to the registration flow or the "continue to registration" flow, depending on is_signup, whether the email address can join the organization (checked in HomepageForm), and similar details. """ if multiuse_object_key: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get( confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm invited_as = multiuse_obj.invited_as else: from_multiuse_invite = False multiuse_obj = None try: realm = get_realm(get_subdomain(request)) except Realm.DoesNotExist: realm = None invited_as = PreregistrationUser.INVITE_AS['MEMBER'] form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # If the email address is allowed to sign up for an account in # this organization, construct a PreregistrationUser and # Confirmation objects, and then send the user to account # creation or confirm-continue-registration depending on # is_signup. try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") # password_required and full_name data passed here as argument should take precedence # over the defaults with which the existing PreregistrationUser that we've just fetched # was created. prereg_user.password_required = password_required update_fields = ["password_required"] if full_name: prereg_user.full_name = full_name prereg_user.full_name_validated = full_name_validated update_fields.extend(["full_name", "full_name_validated"]) prereg_user.save(update_fields=update_fields) except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required, full_name=full_name, full_name_validated=full_name_validated) if multiuse_obj is not None: request.session.modified = True streams_to_subscribe = list(multiuse_obj.streams.all()) prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() # We want to create a confirmation link to create an account # in the current realm, i.e. one with a hostname of # realm.host. For the Apache REMOTE_USER_SSO auth code path, # this is preferable over realm.get_host() because the latter # contains the port number of the Apache instance and we want # to send the user back to nginx. But if we're in the realm # creation code path, there might not be a realm yet, so we # have to use request.get_host(). if realm is not None: host = realm.host else: host = request.get_host() confirmation_link = create_confirmation_link( prereg_user, host, Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = { 'email': email, 'continue_link': confirmation_link, 'full_name': full_name } return render(request, 'zerver/confirm_continue_registration.html', context=context) # This email address it not allowed to join this organization, so # just send the user back to the registration page. url = reverse('register') context = login_context(request) extra_context = { 'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite, 'multiuse_object_key': multiuse_object_key } # type: Mapping[str, Any] context.update(extra_context) return render(request, 'zerver/accounts_home.html', context=context)
def maybe_send_to_registration( request: HttpRequest, email: str, full_name: str = "", mobile_flow_otp: Optional[str] = None, desktop_flow_otp: Optional[str] = None, is_signup: bool = False, password_required: bool = True, multiuse_object_key: str = "", full_name_validated: bool = False, ) -> HttpResponse: """Given a successful authentication for an email address (i.e. we've confirmed the user controls the email address) that does not currently have a Zulip account in the target realm, send them to the registration flow or the "continue to registration" flow, depending on is_signup, whether the email address can join the organization (checked in HomepageForm), and similar details. """ # In the desktop and mobile registration flows, the sign up # happens in the browser so the user can use their # already-logged-in social accounts. Then at the end, with the # user account created, we pass the appropriate data to the app # via e.g. a `zulip://` redirect. We store the OTP keys for the # mobile/desktop flow in the session with 1-hour expiry, because # we want this configuration of having a successful authentication # result in being logged into the app to persist if the user makes # mistakes while trying to authenticate (E.g. clicks the wrong # Google account, hits back, etc.) during a given browser session, # rather than just logging into the webapp in the target browser. # # We can't use our usual pre-account-creation state storage # approach of putting something in PreregistrationUser, because # that would apply to future registration attempts on other # devices, e.g. just creating an account on the web on their laptop. assert not (mobile_flow_otp and desktop_flow_otp) if mobile_flow_otp: set_expirable_session_var( request.session, "registration_mobile_flow_otp", mobile_flow_otp, expiry_seconds=3600 ) elif desktop_flow_otp: set_expirable_session_var( request.session, "registration_desktop_flow_otp", desktop_flow_otp, expiry_seconds=3600 ) if multiuse_object_key: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get(confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm invited_as = multiuse_obj.invited_as else: from_multiuse_invite = False multiuse_obj = None try: realm = get_realm(get_subdomain(request)) except Realm.DoesNotExist: realm = None invited_as = PreregistrationUser.INVITE_AS["MEMBER"] form = HomepageForm({"email": email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # If the email address is allowed to sign up for an account in # this organization, construct a PreregistrationUser and # Confirmation objects, and then send the user to account # creation or confirm-continue-registration depending on # is_signup. try: prereg_user = filter_to_valid_prereg_users( PreregistrationUser.objects.filter(email__iexact=email, realm=realm) ).latest("invited_at") # password_required and full_name data passed here as argument should take precedence # over the defaults with which the existing PreregistrationUser that we've just fetched # was created. prereg_user.password_required = password_required update_fields = ["password_required"] if full_name: prereg_user.full_name = full_name prereg_user.full_name_validated = full_name_validated update_fields.extend(["full_name", "full_name_validated"]) prereg_user.save(update_fields=update_fields) except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required, full_name=full_name, full_name_validated=full_name_validated, ) if multiuse_obj is not None: request.session.modified = True streams_to_subscribe = list(multiuse_obj.streams.all()) prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() confirmation_link = create_confirmation_link(prereg_user, Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = {"email": email, "continue_link": confirmation_link, "full_name": full_name} return render(request, "zerver/confirm_continue_registration.html", context=context) # This email address it not allowed to join this organization, so # just send the user back to the registration page. url = reverse("register") context = login_context(request) extra_context: Mapping[str, Any] = { "form": form, "current_url": lambda: url, "from_multiuse_invite": from_multiuse_invite, "multiuse_object_key": multiuse_object_key, "mobile_flow_otp": mobile_flow_otp, "desktop_flow_otp": desktop_flow_otp, } context.update(extra_context) return render(request, "zerver/accounts_home.html", context=context)
def maybe_send_to_registration( request: HttpRequest, email: str, full_name: str = '', mobile_flow_otp: Optional[str] = None, desktop_flow_otp: Optional[str] = None, is_signup: bool = False, password_required: bool = True, multiuse_object_key: str = '', full_name_validated: bool = False) -> HttpResponse: """Given a successful authentication for an email address (i.e. we've confirmed the user controls the email address) that does not currently have a Zulip account in the target realm, send them to the registration flow or the "continue to registration" flow, depending on is_signup, whether the email address can join the organization (checked in HomepageForm), and similar details. """ # In the desktop and mobile registration flows, the sign up # happens in the browser so the user can use their # already-logged-in social accounts. Then at the end, with the # user account created, we pass the appropriate data to the app # via e.g. a `zulip://` redirect. We store the OTP keys for the # mobile/desktop flow in the session with 1-hour expiry, because # we want this configuration of having a successful authentication # result in being logged into the app to persist if the user makes # mistakes while trying to authenticate (E.g. clicks the wrong # Google account, hits back, etc.) during a given browser session, # rather than just logging into the webapp in the target browser. # # We can't use our usual pre-account-creation state storage # approach of putting something in PreregistrationUser, because # that would apply to future registration attempts on other # devices, e.g. just creating an account on the web on their laptop. assert not (mobile_flow_otp and desktop_flow_otp) if mobile_flow_otp: set_expirable_session_var(request.session, 'registration_mobile_flow_otp', mobile_flow_otp, expiry_seconds=3600) elif desktop_flow_otp: set_expirable_session_var(request.session, 'registration_desktop_flow_otp', desktop_flow_otp, expiry_seconds=3600) if multiuse_object_key: from_multiuse_invite = True multiuse_obj = Confirmation.objects.get( confirmation_key=multiuse_object_key).content_object realm = multiuse_obj.realm invited_as = multiuse_obj.invited_as else: from_multiuse_invite = False multiuse_obj = None try: realm = get_realm(get_subdomain(request)) except Realm.DoesNotExist: realm = None invited_as = PreregistrationUser.INVITE_AS['MEMBER'] form = HomepageForm({'email': email}, realm=realm, from_multiuse_invite=from_multiuse_invite) if form.is_valid(): # If the email address is allowed to sign up for an account in # this organization, construct a PreregistrationUser and # Confirmation objects, and then send the user to account # creation or confirm-continue-registration depending on # is_signup. try: prereg_user = PreregistrationUser.objects.filter( email__iexact=email, realm=realm).latest("invited_at") # password_required and full_name data passed here as argument should take precedence # over the defaults with which the existing PreregistrationUser that we've just fetched # was created. prereg_user.password_required = password_required update_fields = ["password_required"] if full_name: prereg_user.full_name = full_name prereg_user.full_name_validated = full_name_validated update_fields.extend(["full_name", "full_name_validated"]) prereg_user.save(update_fields=update_fields) except PreregistrationUser.DoesNotExist: prereg_user = create_preregistration_user( email, request, password_required=password_required, full_name=full_name, full_name_validated=full_name_validated, ) if multiuse_obj is not None: request.session.modified = True streams_to_subscribe = list(multiuse_obj.streams.all()) prereg_user.streams.set(streams_to_subscribe) prereg_user.invited_as = invited_as prereg_user.save() # We want to create a confirmation link to create an account # in the current realm, i.e. one with a hostname of # realm.host. For the Apache REMOTE_USER_SSO auth code path, # this is preferable over realm.get_host() because the latter # contains the port number of the Apache instance and we want # to send the user back to nginx. But if we're in the realm # creation code path, there might not be a realm yet, so we # have to use request.get_host(). if realm is not None: host = realm.host else: host = request.get_host() # Mark 'host' as safe for use in a redirect. It's pulled from the # current request or realm, both of which only allow a limited set of # trusted hosts. confirmation_link = create_confirmation_link( prereg_user, mark_sanitized(host), Confirmation.USER_REGISTRATION) if is_signup: return redirect(confirmation_link) context = { 'email': email, 'continue_link': confirmation_link, 'full_name': full_name } return render(request, 'zerver/confirm_continue_registration.html', context=context) # This email address it not allowed to join this organization, so # just send the user back to the registration page. url = reverse('register') context = login_context(request) extra_context: Mapping[str, Any] = { 'form': form, 'current_url': lambda: url, 'from_multiuse_invite': from_multiuse_invite, 'multiuse_object_key': multiuse_object_key, 'mobile_flow_otp': mobile_flow_otp, 'desktop_flow_otp': desktop_flow_otp, } context.update(extra_context) return render(request, 'zerver/accounts_home.html', context=context)