Beispiel #1
0
    def test_delivery_email_presence_for_admins(self) -> None:
        user_profile = self.example_user('iago')
        self.assertTrue(user_profile.is_realm_admin)

        do_set_realm_property(user_profile.realm, "email_address_visibility",
                              Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE)
        result = fetch_initial_state_data(user_profile,
                                          None,
                                          "",
                                          client_gravatar=False,
                                          user_avatar_url_field_optional=False,
                                          realm=user_profile.realm)
        for key, value in result['raw_users'].items():
            self.assertNotIn('delivery_email', value)

        do_set_realm_property(user_profile.realm, "email_address_visibility",
                              Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS)
        result = fetch_initial_state_data(user_profile,
                                          None,
                                          "",
                                          client_gravatar=False,
                                          user_avatar_url_field_optional=False,
                                          realm=user_profile.realm)
        for key, value in result['raw_users'].items():
            self.assertIn('delivery_email', value)
Beispiel #2
0
    def test_confirm_email_change(self) -> None:
        user_profile = self.example_user('hamlet')
        do_set_realm_property(
            user_profile.realm,
            'email_address_visibility',
            Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
        )

        old_email = user_profile.delivery_email
        new_email = '*****@*****.**'
        new_realm = get_realm('zulip')
        self.login('hamlet')
        obj = EmailChangeStatus.objects.create(new_email=new_email,
                                               old_email=old_email,
                                               user_profile=user_profile,
                                               realm=user_profile.realm)
        key = generate_key()
        Confirmation.objects.create(content_object=obj,
                                    date_sent=now(),
                                    confirmation_key=key,
                                    type=Confirmation.EMAIL_CHANGE)
        url = confirmation_url(key, user_profile.realm,
                               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_by_delivery_email(new_email, new_realm)
        self.assertTrue(bool(user_profile))
        obj.refresh_from_db()
        self.assertEqual(obj.status, 1)
Beispiel #3
0
    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 test_unauthorized_email_change_from_email_confirmation_link(self) -> None:
        data = {'email': '*****@*****.**'}
        user_profile = self.example_user('hamlet')
        email = user_profile.email
        self.login(email)
        url = '/json/settings'
        self.assertEqual(len(mail.outbox), 0)
        result = self.client_patch(url, data)
        self.assertEqual(len(mail.outbox), 1)
        self.assert_in_success_response(['Check your email for a confirmation link.'], result)
        email_message = mail.outbox[0]
        self.assertEqual(
            email_message.subject,
            'Verify your new email address'
        )
        body = email_message.body
        self.assertIn('We received a request to change the email', body)

        do_set_realm_property(user_profile.realm, 'email_changes_disabled', True)

        activation_url = [s for s in body.split('\n') if s][4]
        response = self.client_get(activation_url)

        self.assertEqual(response.status_code, 400)
        self.assert_in_response("Email address changes are disabled in this organization.",
                                response)
    def test_unauthorized_email_change_from_email_confirmation_link(
            self) -> None:
        data = {"email": "*****@*****.**"}
        user_profile = self.example_user("hamlet")
        self.login_user(user_profile)
        url = "/json/settings"
        self.assertEqual(len(mail.outbox), 0)
        result = self.client_patch(url, data)
        self.assertEqual(len(mail.outbox), 1)
        self.assert_in_success_response(
            ["Check your email for a confirmation link."], result)
        email_message = mail.outbox[0]
        self.assertEqual(
            email_message.subject,
            "Verify your new email address",
        )
        body = email_message.body
        self.assertIn("We received a request to change the email", body)

        do_set_realm_property(user_profile.realm, "email_changes_disabled",
                              True)

        activation_url = [s for s in body.split("\n") if s][2]
        response = self.client_get(activation_url)

        self.assertEqual(response.status_code, 400)
        self.assert_in_response(
            "Email address changes are disabled in this organization.",
            response)
Beispiel #6
0
    def test_confirm_email_change(self) -> None:
        user_profile = self.example_user("hamlet")
        do_set_realm_property(
            user_profile.realm,
            "email_address_visibility",
            Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
            acting_user=None,
        )

        old_email = user_profile.delivery_email
        new_email = "*****@*****.**"
        new_realm = get_realm("zulip")
        self.login("hamlet")
        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_by_delivery_email(new_email, new_realm)
        self.assertTrue(bool(user_profile))
        obj.refresh_from_db()
        self.assertEqual(obj.status, 1)
Beispiel #7
0
    def test_delivery_email_presence_for_non_admins(self) -> None:
        user_profile = self.example_user("aaron")
        self.assertFalse(user_profile.is_realm_admin)

        do_set_realm_property(
            user_profile.realm,
            "email_address_visibility",
            Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
            acting_user=None,
        )
        result = fetch_initial_state_data(user_profile)

        for key, value in result["raw_users"].items():
            self.assertNotIn("delivery_email", value)

        do_set_realm_property(
            user_profile.realm,
            "email_address_visibility",
            Realm.EMAIL_ADDRESS_VISIBILITY_ADMINS,
            acting_user=None,
        )
        result = fetch_initial_state_data(user_profile)

        for key, value in result["raw_users"].items():
            self.assertNotIn("delivery_email", value)
Beispiel #8
0
    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)

        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)
        key = generate_key()
        Confirmation.objects.create(content_object=obj,
                                    date_sent=now(),
                                    confirmation_key=key,
                                    type=Confirmation.EMAIL_CHANGE)
        url = confirmation_url(key, user_profile.realm.host, 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)
Beispiel #9
0
    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)

        old_email = user_profile.email
        new_email = '*****@*****.**'
        self.login(self.example_email('hamlet'))
        obj = EmailChangeStatus.objects.create(new_email=new_email,
                                               old_email=old_email,
                                               user_profile=user_profile,
                                               realm=user_profile.realm)
        key = generate_key()
        Confirmation.objects.create(content_object=obj,
                                    date_sent=now(),
                                    confirmation_key=key,
                                    type=Confirmation.EMAIL_CHANGE)
        url = confirmation_url(key, user_profile.realm.host, 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, "*****@*****.**")
        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)
Beispiel #10
0
def reset_emails_in_zulip_realm() -> None:
    realm = get_realm("zulip")
    do_set_realm_property(
        realm,
        "email_address_visibility",
        Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE,
        acting_user=None,
    )
Beispiel #11
0
 def test_do_set_realm_name_caching(self) -> None:
     """The main complicated thing about setting realm names is fighting the
     cache, and we start by populating the cache for Hamlet, and we end
     by checking the cache to ensure that the new value is there."""
     realm = get_realm("zulip")
     new_name = "Zed You Elle Eye Pea"
     do_set_realm_property(realm, "name", new_name, acting_user=None)
     self.assertEqual(get_realm(realm.string_id).name, new_name)
     self.assert_user_profile_cache_gets_new_name(self.example_user("hamlet"), new_name)
Beispiel #12
0
 def test_do_set_realm_name_caching(self) -> None:
     """The main complicated thing about setting realm names is fighting the
     cache, and we start by populating the cache for Hamlet, and we end
     by checking the cache to ensure that the new value is there."""
     self.example_user('hamlet')
     realm = get_realm('zulip')
     new_name = u'Zed You Elle Eye Pea'
     do_set_realm_property(realm, 'name', new_name)
     self.assertEqual(get_realm(realm.string_id).name, new_name)
     self.assert_user_profile_cache_gets_new_name(self.example_user('hamlet'), new_name)
