From 36584a3571074480b2fdebafc515eb649e9cda86 Mon Sep 17 00:00:00 2001 From: Sahil Batra Date: Mon, 13 Feb 2023 22:10:16 +0530 Subject: [PATCH] registration: Add code to set email_address_visibility during signup. This commit adds backend code to set email_address_visibility when registering a new user. The realm-level default and the value of source profile gets overridden by the value user selected during signup. --- zerver/actions/create_user.py | 2 ++ zerver/forms.py | 9 +++++++ zerver/lib/create_user.py | 16 ++++++++++--- zerver/lib/test_classes.py | 3 +++ zerver/models.py | 17 ++++++++------ zerver/tests/test_signup.py | 44 +++++++++++++++++++++++++++++++++-- zerver/views/registration.py | 2 ++ 7 files changed, 81 insertions(+), 12 deletions(-) diff --git a/zerver/actions/create_user.py b/zerver/actions/create_user.py index 84a57c5061..14c670b0f9 100644 --- a/zerver/actions/create_user.py +++ b/zerver/actions/create_user.py @@ -390,6 +390,7 @@ def do_create_user( *, acting_user: Optional[UserProfile], enable_marketing_emails: bool = True, + email_address_visibility: Optional[int] = None, ) -> UserProfile: with transaction.atomic(): user_profile = create_user( @@ -409,6 +410,7 @@ def do_create_user( default_all_public_streams=default_all_public_streams, source_profile=source_profile, enable_marketing_emails=enable_marketing_emails, + email_address_visibility=email_address_visibility, ) event_time = user_profile.date_joined diff --git a/zerver/forms.py b/zerver/forms.py index 8a1aa41565..37562f1c36 100644 --- a/zerver/forms.py +++ b/zerver/forms.py @@ -115,6 +115,15 @@ class RegistrationForm(forms.Form): realm_type = forms.IntegerField(required=False) is_demo_organization = forms.BooleanField(required=False) enable_marketing_emails = forms.BooleanField(required=False) + email_address_visibility = forms.TypedChoiceField( + required=False, + coerce=int, + empty_value=None, + choices=[ + (value, name) + for value, name in UserProfile.EMAIL_ADDRESS_VISIBILITY_ID_TO_NAME_MAP.items() + ], + ) def __init__(self, *args: Any, **kwargs: Any) -> None: # Since the superclass doesn't except random extra kwargs, we diff --git a/zerver/lib/create_user.py b/zerver/lib/create_user.py index 77dc29fec5..736d091ac5 100644 --- a/zerver/lib/create_user.py +++ b/zerver/lib/create_user.py @@ -36,6 +36,12 @@ def copy_default_settings( settings_source, RealmUserDefault ): continue + + if settings_name == "email_address_visibility": + # For email_address_visibility, the value selected in registration form + # is preferred over the realm-level default value and value of source + # profile. + continue value = getattr(settings_source, settings_name) setattr(target_profile, settings_name, value) @@ -156,14 +162,18 @@ def create_user( force_id: Optional[int] = None, force_date_joined: Optional[datetime] = None, enable_marketing_emails: Optional[bool] = None, + email_address_visibility: Optional[int] = None, ) -> UserProfile: realm_user_default = RealmUserDefault.objects.get(realm=realm) if bot_type is None: - email_address_visibility = realm_user_default.email_address_visibility + if email_address_visibility is not None: + user_email_address_visibility = email_address_visibility + else: + user_email_address_visibility = realm_user_default.email_address_visibility else: # There is no privacy motivation for limiting access to bot email addresses, # so we hardcode them to EMAIL_ADDRESS_VISIBILITY_EVERYONE. - email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE + user_email_address_visibility = UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE user_profile = create_user_profile( realm, @@ -179,7 +189,7 @@ def create_user( default_language, force_id=force_id, force_date_joined=force_date_joined, - email_address_visibility=email_address_visibility, + email_address_visibility=user_email_address_visibility, ) user_profile.avatar_source = avatar_source user_profile.timezone = timezone diff --git a/zerver/lib/test_classes.py b/zerver/lib/test_classes.py index b512bb9b17..dd6d6279be 100644 --- a/zerver/lib/test_classes.py +++ b/zerver/lib/test_classes.py @@ -755,6 +755,7 @@ Output: key: Optional[str] = None, realm_type: int = Realm.ORG_TYPES["business"]["id"], enable_marketing_emails: Optional[bool] = None, + email_address_visibility: Optional[int] = None, is_demo_organization: bool = False, **extra: str, ) -> "TestHttpResponse": @@ -783,6 +784,8 @@ Output: } if enable_marketing_emails is not None: payload["enable_marketing_emails"] = enable_marketing_emails + if email_address_visibility is not None: + payload["email_address_visibility"] = email_address_visibility if password is not None: payload["password"] = password if realm_in_root_domain is not None: diff --git a/zerver/models.py b/zerver/models.py index 7af33820f3..1ea42b1c06 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -1612,13 +1612,16 @@ class UserBaseSettings(models.Model): email_address_visibility = models.PositiveSmallIntegerField( default=EMAIL_ADDRESS_VISIBILITY_EVERYONE, ) - EMAIL_ADDRESS_VISIBILITY_TYPES = [ - EMAIL_ADDRESS_VISIBILITY_EVERYONE, - EMAIL_ADDRESS_VISIBILITY_MEMBERS, - EMAIL_ADDRESS_VISIBILITY_ADMINS, - EMAIL_ADDRESS_VISIBILITY_NOBODY, - EMAIL_ADDRESS_VISIBILITY_MODERATORS, - ] + + EMAIL_ADDRESS_VISIBILITY_ID_TO_NAME_MAP = { + EMAIL_ADDRESS_VISIBILITY_EVERYONE: gettext_lazy("Admins, moderators, members and guests"), + EMAIL_ADDRESS_VISIBILITY_MEMBERS: gettext_lazy("Admins, moderators and members"), + EMAIL_ADDRESS_VISIBILITY_MODERATORS: gettext_lazy("Admins and moderators"), + EMAIL_ADDRESS_VISIBILITY_ADMINS: gettext_lazy("Admins only"), + EMAIL_ADDRESS_VISIBILITY_NOBODY: gettext_lazy("Nobody"), + } + + EMAIL_ADDRESS_VISIBILITY_TYPES = list(EMAIL_ADDRESS_VISIBILITY_ID_TO_NAME_MAP.keys()) display_settings_legacy = dict( # Don't add anything new to this legacy dict. diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py index 1436eceb37..567604afc4 100644 --- a/zerver/tests/test_signup.py +++ b/zerver/tests/test_signup.py @@ -4291,6 +4291,45 @@ class UserSignUpTest(InviteUserBase): user_profile.twenty_four_hour_time, realm_user_default.twenty_four_hour_time ) + def test_email_address_visibility_for_new_user(self) -> None: + email = self.nonreg_email("newguy") + password = "newpassword" + realm = get_realm("zulip") + realm_user_default = RealmUserDefault.objects.get(realm=realm) + self.assertEqual( + realm_user_default.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_ADMINS + ) + + result = self.client_post("/accounts/home/", {"email": email}) + self.assertEqual(result.status_code, 302) + self.assertTrue( + result["Location"].endswith( + f"/accounts/send_confirm/?email={urllib.parse.quote(email)}" + ) + ) + result = self.client_get(result["Location"]) + self.assert_in_response("Check your email", result) + + # Visit the confirmation link. + confirmation_url = self.get_confirmation_url_from_outbox(email) + result = self.client_get(confirmation_url) + self.assertEqual(result.status_code, 200) + + # Pick a password and agree to the ToS. + result = self.submit_reg_form_for_user( + email, password, email_address_visibility=UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY + ) + self.assertEqual(result.status_code, 302) + + # Realm-level default is overridden by the value passed during signup. + user_profile = self.nonreg_user("newguy") + self.assertEqual( + user_profile.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY + ) + from django.core.mail import outbox + + outbox.pop() + def test_signup_already_active(self) -> None: """ Check if signing up with an active email redirects to a login page. @@ -4668,9 +4707,10 @@ class UserSignUpTest(InviteUserBase): password, source_realm_id=str(hamlet_in_zulip.realm.id), HTTP_HOST=subdomain + ".testserver", + email_address_visibility=UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY, ) - hamlet_in_lear = get_user(email, lear_realm) + hamlet_in_lear = get_user_by_delivery_email(email, lear_realm) self.assertEqual(hamlet_in_lear.left_side_userlist, True) self.assertEqual(hamlet_in_lear.default_language, "de") self.assertEqual(hamlet_in_lear.emojiset, "twitter") @@ -4679,7 +4719,7 @@ class UserSignUpTest(InviteUserBase): self.assertEqual(hamlet_in_lear.enable_stream_audible_notifications, False) self.assertEqual(hamlet_in_lear.tutorial_status, UserProfile.TUTORIAL_FINISHED) self.assertEqual( - hamlet_in_lear.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_EVERYONE + hamlet_in_lear.email_address_visibility, UserProfile.EMAIL_ADDRESS_VISIBILITY_NOBODY ) zulip_path_id = avatar_disk_path(hamlet_in_zulip) diff --git a/zerver/views/registration.py b/zerver/views/registration.py index 2b81a41c30..776c41fe4a 100644 --- a/zerver/views/registration.py +++ b/zerver/views/registration.py @@ -350,6 +350,7 @@ def accounts_register( full_name = form.cleaned_data["full_name"] enable_marketing_emails = form.cleaned_data["enable_marketing_emails"] + email_address_visibility = form.cleaned_data["email_address_visibility"] default_stream_group_names = request.POST.getlist("default_stream_group") default_stream_groups = lookup_default_stream_groups(default_stream_group_names, realm) @@ -464,6 +465,7 @@ def accounts_register( realm_creation=realm_creation, acting_user=None, enable_marketing_emails=enable_marketing_emails, + email_address_visibility=email_address_visibility, ) if realm_creation: