diff --git a/frontend_tests/node_tests/popovers.js b/frontend_tests/node_tests/popovers.js index 13bca5c2ee..9b91769358 100644 --- a/frontend_tests/node_tests/popovers.js +++ b/frontend_tests/node_tests/popovers.js @@ -50,6 +50,7 @@ const alice = { email: 'alice@example.com', full_name: 'Alice Smith', user_id: 42, + avatar_version: 5, is_guest: false, is_admin: false, }; @@ -184,13 +185,16 @@ run_test('sender_hover', () => { }); $('.user_popover_email').each = noop; - const image_stubber = make_image_stubber(); - + window.location = { + href: 'http://chat.zulip.org/', + }; + const base_url = window.location.href; handler.call(target, e); const avatar_img = image_stubber.get(0); - assert.equal(avatar_img.src, 'avatar/42/medium'); + const expected_url = new URL('avatar/42/medium?v=' + alice.avatar_version, base_url); + assert.equal(avatar_img.src.toString(), expected_url.toString()); // todo: load image }); diff --git a/static/js/popovers.js b/static/js/popovers.js index 56f381d4e0..38b14e17ad 100644 --- a/static/js/popovers.js +++ b/static/js/popovers.js @@ -94,8 +94,10 @@ function init_email_clipboard() { } function load_medium_avatar(user, elt) { - const user_avatar_url = "avatar/" + user.user_id + "/medium"; + const avatar_path = "avatar/" + user.user_id + "/medium?v=" + user.avatar_version; + const user_avatar_url = new URL(avatar_path, window.location.href); const sender_avatar_medium = new Image(); + sender_avatar_medium.src = user_avatar_url; $(sender_avatar_medium).on("load", function () { elt.css("background-image", "url(" + $(this).attr("src") + ")"); diff --git a/static/js/user_events.js b/static/js/user_events.js index eb9a14518a..8c84aef111 100644 --- a/static/js/user_events.js +++ b/static/js/user_events.js @@ -69,6 +69,7 @@ exports.update_person = function update(person) { if (Object.prototype.hasOwnProperty.call(person, 'avatar_url')) { const url = person.avatar_url; person_obj.avatar_url = url; + person_obj.avatar_version = person.avatar_version; if (people.is_my_user_id(person.user_id)) { page_params.avatar_source = person.avatar_source; diff --git a/templates/zerver/api/changelog.md b/templates/zerver/api/changelog.md index 36e2d85a06..c8755c4df1 100644 --- a/templates/zerver/api/changelog.md +++ b/templates/zerver/api/changelog.md @@ -10,6 +10,15 @@ below features are supported. ## Changes in Zulip 2.2 +**Feature level 6** +* [`GET /events`](/api/get-events-from-queue): `realm_user` events to + update a user's avatar now include the `avatar_version` field, which + is important for correctly refetching medium-size avatar images when + the user's avatar changes. +* [`GET /users`](/api/get-all-users) and [`GET + /users/{user_id}`](/api/get-user): User objects now contain the + `avatar_version` field as well. + **Feature level 5** * [`GET /events`](/api/get-events-from-queue): `realm_bot` events, sent when changes are made to bot users, now contain an diff --git a/version.py b/version.py index 74b1a2b671..0edc16c0a1 100644 --- a/version.py +++ b/version.py @@ -29,7 +29,7 @@ DESKTOP_WARNING_VERSION = "5.2.0" # # Changes should be accompanied by documentation explaining what the # new level means in templates/zerver/api/changelog.md. -API_FEATURE_LEVEL = 5 +API_FEATURE_LEVEL = 6 # Bump the minor PROVISION_VERSION to indicate that folks should provision # only when going from an old version of the code to a newer version. Bump diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py index 16a248b403..b9ece499d0 100644 --- a/zerver/lib/actions.py +++ b/zerver/lib/actions.py @@ -3263,10 +3263,11 @@ def notify_avatar_url_change(user_profile: UserProfile) -> None: bot_owner_user_ids(user_profile)) payload = dict( - email=user_profile.email, avatar_source=user_profile.avatar_source, avatar_url=avatar_url(user_profile), avatar_url_medium=avatar_url(user_profile, medium=True), + avatar_version=user_profile.avatar_version, + email=user_profile.email, user_id=user_profile.id ) diff --git a/zerver/lib/users.py b/zerver/lib/users.py index ab63365949..894c6fce96 100644 --- a/zerver/lib/users.py +++ b/zerver/lib/users.py @@ -315,6 +315,7 @@ def format_user_row(realm: Realm, acting_user: UserProfile, row: Dict[str, Any], email=row['email'], user_id=row['id'], avatar_url=avatar_url, + avatar_version=row['avatar_version'], is_admin=is_admin, is_guest=is_guest, is_bot=is_bot, diff --git a/zerver/tests/test_custom_profile_data.py b/zerver/tests/test_custom_profile_data.py index 80facd068e..b8f16322bb 100644 --- a/zerver/tests/test_custom_profile_data.py +++ b/zerver/tests/test_custom_profile_data.py @@ -672,14 +672,14 @@ class ListCustomProfileFieldTest(CustomProfileFieldTestCase): expected_keys_for_iago = { "delivery_email", - "email", "user_id", "avatar_url", "is_admin", "is_guest", "is_bot", + "email", "user_id", "avatar_url", "avatar_version", "is_admin", "is_guest", "is_bot", "full_name", "timezone", "is_active", "date_joined", "profile_data"} self.assertEqual(set(iago_raw_data.keys()), expected_keys_for_iago) self.assertNotEqual(iago_raw_data["profile_data"], {}) expected_keys_for_test_bot = { "delivery_email", - "email", "user_id", "avatar_url", "is_admin", "is_guest", "is_bot", "full_name", + "email", "user_id", "avatar_url", "avatar_version", "is_admin", "is_guest", "is_bot", "full_name", "timezone", "is_active", "date_joined", "bot_type", "bot_owner_id"} self.assertEqual(set(test_bot_raw_data.keys()), expected_keys_for_test_bot) self.assertEqual(test_bot_raw_data["bot_type"], 1) diff --git a/zerver/tests/test_events.py b/zerver/tests/test_events.py index d4aab01054..de57989fb7 100644 --- a/zerver/tests/test_events.py +++ b/zerver/tests/test_events.py @@ -1247,6 +1247,7 @@ class EventsRegisterTest(ZulipTestCase): ('user_id', check_int), ('email', check_string), ('avatar_url', check_none_or(check_string)), + ('avatar_version', check_int), ('full_name', check_string), ('is_admin', check_bool), ('is_bot', check_bool), @@ -1273,6 +1274,7 @@ class EventsRegisterTest(ZulipTestCase): ('user_id', check_int), ('email', check_string), ('avatar_url', check_none_or(check_string)), + ('avatar_version', check_int), ('full_name', check_string), ('is_active', check_bool), ('is_admin', check_bool), @@ -1534,6 +1536,7 @@ class EventsRegisterTest(ZulipTestCase): ('user_id', check_int), ('avatar_url', check_string), ('avatar_url_medium', check_string), + ('avatar_version', check_int), ('avatar_source', check_string), ])), ]) @@ -1547,11 +1550,12 @@ class EventsRegisterTest(ZulipTestCase): ('type', equals('realm_user')), ('op', equals('update')), ('person', check_dict_only([ - ('email', check_string), - ('user_id', check_int), + ('avatar_source', check_string), ('avatar_url', check_none_or(check_string)), ('avatar_url_medium', check_none_or(check_string)), - ('avatar_source', check_string), + ('avatar_version', check_int), + ('email', check_string), + ('user_id', check_int), ])), ]) events = self.do_test( @@ -1589,9 +1593,10 @@ class EventsRegisterTest(ZulipTestCase): ('person', check_dict_only([ ('email', check_string), ('user_id', check_int), + ('avatar_source', check_string), ('avatar_url', check_string), ('avatar_url_medium', check_string), - ('avatar_source', check_string), + ('avatar_version', check_int), ])), ]) do_set_realm_property(self.user_profile.realm, "email_address_visibility", diff --git a/zerver/tests/test_home.py b/zerver/tests/test_home.py index 8b9de34748..d6228cf28d 100644 --- a/zerver/tests/test_home.py +++ b/zerver/tests/test_home.py @@ -604,6 +604,7 @@ class HomeTest(ZulipTestCase): self.assertEqual(sorted(cross_bots, key=by_email), sorted([ dict( + avatar_version=email_gateway_bot.avatar_version, bot_owner_id=None, bot_type=1, email=email_gateway_bot.email, @@ -616,6 +617,7 @@ class HomeTest(ZulipTestCase): is_guest=False ), dict( + avatar_version=email_gateway_bot.avatar_version, bot_owner_id=None, bot_type=1, email=notification_bot.email, @@ -628,6 +630,7 @@ class HomeTest(ZulipTestCase): is_guest=False ), dict( + avatar_version=email_gateway_bot.avatar_version, bot_owner_id=None, bot_type=1, email=welcome_bot.email,