Beispiel #13
0
 def test_unauthorized_name_change(self) -> None:
     data = {'full_name': 'Sir Hamlet'}
     user_profile = self.example_user('hamlet')
     email = user_profile.email
     self.login(email)
     do_set_realm_property(user_profile.realm, 'name_changes_disabled', True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(result.status_code, 200)
     # Since the setting fails silently, no message is returned
     self.assert_in_response("", result)
Beispiel #14
0
 def test_unauthorized_name_change(self) -> None:
     data = {'full_name': 'Sir Hamlet'}
     user_profile = self.example_user('hamlet')
     email = user_profile.email
     self.login(email)
     do_set_realm_property(user_profile.realm, 'name_changes_disabled',
                           True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(result.status_code, 200)
     # Since the setting fails silently, no message is returned
     self.assert_in_response("", result)
Beispiel #15
0
 def test_do_set_realm_name_caching(self):
     # type: () -> None
     """The main complicated thing about setting realm names is fighting the
     cache, and we start by populating the cache for Hamlet, and we end
     by checking the cache to ensure that the new value is there."""
     self.example_user('hamlet')
     realm = get_realm('zulip')
     new_name = u'Zed You Elle Eye Pea'
     do_set_realm_property(realm, 'name', new_name)
     self.assertEqual(get_realm(realm.string_id).name, new_name)
     self.assert_user_profile_cache_gets_new_name(
         self.example_user('hamlet'), new_name)
Beispiel #16
0
 def test_unauthorized_email_change(self) -> None:
     data = {'email': '*****@*****.**'}
     user_profile = self.example_user('hamlet')
     email = user_profile.email
     self.login(email)
     do_set_realm_property(user_profile.realm, 'email_changes_disabled', True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(len(mail.outbox), 0)
     self.assertEqual(result.status_code, 400)
     self.assert_in_response("Email address changes are disabled in this organization.",
                             result)
Beispiel #17
0
 def test_update_realm_description_events(self) -> None:
     realm = get_realm('zulip')
     new_description = u'zulip dev group'
     events = []  # type: List[Mapping[str, Any]]
     with tornado_redirected_to_list(events):
         do_set_realm_property(realm, 'description', new_description)
     event = events[0]['event']
     self.assertEqual(event, dict(
         type='realm',
         op='update',
         property='description',
         value=new_description,
     ))
Beispiel #18
0
 def test_update_realm_name_events(self) -> None:
     realm = get_realm('zulip')
     new_name = u'Puliz'
     events = []  # type: List[Mapping[str, Any]]
     with tornado_redirected_to_list(events):
         do_set_realm_property(realm, 'name', new_name)
     event = events[0]['event']
     self.assertEqual(event, dict(
         type='realm',
         op='update',
         property='name',
         value=new_name,
     ))
Beispiel #19
0
 def test_unauthorized_email_change(self) -> None:
     data = {'email': '*****@*****.**'}
     user_profile = self.example_user('hamlet')
     email = user_profile.email
     self.login(email)
     do_set_realm_property(user_profile.realm, 'email_changes_disabled',
                           True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(len(mail.outbox), 0)
     self.assertEqual(result.status_code, 400)
     self.assert_in_response(
         "Email address changes are disabled in this organization.", result)
Beispiel #20
0
 def test_update_realm_description_events(self) -> None:
     realm = get_realm("zulip")
     new_description = "zulip dev group"
     events: List[Mapping[str, Any]] = []
     with self.tornado_redirected_to_list(events, expected_num_events=1):
         do_set_realm_property(realm, "description", new_description, acting_user=None)
     event = events[0]["event"]
     self.assertEqual(
         event,
         dict(
             type="realm",
             op="update",
             property="description",
             value=new_description,
         ),
     )
Beispiel #21
0
 def test_update_realm_name_events(self) -> None:
     realm = get_realm("zulip")
     new_name = "Puliz"
     events: List[Mapping[str, Any]] = []
     with tornado_redirected_to_list(events):
         do_set_realm_property(realm, "name", new_name, acting_user=None)
     event = events[0]["event"]
     self.assertEqual(
         event,
         dict(
             type="realm",
             op="update",
             property="name",
             value=new_name,
         ),
     )
Beispiel #22
0
 def test_unauthorized_name_change(self) -> None:
     data = {"full_name": "Sir Hamlet"}
     user_profile = self.example_user("hamlet")
     self.login_user(user_profile)
     do_set_realm_property(user_profile.realm, "name_changes_disabled", True, acting_user=None)
     url = "/json/settings"
     result = self.client_patch(url, data)
     self.assertEqual(result.status_code, 200)
     # Since the setting fails silently, no message is returned
     self.assert_in_response("", result)
     # Realm admins can change their name even setting is disabled.
     data = {"full_name": "New Iago"}
     self.login("iago")
     url = "/json/settings"
     result = self.client_patch(url, data)
     self.assert_in_success_response(['"full_name":"New Iago"'], result)
Beispiel #23
0
 def test_unauthorized_email_change(self) -> None:
     data = {'email': '*****@*****.**'}
     user_profile = self.example_user('hamlet')
     self.login_user(user_profile)
     do_set_realm_property(user_profile.realm, 'email_changes_disabled', True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(len(mail.outbox), 0)
     self.assertEqual(result.status_code, 400)
     self.assert_in_response("Email address changes are disabled in this organization.",
                             result)
     # Realm admins can change their email address even setting is disabled.
     data = {'email': '*****@*****.**'}
     self.login('iago')
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assert_in_success_response(['Check your email for a confirmation link.'], result)
Beispiel #24
0
 def test_unauthorized_name_change(self) -> None:
     data = {'full_name': 'Sir Hamlet'}
     user_profile = self.example_user('hamlet')
     email = user_profile.email
     self.login(email)
     do_set_realm_property(user_profile.realm, 'name_changes_disabled', True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(result.status_code, 200)
     # Since the setting fails silently, no message is returned
     self.assert_in_response("", result)
     # Realm admins can change their name even setting is disabled.
     data = {'full_name': 'New Iago'}
     self.login(self.example_email("iago"))
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assert_in_success_response(['"full_name":"New Iago"'], result)
Beispiel #25
0
 def test_unauthorized_email_change(self) -> None:
     data = {'email': '*****@*****.**'}
     user_profile = self.example_user('hamlet')
     email = user_profile.email
     self.login(email)
     do_set_realm_property(user_profile.realm, 'email_changes_disabled', True)
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assertEqual(len(mail.outbox), 0)
     self.assertEqual(result.status_code, 400)
     self.assert_in_response("Email address changes are disabled in this organization.",
                             result)
     # Realm admins can change their email address even setting is disabled.
     data = {'email': '*****@*****.**'}
     self.login(self.example_email("iago"))
     url = '/json/settings'
     result = self.client_patch(url, data)
     self.assert_in_success_response(['Check your email for a confirmation link.'], result)
Beispiel #26
0
 def test_unauthorized_email_change(self) -> None:
     data = {"email": "*****@*****.**"}
     user_profile = self.example_user("hamlet")
     self.login_user(user_profile)
     do_set_realm_property(
         user_profile.realm,
         "email_changes_disabled",
         True,
         acting_user=None,
     )
     url = "/json/settings"
     result = self.client_patch(url, data)
     self.assertEqual(len(mail.outbox), 0)
     self.assertEqual(result.status_code, 400)
     self.assert_in_response("Email address changes are disabled in this organization.", result)
     # Realm admins can change their email address even setting is disabled.
     data = {"email": "*****@*****.**"}
     self.login("iago")
     url = "/json/settings"
     result = self.client_patch(url, data)
     self.assert_in_success_response(["Check your email for a confirmation link."], result)
    def test_promote_new_full_members(self) -> None:
        realm = get_realm("zulip")

        cordelia = self.example_user("cordelia")
        hamlet = self.example_user("hamlet")
        cordelia.date_joined = timezone_now() - timedelta(days=11)
        cordelia.save()

        hamlet.date_joined = timezone_now() - timedelta(days=8)
        hamlet.save()

        do_set_realm_property(realm,
                              "waiting_period_threshold",
                              10,
                              acting_user=None)
        full_members_group = UserGroup.objects.get(realm=realm,
                                                   name="@role:fullmembers",
                                                   is_system_group=True)

        self.assertTrue(
            UserGroupMembership.objects.filter(
                user_profile=cordelia, user_group=full_members_group).exists())
        self.assertFalse(
            UserGroupMembership.objects.filter(
                user_profile=hamlet, user_group=full_members_group).exists())

        current_time = timezone_now()
        with mock.patch("zerver.lib.actions.timezone_now",
                        return_value=current_time + timedelta(days=3)):
            promote_new_full_members()

        self.assertTrue(
            UserGroupMembership.objects.filter(
                user_profile=cordelia, user_group=full_members_group).exists())
        self.assertTrue(
            UserGroupMembership.objects.filter(
                user_profile=hamlet, user_group=full_members_group).exists())
Beispiel #28
0
    def test_get_realms_and_streams_for_archiving(self) -> None:
        zulip_realm = get_realm("zulip")
        zulip_realm.message_retention_days = 10
        zulip_realm.save()

        verona = get_stream("Verona", zulip_realm)
        verona.message_retention_days = -1  # Block archiving for this stream
        verona.save()
        denmark = get_stream("Denmark", zulip_realm)
        denmark.message_retention_days = 1
        denmark.save()

        zephyr_realm = get_realm("zephyr")
        zephyr_realm.message_retention_days = -1
        zephyr_realm.save()
        self.make_stream("normal stream", realm=zephyr_realm)

        archiving_blocked_zephyr_stream = self.make_stream("no archiving",
                                                           realm=zephyr_realm)
        archiving_blocked_zephyr_stream.message_retention_days = -1
        archiving_blocked_zephyr_stream.save()

        archiving_enabled_zephyr_stream = self.make_stream("with archiving",
                                                           realm=zephyr_realm)
        archiving_enabled_zephyr_stream.message_retention_days = 1
        archiving_enabled_zephyr_stream.save()

        no_archiving_realm = do_create_realm(string_id="no_archiving",
                                             name="no_archiving")
        do_set_realm_property(no_archiving_realm,
                              "invite_required",
                              False,
                              acting_user=None)
        do_set_realm_property(no_archiving_realm,
                              "message_retention_days",
                              -1,
                              acting_user=None)

        # Realm for testing the edge case where it has a default retention policy,
        # but all streams disable it.
        realm_all_streams_archiving_disabled = do_create_realm(
            string_id="with_archiving", name="with_archiving")
        do_set_realm_property(realm_all_streams_archiving_disabled,
                              "invite_required",
                              False,
                              acting_user=None)
        do_set_realm_property(realm_all_streams_archiving_disabled,
                              "message_retention_days",
                              1,
                              acting_user=None)
        Stream.objects.filter(
            realm=realm_all_streams_archiving_disabled).update(
                message_retention_days=-1)

        # We construct a list representing how the result of get_realms_and_streams_for_archiving should be.
        # One nuisance is that the ordering of the elements in the result structure is not deterministic,
        # so we use a helper to order both structures in a consistent manner. This wouldn't be necessary
        # if python had a true "unordered list" data structure. Set doesn't do the job, because it requires
        # elements to be hashable.
        expected_result = [
            (zulip_realm,
             list(
                 Stream.objects.filter(realm=zulip_realm).exclude(
                     id=verona.id))),
            (zephyr_realm, [archiving_enabled_zephyr_stream]),
            (realm_all_streams_archiving_disabled, []),
        ]
        self.fix_ordering_of_result(expected_result)

        simple_algorithm_result = self.simple_get_realms_and_streams_for_archiving(
        )
        self.fix_ordering_of_result(simple_algorithm_result)

        result = get_realms_and_streams_for_archiving()
        self.fix_ordering_of_result(result)

        self.assert_length(result, len(expected_result))
        self.assertEqual(result, expected_result)

        self.assert_length(result, len(simple_algorithm_result))
        self.assertEqual(result, simple_algorithm_result)
Beispiel #29
0
def update_realm(request, user_profile, name=REQ(validator=check_string, default=None),
                 description=REQ(validator=check_string, default=None),
                 restricted_to_domain=REQ(validator=check_bool, default=None),
                 invite_required=REQ(validator=check_bool, default=None),
                 invite_by_admins_only=REQ(validator=check_bool, default=None),
                 name_changes_disabled=REQ(validator=check_bool, default=None),
                 email_changes_disabled=REQ(validator=check_bool, default=None),
                 inline_image_preview=REQ(validator=check_bool, default=None),
                 inline_url_embed_preview=REQ(validator=check_bool, default=None),
                 create_stream_by_admins_only=REQ(validator=check_bool, default=None),
                 add_emoji_by_admins_only=REQ(validator=check_bool, default=None),
                 allow_message_editing=REQ(validator=check_bool, default=None),
                 message_content_edit_limit_seconds=REQ(converter=to_non_negative_int, default=None),
                 default_language=REQ(validator=check_string, default=None),
                 waiting_period_threshold=REQ(converter=to_non_negative_int, default=None),
                 authentication_methods=REQ(validator=check_dict([]), default=None),
                 message_retention_days=REQ(converter=to_not_negative_int_or_none, default=None)):
    # type: (HttpRequest, UserProfile, Optional[str], Optional[str], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[bool], Optional[int], Optional[str], Optional[int], Optional[dict], Optional[int]) -> HttpResponse
    realm = user_profile.realm

    # Additional validation/error checking beyond types go here, so
    # the entire request can succeed or fail atomically.
    if default_language is not None and default_language not in get_available_language_codes():
        raise JsonableError(_("Invalid language '%s'" % (default_language,)))
    if description is not None and len(description) > 1000:
        return json_error(_("Realm description is too long."))
    if authentication_methods is not None and True not in list(authentication_methods.values()):
        return json_error(_("At least one authentication method must be enabled."),
                          data={"reason": "no authentication"},
                          status=403)

    # The user of `locals()` here is a bit of a code smell, but it's
    # restricted to the elements present in realm.property_types.
    #
    # TODO: It should be possible to deduplicate this function up
    # further by some more advanced usage of the
    # `REQ/has_request_variables` extraction.
    req_vars = {k: v for k, v in list(locals().items()) if k in realm.property_types}
    data = {}  # type: Dict[str, Any]

    for k, v in list(req_vars.items()):
        if v is not None and getattr(realm, k) != v:
            do_set_realm_property(realm, k, v)
            if isinstance(v, Text):
                data[k] = 'updated'
            else:
                data[k] = v

    # The following realm properties do not fit the pattern above
    # authentication_methods is not supported by the do_set_realm_property
    # framework because of its bitfield.
    if authentication_methods is not None and realm.authentication_methods_dict() != authentication_methods:
        do_set_realm_authentication_methods(realm, authentication_methods)
        data['authentication_methods'] = authentication_methods
    # The message_editing settings are coupled to each other, and thus don't fit
    # into the do_set_realm_property framework.
    if (allow_message_editing is not None and realm.allow_message_editing != allow_message_editing) or \
       (message_content_edit_limit_seconds is not None and
            realm.message_content_edit_limit_seconds != message_content_edit_limit_seconds):
        if allow_message_editing is None:
            allow_message_editing = realm.allow_message_editing
        if message_content_edit_limit_seconds is None:
            message_content_edit_limit_seconds = realm.message_content_edit_limit_seconds
        do_set_realm_message_editing(realm, allow_message_editing, message_content_edit_limit_seconds)
        data['allow_message_editing'] = allow_message_editing
        data['message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
    return json_success(data)
def reset_emails_in_zulip_realm() -> None:
    realm = get_realm('zulip')
    do_set_realm_property(realm, 'email_address_visibility',
                          Realm.EMAIL_ADDRESS_VISIBILITY_EVERYONE)
Beispiel #31
0
def update_realm(
    request: HttpRequest,
    user_profile: UserProfile,
    name: Optional[str] = REQ(str_validator=check_capped_string(
        Realm.MAX_REALM_NAME_LENGTH),
                              default=None),
    description: Optional[str] = REQ(str_validator=check_capped_string(
        Realm.MAX_REALM_DESCRIPTION_LENGTH),
                                     default=None),
    emails_restricted_to_domains: Optional[bool] = REQ(
        json_validator=check_bool, default=None),
    disallow_disposable_email_addresses: Optional[bool] = REQ(
        json_validator=check_bool, default=None),
    invite_required: Optional[bool] = REQ(json_validator=check_bool,
                                          default=None),
    invite_to_realm_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.INVITE_TO_REALM_POLICY_TYPES),
                                                default=None),
    name_changes_disabled: Optional[bool] = REQ(json_validator=check_bool,
                                                default=None),
    email_changes_disabled: Optional[bool] = REQ(json_validator=check_bool,
                                                 default=None),
    avatar_changes_disabled: Optional[bool] = REQ(json_validator=check_bool,
                                                  default=None),
    inline_image_preview: Optional[bool] = REQ(json_validator=check_bool,
                                               default=None),
    inline_url_embed_preview: Optional[bool] = REQ(json_validator=check_bool,
                                                   default=None),
    add_custom_emoji_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.COMMON_POLICY_TYPES),
                                                 default=None),
    delete_own_message_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.COMMON_MESSAGE_POLICY_TYPES),
                                                   default=None),
    message_content_delete_limit_seconds_raw: Optional[Union[int, str]] = REQ(
        "message_content_delete_limit_seconds",
        json_validator=check_string_or_int,
        default=None),
    allow_message_editing: Optional[bool] = REQ(json_validator=check_bool,
                                                default=None),
    edit_topic_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.COMMON_MESSAGE_POLICY_TYPES),
                                           default=None),
    mandatory_topics: Optional[bool] = REQ(json_validator=check_bool,
                                           default=None),
    message_content_edit_limit_seconds: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    allow_edit_history: Optional[bool] = REQ(json_validator=check_bool,
                                             default=None),
    default_language: Optional[str] = REQ(default=None),
    waiting_period_threshold: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    authentication_methods: Optional[Dict[str, Any]] = REQ(
        json_validator=check_dict([]), default=None),
    notifications_stream_id: Optional[int] = REQ(json_validator=check_int,
                                                 default=None),
    signup_notifications_stream_id: Optional[int] = REQ(
        json_validator=check_int, default=None),
    message_retention_days_raw: Optional[Union[int, str]] = REQ(
        "message_retention_days",
        json_validator=check_string_or_int,
        default=None),
    send_welcome_emails: Optional[bool] = REQ(json_validator=check_bool,
                                              default=None),
    digest_emails_enabled: Optional[bool] = REQ(json_validator=check_bool,
                                                default=None),
    message_content_allowed_in_email_notifications: Optional[bool] = REQ(
        json_validator=check_bool, default=None),
    bot_creation_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.BOT_CREATION_POLICY_TYPES),
                                             default=None),
    create_public_stream_policy: Optional[int] = REQ(
        json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None),
    create_private_stream_policy: Optional[int] = REQ(
        json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None),
    create_web_public_stream_policy: Optional[int] = REQ(
        json_validator=check_int_in(
            Realm.CREATE_WEB_PUBLIC_STREAM_POLICY_TYPES),
        default=None),
    invite_to_stream_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.COMMON_POLICY_TYPES),
                                                 default=None),
    move_messages_between_streams_policy: Optional[int] = REQ(
        json_validator=check_int_in(Realm.COMMON_POLICY_TYPES), default=None),
    user_group_edit_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.COMMON_POLICY_TYPES),
                                                default=None),
    private_message_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.PRIVATE_MESSAGE_POLICY_TYPES),
                                                default=None),
    wildcard_mention_policy: Optional[int] = REQ(json_validator=check_int_in(
        Realm.WILDCARD_MENTION_POLICY_TYPES),
                                                 default=None),
    email_address_visibility: Optional[int] = REQ(json_validator=check_int_in(
        Realm.EMAIL_ADDRESS_VISIBILITY_TYPES),
                                                  default=None),
    video_chat_provider: Optional[int] = REQ(json_validator=check_int,
                                             default=None),
    giphy_rating: Optional[int] = REQ(json_validator=check_int, default=None),
    default_code_block_language: Optional[str] = REQ(default=None),
    digest_weekday: Optional[int] = REQ(json_validator=check_int_in(
        Realm.DIGEST_WEEKDAY_VALUES),
                                        default=None),
    string_id: Optional[str] = REQ(
        str_validator=check_capped_string(Realm.MAX_REALM_SUBDOMAIN_LENGTH),
        default=None,
    ),
    enable_spectator_access: Optional[bool] = REQ(json_validator=check_bool,
                                                  default=None),
) -> HttpResponse:
    realm = user_profile.realm

    # Additional validation/error checking beyond types go here, so
    # the entire request can succeed or fail atomically.
    if default_language is not None and default_language not in get_available_language_codes(
    ):
        raise JsonableError(
            _("Invalid language '{}'").format(default_language))
    if authentication_methods is not None:
        if not user_profile.is_realm_owner:
            raise OrganizationOwnerRequired()
        if True not in list(authentication_methods.values()):
            raise JsonableError(
                _("At least one authentication method must be enabled."))
    if video_chat_provider is not None and video_chat_provider not in {
            p["id"]
            for p in Realm.VIDEO_CHAT_PROVIDERS.values()
    }:
        raise JsonableError(
            _("Invalid video_chat_provider {}").format(video_chat_provider))
    if giphy_rating is not None and giphy_rating not in {
            p["id"]
            for p in Realm.GIPHY_RATING_OPTIONS.values()
    }:
        raise JsonableError(_("Invalid giphy_rating {}").format(giphy_rating))

    message_retention_days: Optional[int] = None
    if message_retention_days_raw is not None:
        if not user_profile.is_realm_owner:
            raise OrganizationOwnerRequired()
        realm.ensure_not_on_limited_plan()
        message_retention_days = parse_message_retention_days(
            message_retention_days_raw,
            Realm.MESSAGE_RETENTION_SPECIAL_VALUES_MAP)

    if invite_to_realm_policy is not None and not user_profile.is_realm_owner:
        raise OrganizationOwnerRequired()

    data: Dict[str, Any] = {}

    message_content_delete_limit_seconds: Optional[int] = None
    if message_content_delete_limit_seconds_raw is not None:
        message_content_delete_limit_seconds = parse_message_content_delete_limit(
            message_content_delete_limit_seconds_raw,
            Realm.MESSAGE_CONTENT_DELETE_LIMIT_SPECIAL_VALUES_MAP,
        )
        do_set_realm_property(
            realm,
            "message_content_delete_limit_seconds",
            message_content_delete_limit_seconds,
            acting_user=user_profile,
        )
        data[
            "message_content_delete_limit_seconds"] = message_content_delete_limit_seconds

    # The user of `locals()` here is a bit of a code smell, but it's
    # restricted to the elements present in realm.property_types.
    #
    # TODO: It should be possible to deduplicate this function up
    # further by some more advanced usage of the
    # `REQ/has_request_variables` extraction.
    req_vars = {
        k: v
        for k, v in list(locals().items()) if k in realm.property_types
    }

    for k, v in list(req_vars.items()):
        if v is not None and getattr(realm, k) != v:
            do_set_realm_property(realm, k, v, acting_user=user_profile)
            if isinstance(v, str):
                data[k] = "updated"
            else:
                data[k] = v

    # The following realm properties do not fit the pattern above
    # authentication_methods is not supported by the do_set_realm_property
    # framework because of its bitfield.
    if authentication_methods is not None and (
            realm.authentication_methods_dict() != authentication_methods):
        do_set_realm_authentication_methods(realm,
                                            authentication_methods,
                                            acting_user=user_profile)
        data["authentication_methods"] = authentication_methods
    # The message_editing settings are coupled to each other, and thus don't fit
    # into the do_set_realm_property framework.
    if ((allow_message_editing is not None
         and realm.allow_message_editing != allow_message_editing)
            or (message_content_edit_limit_seconds is not None
                and realm.message_content_edit_limit_seconds !=
                message_content_edit_limit_seconds)
            or (edit_topic_policy is not None
                and realm.edit_topic_policy != edit_topic_policy)):
        if allow_message_editing is None:
            allow_message_editing = realm.allow_message_editing
        if message_content_edit_limit_seconds is None:
            message_content_edit_limit_seconds = realm.message_content_edit_limit_seconds
        if edit_topic_policy is None:
            edit_topic_policy = realm.edit_topic_policy
        do_set_realm_message_editing(
            realm,
            allow_message_editing,
            message_content_edit_limit_seconds,
            edit_topic_policy,
            acting_user=user_profile,
        )
        data["allow_message_editing"] = allow_message_editing
        data[
            "message_content_edit_limit_seconds"] = message_content_edit_limit_seconds
        data["edit_topic_policy"] = edit_topic_policy

    # Realm.notifications_stream and Realm.signup_notifications_stream are not boolean,
    # str or integer field, and thus doesn't fit into the do_set_realm_property framework.
    if notifications_stream_id is not None:
        if realm.notifications_stream is None or (realm.notifications_stream.id
                                                  != notifications_stream_id):
            new_notifications_stream = None
            if notifications_stream_id >= 0:
                (new_notifications_stream,
                 sub) = access_stream_by_id(user_profile,
                                            notifications_stream_id)
            do_set_realm_notifications_stream(realm,
                                              new_notifications_stream,
                                              notifications_stream_id,
                                              acting_user=user_profile)
            data["notifications_stream_id"] = notifications_stream_id

    if signup_notifications_stream_id is not None:
        if realm.signup_notifications_stream is None or (
                realm.signup_notifications_stream.id !=
                signup_notifications_stream_id):
            new_signup_notifications_stream = None
            if signup_notifications_stream_id >= 0:
                (new_signup_notifications_stream,
                 sub) = access_stream_by_id(user_profile,
                                            signup_notifications_stream_id)
            do_set_realm_signup_notifications_stream(
                realm,
                new_signup_notifications_stream,
                signup_notifications_stream_id,
                acting_user=user_profile,
            )
            data[
                "signup_notifications_stream_id"] = signup_notifications_stream_id

    if default_code_block_language is not None:
        # Migrate '', used in the API to encode the default/None behavior of this feature.
        if default_code_block_language == "":
            data["default_code_block_language"] = None
        else:
            data["default_code_block_language"] = default_code_block_language

    if string_id is not None:
        if not user_profile.is_realm_owner:
            raise OrganizationOwnerRequired()

        if realm.demo_organization_scheduled_deletion_date is None:
            raise JsonableError(_("Must be a demo organization."))

        try:
            check_subdomain(string_id)
        except ValidationError as err:
            raise JsonableError(str(err.message))

        do_change_realm_subdomain(realm, string_id, acting_user=user_profile)
        data["realm_uri"] = realm.uri

    return json_success(data)
Beispiel #32
0
def update_realm(
        request: HttpRequest, user_profile: UserProfile,
        name: Optional[str]=REQ(validator=check_string, default=None),
        description: Optional[str]=REQ(validator=check_string, default=None),
        emails_restricted_to_domains: Optional[bool]=REQ(validator=check_bool, default=None),
        disallow_disposable_email_addresses: Optional[bool]=REQ(validator=check_bool, default=None),
        invite_required: Optional[bool]=REQ(validator=check_bool, default=None),
        invite_by_admins_only: Optional[bool]=REQ(validator=check_bool, default=None),
        name_changes_disabled: Optional[bool]=REQ(validator=check_bool, default=None),
        email_changes_disabled: Optional[bool]=REQ(validator=check_bool, default=None),
        inline_image_preview: Optional[bool]=REQ(validator=check_bool, default=None),
        inline_url_embed_preview: Optional[bool]=REQ(validator=check_bool, default=None),
        create_stream_by_admins_only: Optional[bool]=REQ(validator=check_bool, default=None),
        add_emoji_by_admins_only: Optional[bool]=REQ(validator=check_bool, default=None),
        allow_message_deleting: Optional[bool]=REQ(validator=check_bool, default=None),
        message_content_delete_limit_seconds: Optional[int]=REQ(converter=to_non_negative_int, default=None),
        allow_message_editing: Optional[bool]=REQ(validator=check_bool, default=None),
        allow_community_topic_editing: Optional[bool]=REQ(validator=check_bool, default=None),
        mandatory_topics: Optional[bool]=REQ(validator=check_bool, default=None),
        message_content_edit_limit_seconds: Optional[int]=REQ(converter=to_non_negative_int, default=None),
        allow_edit_history: Optional[bool]=REQ(validator=check_bool, default=None),
        default_language: Optional[str]=REQ(validator=check_string, default=None),
        waiting_period_threshold: Optional[int]=REQ(converter=to_non_negative_int, default=None),
        authentication_methods: Optional[Dict[Any, Any]]=REQ(validator=check_dict([]), default=None),
        notifications_stream_id: Optional[int]=REQ(validator=check_int, default=None),
        signup_notifications_stream_id: Optional[int]=REQ(validator=check_int, default=None),
        message_retention_days: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
        send_welcome_emails: Optional[bool]=REQ(validator=check_bool, default=None),
        message_content_allowed_in_email_notifications:
        Optional[bool]=REQ(validator=check_bool, default=None),
        bot_creation_policy: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
        email_address_visibility: Optional[int]=REQ(converter=to_not_negative_int_or_none, default=None),
        default_twenty_four_hour_time: Optional[bool]=REQ(validator=check_bool, default=None),
        video_chat_provider: Optional[str]=REQ(validator=check_string, default=None),
        google_hangouts_domain: Optional[str]=REQ(validator=check_string, default=None),
        zoom_user_id: Optional[str]=REQ(validator=check_string, default=None),
        zoom_api_key: Optional[str]=REQ(validator=check_string, default=None),
        zoom_api_secret: Optional[str]=REQ(validator=check_string, default=None),
) -> HttpResponse:
    realm = user_profile.realm

    # Additional validation/error checking beyond types go here, so
    # the entire request can succeed or fail atomically.
    if default_language is not None and default_language not in get_available_language_codes():
        raise JsonableError(_("Invalid language '%s'" % (default_language,)))
    if description is not None and len(description) > 1000:
        return json_error(_("Organization description is too long."))
    if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH:
        return json_error(_("Organization name is too long."))
    if authentication_methods is not None and True not in list(authentication_methods.values()):
        return json_error(_("At least one authentication method must be enabled."))
    if video_chat_provider == "Google Hangouts":
        try:
            validate_domain(google_hangouts_domain)
        except ValidationError as e:
            return json_error(_('Invalid domain: {}').format(e.messages[0]))
    if video_chat_provider == "Zoom":
        if not zoom_user_id:
            return json_error(_('Invalid user ID: user ID cannot be empty'))
        if not zoom_api_key:
            return json_error(_('Invalid API key: API key cannot be empty'))
        if not zoom_api_secret:
            return json_error(_('Invalid API secret: API secret cannot be empty'))
        # Technically, we could call some other API endpoint that
        # doesn't create a video call link, but this is a nicer
        # end-to-end test, since it verifies that the Zoom API user's
        # scopes includes the ability to create video calls, which is
        # the only capabiility we use.
        if not request_zoom_video_call_url(zoom_user_id, zoom_api_key, zoom_api_secret):
            return json_error(_('Invalid credentials for the %(third_party_service)s API.') % dict(
                third_party_service="Zoom"))

    # Additional validation of enum-style values
    if bot_creation_policy is not None and bot_creation_policy not in Realm.BOT_CREATION_POLICY_TYPES:
        return json_error(_("Invalid bot creation policy"))
    if email_address_visibility is not None and \
            email_address_visibility not in Realm.EMAIL_ADDRESS_VISIBILITY_TYPES:
        return json_error(_("Invalid email address visibility policy"))

    # The user of `locals()` here is a bit of a code smell, but it's
    # restricted to the elements present in realm.property_types.
    #
    # TODO: It should be possible to deduplicate this function up
    # further by some more advanced usage of the
    # `REQ/has_request_variables` extraction.
    req_vars = {k: v for k, v in list(locals().items()) if k in realm.property_types}
    data = {}  # type: Dict[str, Any]

    for k, v in list(req_vars.items()):
        if v is not None and getattr(realm, k) != v:
            do_set_realm_property(realm, k, v)
            if isinstance(v, str):
                data[k] = 'updated'
            else:
                data[k] = v

    # The following realm properties do not fit the pattern above
    # authentication_methods is not supported by the do_set_realm_property
    # framework because of its bitfield.
    if authentication_methods is not None and (realm.authentication_methods_dict() !=
                                               authentication_methods):
        do_set_realm_authentication_methods(realm, authentication_methods)
        data['authentication_methods'] = authentication_methods
    # The message_editing settings are coupled to each other, and thus don't fit
    # into the do_set_realm_property framework.
    if ((allow_message_editing is not None and realm.allow_message_editing != allow_message_editing) or
        (message_content_edit_limit_seconds is not None and
            realm.message_content_edit_limit_seconds != message_content_edit_limit_seconds) or
        (allow_community_topic_editing is not None and
            realm.allow_community_topic_editing != allow_community_topic_editing)):
        if allow_message_editing is None:
            allow_message_editing = realm.allow_message_editing
        if message_content_edit_limit_seconds is None:
            message_content_edit_limit_seconds = realm.message_content_edit_limit_seconds
        if allow_community_topic_editing is None:
            allow_community_topic_editing = realm.allow_community_topic_editing
        do_set_realm_message_editing(realm, allow_message_editing,
                                     message_content_edit_limit_seconds,
                                     allow_community_topic_editing)
        data['allow_message_editing'] = allow_message_editing
        data['message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
        data['allow_community_topic_editing'] = allow_community_topic_editing

    if (message_content_delete_limit_seconds is not None and
            realm.message_content_delete_limit_seconds != message_content_delete_limit_seconds):
        do_set_realm_message_deleting(realm, message_content_delete_limit_seconds)
        data['message_content_delete_limit_seconds'] = message_content_delete_limit_seconds
    # Realm.notifications_stream and Realm.signup_notifications_stream are not boolean,
    # str or integer field, and thus doesn't fit into the do_set_realm_property framework.
    if notifications_stream_id is not None:
        if realm.notifications_stream is None or (realm.notifications_stream.id !=
                                                  notifications_stream_id):
            new_notifications_stream = None
            if notifications_stream_id >= 0:
                (new_notifications_stream, recipient, sub) = access_stream_by_id(
                    user_profile, notifications_stream_id)
            do_set_realm_notifications_stream(realm, new_notifications_stream,
                                              notifications_stream_id)
            data['notifications_stream_id'] = notifications_stream_id

    if signup_notifications_stream_id is not None:
        if realm.signup_notifications_stream is None or (realm.signup_notifications_stream.id !=
                                                         signup_notifications_stream_id):
            new_signup_notifications_stream = None
            if signup_notifications_stream_id >= 0:
                (new_signup_notifications_stream, recipient, sub) = access_stream_by_id(
                    user_profile, signup_notifications_stream_id)
            do_set_realm_signup_notifications_stream(realm, new_signup_notifications_stream,
                                                     signup_notifications_stream_id)
            data['signup_notifications_stream_id'] = signup_notifications_stream_id

    return json_success(data)
Beispiel #33
0
def update_realm(
    request: HttpRequest,
    user_profile: UserProfile,
    name: Optional[str] = REQ(validator=check_string, default=None),
    description: Optional[str] = REQ(validator=check_string, default=None),
    emails_restricted_to_domains: Optional[bool] = REQ(validator=check_bool,
                                                       default=None),
    disallow_disposable_email_addresses: Optional[bool] = REQ(
        validator=check_bool, default=None),
    invite_required: Optional[bool] = REQ(validator=check_bool, default=None),
    invite_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    name_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    email_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                 default=None),
    avatar_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                  default=None),
    inline_image_preview: Optional[bool] = REQ(validator=check_bool,
                                               default=None),
    inline_url_embed_preview: Optional[bool] = REQ(validator=check_bool,
                                                   default=None),
    add_emoji_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                   default=None),
    allow_message_deleting: Optional[bool] = REQ(validator=check_bool,
                                                 default=None),
    message_content_delete_limit_seconds: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    allow_message_editing: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    allow_community_topic_editing: Optional[bool] = REQ(validator=check_bool,
                                                        default=None),
    mandatory_topics: Optional[bool] = REQ(validator=check_bool, default=None),
    message_content_edit_limit_seconds: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    allow_edit_history: Optional[bool] = REQ(validator=check_bool,
                                             default=None),
    default_language: Optional[str] = REQ(validator=check_string,
                                          default=None),
    waiting_period_threshold: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    authentication_methods: Optional[Dict[Any,
                                          Any]] = REQ(validator=check_dict([]),
                                                      default=None),
    notifications_stream_id: Optional[int] = REQ(validator=check_int,
                                                 default=None),
    signup_notifications_stream_id: Optional[int] = REQ(validator=check_int,
                                                        default=None),
    message_retention_days: Optional[int] = REQ(
        converter=to_not_negative_int_or_none, default=None),
    send_welcome_emails: Optional[bool] = REQ(validator=check_bool,
                                              default=None),
    digest_emails_enabled: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    message_content_allowed_in_email_notifications: Optional[bool] = REQ(
        validator=check_bool, default=None),
    bot_creation_policy: Optional[int] = REQ(
        converter=to_not_negative_int_or_none, default=None),
    create_stream_policy: Optional[int] = REQ(validator=check_int,
                                              default=None),
    invite_to_stream_policy: Optional[int] = REQ(validator=check_int,
                                                 default=None),
    user_group_edit_policy: Optional[int] = REQ(validator=check_int,
                                                default=None),
    email_address_visibility: Optional[int] = REQ(
        converter=to_not_negative_int_or_none, default=None),
    default_twenty_four_hour_time: Optional[bool] = REQ(validator=check_bool,
                                                        default=None),
    video_chat_provider: Optional[int] = REQ(validator=check_int,
                                             default=None),
    google_hangouts_domain: Optional[str] = REQ(validator=check_string,
                                                default=None),
    zoom_user_id: Optional[str] = REQ(validator=check_string, default=None),
    zoom_api_key: Optional[str] = REQ(validator=check_string, default=None),
    zoom_api_secret: Optional[str] = REQ(validator=check_string, default=None),
    digest_weekday: Optional[int] = REQ(validator=check_int, default=None),
) -> HttpResponse:
    realm = user_profile.realm

    # Additional validation/error checking beyond types go here, so
    # the entire request can succeed or fail atomically.
    if default_language is not None and default_language not in get_available_language_codes(
    ):
        raise JsonableError(_("Invalid language '%s'") % (default_language, ))
    if description is not None and len(description) > 1000:
        return json_error(_("Organization description is too long."))
    if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH:
        return json_error(_("Organization name is too long."))
    if authentication_methods is not None and True not in list(
            authentication_methods.values()):
        return json_error(
            _("At least one authentication method must be enabled."))
    if (video_chat_provider is not None and video_chat_provider not in set(
            p['id'] for p in Realm.VIDEO_CHAT_PROVIDERS.values())):
        return json_error(
            _("Invalid video chat provider {}").format(video_chat_provider))
    if video_chat_provider == Realm.VIDEO_CHAT_PROVIDERS['google_hangouts'][
            'id']:
        try:
            validate_domain(google_hangouts_domain)
        except ValidationError as e:
            return json_error(_('Invalid domain: {}').format(e.messages[0]))
    if video_chat_provider == Realm.VIDEO_CHAT_PROVIDERS['zoom']['id']:
        if not zoom_api_secret:
            # Use the saved Zoom API secret if a new value isn't being sent
            zoom_api_secret = user_profile.realm.zoom_api_secret
        if not zoom_user_id:
            return json_error(_('User ID cannot be empty'))
        if not zoom_api_key:
            return json_error(_('API key cannot be empty'))
        if not zoom_api_secret:
            return json_error(_('API secret cannot be empty'))
        # If any of the Zoom settings have changed, validate the Zoom credentials.
        #
        # Technically, we could call some other API endpoint that
        # doesn't create a video call link, but this is a nicer
        # end-to-end test, since it verifies that the Zoom API user's
        # scopes includes the ability to create video calls, which is
        # the only capabiility we use.
        if ((zoom_user_id != realm.zoom_user_id
             or zoom_api_key != realm.zoom_api_key
             or zoom_api_secret != realm.zoom_api_secret)
                and not request_zoom_video_call_url(zoom_user_id, zoom_api_key,
                                                    zoom_api_secret)):
            return json_error(
                _('Invalid credentials for the %(third_party_service)s API.') %
                dict(third_party_service="Zoom"))

    # Additional validation of enum-style values
    # TODO: Ideally, these checks would be automated rather than being manually maintained.
    if bot_creation_policy is not None and bot_creation_policy not in Realm.BOT_CREATION_POLICY_TYPES:
        return json_error(
            _("Invalid %(field_name)s") %
            dict(field_name="bot_creation_policy"))
    if email_address_visibility is not None and \
            email_address_visibility not in Realm.EMAIL_ADDRESS_VISIBILITY_TYPES:
        return json_error(
            _("Invalid %(field_name)s") %
            dict(field_name="email_address_visibility"))
    if create_stream_policy is not None and \
            create_stream_policy not in Realm.CREATE_STREAM_POLICY_TYPES:
        return json_error(
            _("Invalid %(field_name)s") %
            dict(field_name="create_stream_policy"))
    if invite_to_stream_policy is not None and \
            invite_to_stream_policy not in Realm.INVITE_TO_STREAM_POLICY_TYPES:
        return json_error(
            _("Invalid %(field_name)s") %
            dict(field_name="invite_to_stream_policy"))
    if user_group_edit_policy is not None and \
            user_group_edit_policy not in Realm.USER_GROUP_EDIT_POLICY_TYPES:
        return json_error(
            _("Invalid %(field_name)s") %
            dict(field_name="user_group_edit_policy"))

    # The user of `locals()` here is a bit of a code smell, but it's
    # restricted to the elements present in realm.property_types.
    #
    # TODO: It should be possible to deduplicate this function up
    # further by some more advanced usage of the
    # `REQ/has_request_variables` extraction.
    req_vars = {
        k: v
        for k, v in list(locals().items()) if k in realm.property_types
    }
    data = {}  # type: Dict[str, Any]

    for k, v in list(req_vars.items()):
        if v is not None and getattr(realm, k) != v:
            do_set_realm_property(realm, k, v)
            if isinstance(v, str):
                data[k] = 'updated'
            else:
                data[k] = v

    # The following realm properties do not fit the pattern above
    # authentication_methods is not supported by the do_set_realm_property
    # framework because of its bitfield.
    if authentication_methods is not None and (
            realm.authentication_methods_dict() != authentication_methods):
        do_set_realm_authentication_methods(realm, authentication_methods)
        data['authentication_methods'] = authentication_methods
    # The message_editing settings are coupled to each other, and thus don't fit
    # into the do_set_realm_property framework.
    if ((allow_message_editing is not None
         and realm.allow_message_editing != allow_message_editing)
            or (message_content_edit_limit_seconds is not None
                and realm.message_content_edit_limit_seconds !=
                message_content_edit_limit_seconds)
            or (allow_community_topic_editing is not None
                and realm.allow_community_topic_editing !=
                allow_community_topic_editing)):
        if allow_message_editing is None:
            allow_message_editing = realm.allow_message_editing
        if message_content_edit_limit_seconds is None:
            message_content_edit_limit_seconds = realm.message_content_edit_limit_seconds
        if allow_community_topic_editing is None:
            allow_community_topic_editing = realm.allow_community_topic_editing
        do_set_realm_message_editing(realm, allow_message_editing,
                                     message_content_edit_limit_seconds,
                                     allow_community_topic_editing)
        data['allow_message_editing'] = allow_message_editing
        data[
            'message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
        data['allow_community_topic_editing'] = allow_community_topic_editing

    if (message_content_delete_limit_seconds is not None
            and realm.message_content_delete_limit_seconds !=
            message_content_delete_limit_seconds):
        do_set_realm_message_deleting(realm,
                                      message_content_delete_limit_seconds)
        data[
            'message_content_delete_limit_seconds'] = message_content_delete_limit_seconds
    # Realm.notifications_stream and Realm.signup_notifications_stream are not boolean,
    # str or integer field, and thus doesn't fit into the do_set_realm_property framework.
    if notifications_stream_id is not None:
        if realm.notifications_stream is None or (realm.notifications_stream.id
                                                  != notifications_stream_id):
            new_notifications_stream = None
            if notifications_stream_id >= 0:
                (new_notifications_stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            notifications_stream_id)
            do_set_realm_notifications_stream(realm, new_notifications_stream,
                                              notifications_stream_id)
            data['notifications_stream_id'] = notifications_stream_id

    if signup_notifications_stream_id is not None:
        if realm.signup_notifications_stream is None or (
                realm.signup_notifications_stream.id !=
                signup_notifications_stream_id):
            new_signup_notifications_stream = None
            if signup_notifications_stream_id >= 0:
                (new_signup_notifications_stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            signup_notifications_stream_id)
            do_set_realm_signup_notifications_stream(
                realm, new_signup_notifications_stream,
                signup_notifications_stream_id)
            data[
                'signup_notifications_stream_id'] = signup_notifications_stream_id

    return json_success(data)
Beispiel #34
0
    def test_search(self) -> None:
        reset_emails_in_zulip_realm()

        def assert_user_details_in_html_response(html_response: HttpResponse,
                                                 full_name: str, email: str,
                                                 role: str) -> None:
            self.assert_in_success_response(
                [
                    '<span class="label">user</span>\n',
                    f"<h3>{full_name}</h3>",
                    f"<b>Email</b>: {email}",
                    "<b>Is active</b>: True<br />",
                    f"<b>Role</b>: {role}<br />",
                ],
                html_response,
            )

        def check_hamlet_user_query_result(result: HttpResponse) -> None:
            assert_user_details_in_html_response(result, "King Hamlet",
                                                 self.example_email("hamlet"),
                                                 "Member")
            self.assert_in_success_response(
                [
                    f"<b>Admins</b>: {self.example_email('iago')}\n",
                    f"<b>Owners</b>: {self.example_email('desdemona')}\n",
                    'class="copy-button" data-copytext="{}">'.format(
                        self.example_email("iago")),
                    'class="copy-button" data-copytext="{}">'.format(
                        self.example_email("desdemona")),
                ],
                result,
            )

        def check_othello_user_query_result(result: HttpResponse) -> None:
            assert_user_details_in_html_response(
                result, "Othello, the Moor of Venice",
                self.example_email("othello"), "Member")

        def check_polonius_user_query_result(result: HttpResponse) -> None:
            assert_user_details_in_html_response(
                result, "Polonius", self.example_email("polonius"), "Guest")

        def check_zulip_realm_query_result(result: HttpResponse) -> None:
            zulip_realm = get_realm("zulip")
            first_human_user = zulip_realm.get_first_human_user()
            assert first_human_user is not None
            self.assert_in_success_response(
                [
                    f"<b>First human user</b>: {first_human_user.delivery_email}\n",
                    f'<input type="hidden" name="realm_id" value="{zulip_realm.id}"',
                    "Zulip Dev</h3>",
                    '<option value="1" selected>Self hosted</option>',
                    '<option value="2" >Limited</option>',
                    'input type="number" name="discount" value="None"',
                    '<option value="active" selected>Active</option>',
                    '<option value="deactivated" >Deactivated</option>',
                    f'<option value="{zulip_realm.org_type}" selected>',
                    'scrub-realm-button">',
                    'data-string-id="zulip"',
                ],
                result,
            )

        def check_lear_realm_query_result(result: HttpResponse) -> None:
            lear_realm = get_realm("lear")
            self.assert_in_success_response(
                [
                    f'<input type="hidden" name="realm_id" value="{lear_realm.id}"',
                    "Lear &amp; Co.</h3>",
                    '<option value="1" selected>Self hosted</option>',
                    '<option value="2" >Limited</option>',
                    'input type="number" name="discount" value="None"',
                    '<option value="active" selected>Active</option>',
                    '<option value="deactivated" >Deactivated</option>',
                    'scrub-realm-button">',
                    'data-string-id="lear"',
                    "<b>Name</b>: Zulip Standard",
                    "<b>Status</b>: Active",
                    "<b>Billing schedule</b>: Annual",
                    "<b>Licenses</b>: 2/10 (Manual)",
                    "<b>Price per license</b>: $80.0",
                    "<b>Next invoice date</b>: 02 January 2017",
                    '<option value="send_invoice" selected>',
                    '<option value="charge_automatically" >',
                ],
                result,
            )

        def check_preregistration_user_query_result(
                result: HttpResponse,
                email: str,
                invite: bool = False) -> None:
            self.assert_in_success_response(
                [
                    '<span class="label">preregistration user</span>\n',
                    f"<b>Email</b>: {email}",
                ],
                result,
            )
            if invite:
                self.assert_in_success_response(
                    ['<span class="label">invite</span>'], result)
                self.assert_in_success_response(
                    [
                        "<b>Expires in</b>: 1\xa0week, 3\xa0days",
                        "<b>Status</b>: Link has never been clicked",
                    ],
                    result,
                )
                self.assert_in_success_response([], result)
            else:
                self.assert_not_in_success_response(
                    ['<span class="label">invite</span>'], result)
                self.assert_in_success_response(
                    [
                        "<b>Expires in</b>: 1\xa0day",
                        "<b>Status</b>: Link has never been clicked",
                    ],
                    result,
                )

        def check_realm_creation_query_result(result: HttpResponse,
                                              email: str) -> None:
            self.assert_in_success_response(
                [
                    '<span class="label">preregistration user</span>\n',
                    '<span class="label">realm creation</span>\n',
                    "<b>Link</b>: http://testserver/accounts/do_confirm/",
                    "<b>Expires in</b>: 1\xa0day",
                ],
                result,
            )

        def check_multiuse_invite_link_query_result(
                result: HttpResponse) -> None:
            self.assert_in_success_response(
                [
                    '<span class="label">multiuse invite</span>\n',
                    "<b>Link</b>: http://zulip.testserver/join/",
                    "<b>Expires in</b>: 1\xa0week, 3\xa0days",
                ],
                result,
            )

        def check_realm_reactivation_link_query_result(
                result: HttpResponse) -> None:
            self.assert_in_success_response(
                [
                    '<span class="label">realm reactivation</span>\n',
                    "<b>Link</b>: http://zulip.testserver/reactivate/",
                    "<b>Expires in</b>: 1\xa0day",
                ],
                result,
            )

        self.login("cordelia")

        result = self.client_get("/activity/support")
        self.assertEqual(result.status_code, 302)
        self.assertEqual(result["Location"], "/login/")

        self.login("iago")

        do_set_realm_property(
            get_realm("zulip"),
            "email_address_visibility",
            Realm.EMAIL_ADDRESS_VISIBILITY_NOBODY,
            acting_user=None,
        )

        customer = Customer.objects.create(realm=get_realm("lear"),
                                           stripe_customer_id="cus_123")
        now = datetime(2016, 1, 2, tzinfo=timezone.utc)
        plan = CustomerPlan.objects.create(
            customer=customer,
            billing_cycle_anchor=now,
            billing_schedule=CustomerPlan.ANNUAL,
            tier=CustomerPlan.STANDARD,
            price_per_license=8000,
            next_invoice_date=add_months(now, 12),
        )
        LicenseLedger.objects.create(
            licenses=10,
            licenses_at_next_renewal=10,
            event_time=timezone_now(),
            is_renewal=True,
            plan=plan,
        )

        result = self.client_get("/activity/support")
        self.assert_in_success_response(
            ['<input type="text" name="q" class="input-xxlarge search-query"'],
            result)

        result = self.client_get("/activity/support",
                                 {"q": self.example_email("hamlet")})
        check_hamlet_user_query_result(result)
        check_zulip_realm_query_result(result)

        result = self.client_get("/activity/support",
                                 {"q": self.example_email("polonius")})
        check_polonius_user_query_result(result)
        check_zulip_realm_query_result(result)

        result = self.client_get("/activity/support", {"q": "lear"})
        check_lear_realm_query_result(result)

        result = self.client_get("/activity/support",
                                 {"q": "http://lear.testserver"})
        check_lear_realm_query_result(result)

        with self.settings(REALM_HOSTS={"zulip": "localhost"}):
            result = self.client_get("/activity/support",
                                     {"q": "http://localhost"})
            check_zulip_realm_query_result(result)

        result = self.client_get("/activity/support",
                                 {"q": "[email protected], lear"})
        check_hamlet_user_query_result(result)
        check_zulip_realm_query_result(result)
        check_lear_realm_query_result(result)

        result = self.client_get("/activity/support",
                                 {"q": "King hamlet,lear"})
        check_hamlet_user_query_result(result)
        check_zulip_realm_query_result(result)
        check_lear_realm_query_result(result)

        result = self.client_get("/activity/support",
                                 {"q": "Othello, the Moor of Venice"})
        check_othello_user_query_result(result)
        check_zulip_realm_query_result(result)

        result = self.client_get("/activity/support",
                                 {"q": "lear, Hamlet <*****@*****.**>"})
        check_hamlet_user_query_result(result)
        check_zulip_realm_query_result(result)
        check_lear_realm_query_result(result)

        with mock.patch(
                "analytics.views.support.timezone_now",
                return_value=timezone_now() - timedelta(minutes=50),
        ):
            self.client_post("/accounts/home/",
                             {"email": self.nonreg_email("test")})
            self.login("iago")
            result = self.client_get("/activity/support",
                                     {"q": self.nonreg_email("test")})
            check_preregistration_user_query_result(result,
                                                    self.nonreg_email("test"))
            check_zulip_realm_query_result(result)

            invite_expires_in_days = 10
            stream_ids = [self.get_stream_id("Denmark")]
            invitee_emails = [self.nonreg_email("test1")]
            self.client_post(
                "/json/invites",
                {
                    "invitee_emails": invitee_emails,
                    "stream_ids": orjson.dumps(stream_ids).decode(),
                    "invite_expires_in_days": invite_expires_in_days,
                    "invite_as": PreregistrationUser.INVITE_AS["MEMBER"],
                },
            )
            result = self.client_get("/activity/support",
                                     {"q": self.nonreg_email("test1")})
            check_preregistration_user_query_result(result,
                                                    self.nonreg_email("test1"),
                                                    invite=True)
            check_zulip_realm_query_result(result)

            email = self.nonreg_email("alice")
            self.client_post("/new/", {"email": email})
            result = self.client_get("/activity/support", {"q": email})
            check_realm_creation_query_result(result, email)

            do_create_multiuse_invite_link(
                self.example_user("hamlet"),
                invited_as=1,
                invite_expires_in_days=invite_expires_in_days,
            )
            result = self.client_get("/activity/support", {"q": "zulip"})
            check_multiuse_invite_link_query_result(result)
            check_zulip_realm_query_result(result)
            MultiuseInvite.objects.all().delete()

            do_send_realm_reactivation_email(get_realm("zulip"),
                                             acting_user=None)
            result = self.client_get("/activity/support", {"q": "zulip"})
            check_realm_reactivation_link_query_result(result)
            check_zulip_realm_query_result(result)
Beispiel #35
0
def update_realm(
    request: HttpRequest,
    user_profile: UserProfile,
    name: Optional[str] = REQ(validator=check_string, default=None),
    description: Optional[str] = REQ(validator=check_string, default=None),
    emails_restricted_to_domains: Optional[bool] = REQ(validator=check_bool,
                                                       default=None),
    disallow_disposable_email_addresses: Optional[bool] = REQ(
        validator=check_bool, default=None),
    invite_required: Optional[bool] = REQ(validator=check_bool, default=None),
    invite_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    name_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    email_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                 default=None),
    avatar_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                  default=None),
    inline_image_preview: Optional[bool] = REQ(validator=check_bool,
                                               default=None),
    inline_url_embed_preview: Optional[bool] = REQ(validator=check_bool,
                                                   default=None),
    add_emoji_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                   default=None),
    allow_message_deleting: Optional[bool] = REQ(validator=check_bool,
                                                 default=None),
    message_content_delete_limit_seconds: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    allow_message_editing: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    allow_community_topic_editing: Optional[bool] = REQ(validator=check_bool,
                                                        default=None),
    mandatory_topics: Optional[bool] = REQ(validator=check_bool, default=None),
    message_content_edit_limit_seconds: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    allow_edit_history: Optional[bool] = REQ(validator=check_bool,
                                             default=None),
    default_language: Optional[str] = REQ(validator=check_string,
                                          default=None),
    waiting_period_threshold: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    authentication_methods: Optional[Dict[Any,
                                          Any]] = REQ(validator=check_dict([]),
                                                      default=None),
    notifications_stream_id: Optional[int] = REQ(validator=check_int,
                                                 default=None),
    signup_notifications_stream_id: Optional[int] = REQ(validator=check_int,
                                                        default=None),
    message_retention_days: Optional[int] = REQ(
        converter=to_positive_or_allowed_int(Realm.RETAIN_MESSAGE_FOREVER),
        default=None),
    send_welcome_emails: Optional[bool] = REQ(validator=check_bool,
                                              default=None),
    digest_emails_enabled: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    message_content_allowed_in_email_notifications: Optional[bool] = REQ(
        validator=check_bool, default=None),
    bot_creation_policy: Optional[int] = REQ(validator=check_int_in(
        Realm.BOT_CREATION_POLICY_TYPES),
                                             default=None),
    create_stream_policy: Optional[int] = REQ(validator=check_int_in(
        Realm.COMMON_POLICY_TYPES),
                                              default=None),
    invite_to_stream_policy: Optional[int] = REQ(validator=check_int_in(
        Realm.COMMON_POLICY_TYPES),
                                                 default=None),
    user_group_edit_policy: Optional[int] = REQ(validator=check_int_in(
        Realm.USER_GROUP_EDIT_POLICY_TYPES),
                                                default=None),
    private_message_policy: Optional[int] = REQ(validator=check_int_in(
        Realm.PRIVATE_MESSAGE_POLICY_TYPES),
                                                default=None),
    email_address_visibility: Optional[int] = REQ(validator=check_int_in(
        Realm.EMAIL_ADDRESS_VISIBILITY_TYPES),
                                                  default=None),
    default_twenty_four_hour_time: Optional[bool] = REQ(validator=check_bool,
                                                        default=None),
    video_chat_provider: Optional[int] = REQ(validator=check_int,
                                             default=None),
    google_hangouts_domain: Optional[str] = REQ(validator=check_string,
                                                default=None),
    default_code_block_language: Optional[str] = REQ(validator=check_string,
                                                     default=None),
    digest_weekday: Optional[int] = REQ(validator=check_int_in(
        Realm.DIGEST_WEEKDAY_VALUES),
                                        default=None),
) -> HttpResponse:
    realm = user_profile.realm

    # Additional validation/error checking beyond types go here, so
    # the entire request can succeed or fail atomically.
    if default_language is not None and default_language not in get_available_language_codes(
    ):
        raise JsonableError(_("Invalid language '%s'") % (default_language, ))
    if description is not None and len(description) > 1000:
        return json_error(_("Organization description is too long."))
    if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH:
        return json_error(_("Organization name is too long."))
    if authentication_methods is not None and True not in list(
            authentication_methods.values()):
        return json_error(
            _("At least one authentication method must be enabled."))
    if (video_chat_provider is not None and video_chat_provider
            not in {p['id']
                    for p in Realm.VIDEO_CHAT_PROVIDERS.values()}):
        return json_error(
            _("Invalid video_chat_provider {}").format(video_chat_provider))
    if video_chat_provider == Realm.VIDEO_CHAT_PROVIDERS['google_hangouts'][
            'id']:
        try:
            validate_domain(google_hangouts_domain)
        except ValidationError as e:
            return json_error(_('Invalid domain: {}').format(e.messages[0]))

    if message_retention_days is not None:
        realm.ensure_not_on_limited_plan()

    # The user of `locals()` here is a bit of a code smell, but it's
    # restricted to the elements present in realm.property_types.
    #
    # TODO: It should be possible to deduplicate this function up
    # further by some more advanced usage of the
    # `REQ/has_request_variables` extraction.
    req_vars = {
        k: v
        for k, v in list(locals().items()) if k in realm.property_types
    }
    data: Dict[str, Any] = {}

    for k, v in list(req_vars.items()):
        if v is not None and getattr(realm, k) != v:
            do_set_realm_property(realm, k, v)
            if isinstance(v, str):
                data[k] = 'updated'
            else:
                data[k] = v

    # The following realm properties do not fit the pattern above
    # authentication_methods is not supported by the do_set_realm_property
    # framework because of its bitfield.
    if authentication_methods is not None and (
            realm.authentication_methods_dict() != authentication_methods):
        do_set_realm_authentication_methods(realm, authentication_methods)
        data['authentication_methods'] = authentication_methods
    # The message_editing settings are coupled to each other, and thus don't fit
    # into the do_set_realm_property framework.
    if ((allow_message_editing is not None
         and realm.allow_message_editing != allow_message_editing)
            or (message_content_edit_limit_seconds is not None
                and realm.message_content_edit_limit_seconds !=
                message_content_edit_limit_seconds)
            or (allow_community_topic_editing is not None
                and realm.allow_community_topic_editing !=
                allow_community_topic_editing)):
        if allow_message_editing is None:
            allow_message_editing = realm.allow_message_editing
        if message_content_edit_limit_seconds is None:
            message_content_edit_limit_seconds = realm.message_content_edit_limit_seconds
        if allow_community_topic_editing is None:
            allow_community_topic_editing = realm.allow_community_topic_editing
        do_set_realm_message_editing(realm, allow_message_editing,
                                     message_content_edit_limit_seconds,
                                     allow_community_topic_editing)
        data['allow_message_editing'] = allow_message_editing
        data[
            'message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
        data['allow_community_topic_editing'] = allow_community_topic_editing

    if (message_content_delete_limit_seconds is not None
            and realm.message_content_delete_limit_seconds !=
            message_content_delete_limit_seconds):
        do_set_realm_message_deleting(realm,
                                      message_content_delete_limit_seconds)
        data[
            'message_content_delete_limit_seconds'] = message_content_delete_limit_seconds
    # Realm.notifications_stream and Realm.signup_notifications_stream are not boolean,
    # str or integer field, and thus doesn't fit into the do_set_realm_property framework.
    if notifications_stream_id is not None:
        if realm.notifications_stream is None or (realm.notifications_stream.id
                                                  != notifications_stream_id):
            new_notifications_stream = None
            if notifications_stream_id >= 0:
                (new_notifications_stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            notifications_stream_id)
            do_set_realm_notifications_stream(realm, new_notifications_stream,
                                              notifications_stream_id)
            data['notifications_stream_id'] = notifications_stream_id

    if signup_notifications_stream_id is not None:
        if realm.signup_notifications_stream is None or (
                realm.signup_notifications_stream.id !=
                signup_notifications_stream_id):
            new_signup_notifications_stream = None
            if signup_notifications_stream_id >= 0:
                (new_signup_notifications_stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            signup_notifications_stream_id)
            do_set_realm_signup_notifications_stream(
                realm, new_signup_notifications_stream,
                signup_notifications_stream_id)
            data[
                'signup_notifications_stream_id'] = signup_notifications_stream_id

    if default_code_block_language is not None:
        # Migrate '', used in the API to encode the default/None behavior of this feature.
        if default_code_block_language == '':
            data['default_code_block_language'] = None
        else:
            data['default_code_block_language'] = default_code_block_language

    return json_success(data)
Beispiel #36
0
def update_realm(
    request: HttpRequest,
    user_profile: UserProfile,
    name: Optional[str] = REQ(validator=check_string, default=None),
    description: Optional[str] = REQ(validator=check_string, default=None),
    restricted_to_domain: Optional[bool] = REQ(validator=check_bool,
                                               default=None),
    invite_required: Optional[bool] = REQ(validator=check_bool, default=None),
    invite_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    name_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    email_changes_disabled: Optional[bool] = REQ(validator=check_bool,
                                                 default=None),
    inline_image_preview: Optional[bool] = REQ(validator=check_bool,
                                               default=None),
    inline_url_embed_preview: Optional[bool] = REQ(validator=check_bool,
                                                   default=None),
    create_stream_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                       default=None),
    add_emoji_by_admins_only: Optional[bool] = REQ(validator=check_bool,
                                                   default=None),
    create_generic_bot_by_admins_only: Optional[bool] = REQ(
        validator=check_bool, default=None),
    allow_message_deleting: Optional[bool] = REQ(validator=check_bool,
                                                 default=None),
    allow_message_editing: Optional[bool] = REQ(validator=check_bool,
                                                default=None),
    mandatory_topics: Optional[bool] = REQ(validator=check_bool, default=None),
    message_content_edit_limit_seconds: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    allow_edit_history: Optional[bool] = REQ(validator=check_bool,
                                             default=None),
    default_language: Optional[str] = REQ(validator=check_string,
                                          default=None),
    waiting_period_threshold: Optional[int] = REQ(
        converter=to_non_negative_int, default=None),
    authentication_methods: Optional[Dict[Any,
                                          Any]] = REQ(validator=check_dict([]),
                                                      default=None),
    notifications_stream_id: Optional[int] = REQ(validator=check_int,
                                                 default=None),
    signup_notifications_stream_id: Optional[int] = REQ(validator=check_int,
                                                        default=None),
    message_retention_days: Optional[int] = REQ(
        converter=to_not_negative_int_or_none, default=None)
) -> HttpResponse:
    realm = user_profile.realm

    # Additional validation/error checking beyond types go here, so
    # the entire request can succeed or fail atomically.
    if default_language is not None and default_language not in get_available_language_codes(
    ):
        raise JsonableError(_("Invalid language '%s'" % (default_language, )))
    if description is not None and len(description) > 1000:
        return json_error(_("Realm description is too long."))
    if name is not None and len(name) > Realm.MAX_REALM_NAME_LENGTH:
        return json_error(_("Realm name is too long."))
    if authentication_methods is not None and True not in list(
            authentication_methods.values()):
        return json_error(
            _("At least one authentication method must be enabled."))

    # The user of `locals()` here is a bit of a code smell, but it's
    # restricted to the elements present in realm.property_types.
    #
    # TODO: It should be possible to deduplicate this function up
    # further by some more advanced usage of the
    # `REQ/has_request_variables` extraction.
    req_vars = {
        k: v
        for k, v in list(locals().items()) if k in realm.property_types
    }
    data = {}  # type: Dict[str, Any]

    for k, v in list(req_vars.items()):
        if v is not None and getattr(realm, k) != v:
            do_set_realm_property(realm, k, v)
            if isinstance(v, Text):
                data[k] = 'updated'
            else:
                data[k] = v

    # The following realm properties do not fit the pattern above
    # authentication_methods is not supported by the do_set_realm_property
    # framework because of its bitfield.
    if authentication_methods is not None and (
            realm.authentication_methods_dict() != authentication_methods):
        do_set_realm_authentication_methods(realm, authentication_methods)
        data['authentication_methods'] = authentication_methods
    # The message_editing settings are coupled to each other, and thus don't fit
    # into the do_set_realm_property framework.
    if (allow_message_editing is not None and realm.allow_message_editing != allow_message_editing) or \
       (message_content_edit_limit_seconds is not None and
            realm.message_content_edit_limit_seconds != message_content_edit_limit_seconds):
        if allow_message_editing is None:
            allow_message_editing = realm.allow_message_editing
        if message_content_edit_limit_seconds is None:
            message_content_edit_limit_seconds = realm.message_content_edit_limit_seconds
        do_set_realm_message_editing(realm, allow_message_editing,
                                     message_content_edit_limit_seconds)
        data['allow_message_editing'] = allow_message_editing
        data[
            'message_content_edit_limit_seconds'] = message_content_edit_limit_seconds
    # Realm.notifications_stream and Realm.signup_notifications_stream are not boolean,
    # Text or integer field, and thus doesn't fit into the do_set_realm_property framework.
    if notifications_stream_id is not None:
        if realm.notifications_stream is None or (realm.notifications_stream.id
                                                  != notifications_stream_id):
            new_notifications_stream = None
            if notifications_stream_id >= 0:
                (new_notifications_stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            notifications_stream_id)
            do_set_realm_notifications_stream(realm, new_notifications_stream,
                                              notifications_stream_id)
            data['notifications_stream_id'] = notifications_stream_id

    if signup_notifications_stream_id is not None:
        if realm.signup_notifications_stream is None or (
                realm.signup_notifications_stream.id !=
                signup_notifications_stream_id):
            new_signup_notifications_stream = None
            if signup_notifications_stream_id >= 0:
                (new_signup_notifications_stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            signup_notifications_stream_id)
            do_set_realm_signup_notifications_stream(
                realm, new_signup_notifications_stream,
                signup_notifications_stream_id)
            data[
                'signup_notifications_stream_id'] = signup_notifications_stream_id

    return json_success(data)
Beispiel #37
0
 def setUp(self) -> None:
     realm = get_realm('zulip')
     do_set_realm_property(realm, 'emails_restricted_to_domains', True)