mirror of https://github.com/zulip/zulip.git
user-status: Update `presence_enabled` with changes to user status `away`.
When a user toggles a status update for `away=True|False`, we now update their `presence_enabled` setting to match (`away!=presence_enabled`). First step of making user status `away` updates a deprecated way to access presence_enabled for clients supporting older servers, and checkpoint commit before migrating users with a current UserStatus of `status=AWAY` to have their `presence_enabled` set to `False`. Note that when user status `away` is updated, we now send 4 events: user_status, user_settings, presence, and update_global_notifications. Also, this means that these updates change the UserPresence.status value, which impacts the test for importing and exporting user information. Part of transitioning from 'unavailable' user status feature to 'invisible mode' user presence feature.
This commit is contained in:
parent
3428fe86d6
commit
843eb4e4fc
|
@ -1,5 +1,6 @@
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from zerver.actions.user_settings import do_change_user_setting
|
||||||
from zerver.lib.user_status import update_user_status
|
from zerver.lib.user_status import update_user_status
|
||||||
from zerver.models import UserProfile, UserStatus, active_user_ids
|
from zerver.models import UserProfile, UserStatus, active_user_ids
|
||||||
from zerver.tornado.django_api import send_event
|
from zerver.tornado.django_api import send_event
|
||||||
|
@ -14,6 +15,13 @@ def do_update_user_status(
|
||||||
emoji_code: Optional[str],
|
emoji_code: Optional[str],
|
||||||
reaction_type: Optional[str],
|
reaction_type: Optional[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
|
# Deprecated way for clients to access the user's `presence_enabled`
|
||||||
|
# setting, with away != presence_enabled.
|
||||||
|
if away is not None:
|
||||||
|
user_setting = "presence_enabled"
|
||||||
|
value = not away
|
||||||
|
do_change_user_setting(user_profile, user_setting, value, acting_user=user_profile)
|
||||||
|
|
||||||
if away is None:
|
if away is None:
|
||||||
status = None
|
status = None
|
||||||
elif away:
|
elif away:
|
||||||
|
|
|
@ -1143,16 +1143,20 @@ class NormalActionsTest(BaseAction):
|
||||||
|
|
||||||
def test_away_events(self) -> None:
|
def test_away_events(self) -> None:
|
||||||
client = get_client("website")
|
client = get_client("website")
|
||||||
|
|
||||||
|
# Set all
|
||||||
|
away_val = True
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_update_user_status(
|
lambda: do_update_user_status(
|
||||||
user_profile=self.user_profile,
|
user_profile=self.user_profile,
|
||||||
away=True,
|
away=away_val,
|
||||||
status_text="out to lunch",
|
status_text="out to lunch",
|
||||||
emoji_name="car",
|
emoji_name="car",
|
||||||
emoji_code="1f697",
|
emoji_code="1f697",
|
||||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||||
client_id=client.id,
|
client_id=client.id,
|
||||||
)
|
),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
check_user_status(
|
check_user_status(
|
||||||
|
@ -1160,16 +1164,29 @@ class NormalActionsTest(BaseAction):
|
||||||
events[0],
|
events[0],
|
||||||
{"away", "status_text", "emoji_name", "emoji_code", "reaction_type"},
|
{"away", "status_text", "emoji_name", "emoji_code", "reaction_type"},
|
||||||
)
|
)
|
||||||
|
check_user_settings_update("events[1]", events[1])
|
||||||
|
check_update_global_notifications("events[2]", events[2], not away_val)
|
||||||
|
check_presence(
|
||||||
|
"events[3]",
|
||||||
|
events[3],
|
||||||
|
has_email=True,
|
||||||
|
presence_key="website",
|
||||||
|
status="active" if not away_val else "idle",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Remove all
|
||||||
|
away_val = False
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_update_user_status(
|
lambda: do_update_user_status(
|
||||||
user_profile=self.user_profile,
|
user_profile=self.user_profile,
|
||||||
away=False,
|
away=away_val,
|
||||||
status_text="",
|
status_text="",
|
||||||
emoji_name="",
|
emoji_name="",
|
||||||
emoji_code="",
|
emoji_code="",
|
||||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||||
client_id=client.id,
|
client_id=client.id,
|
||||||
)
|
),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
check_user_status(
|
check_user_status(
|
||||||
|
@ -1177,21 +1194,43 @@ class NormalActionsTest(BaseAction):
|
||||||
events[0],
|
events[0],
|
||||||
{"away", "status_text", "emoji_name", "emoji_code", "reaction_type"},
|
{"away", "status_text", "emoji_name", "emoji_code", "reaction_type"},
|
||||||
)
|
)
|
||||||
|
check_user_settings_update("events[1]", events[1])
|
||||||
|
check_update_global_notifications("events[2]", events[2], not away_val)
|
||||||
|
check_presence(
|
||||||
|
"events[3]",
|
||||||
|
events[3],
|
||||||
|
has_email=True,
|
||||||
|
presence_key="website",
|
||||||
|
status="active" if not away_val else "idle",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Only set away
|
||||||
|
away_val = True
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_update_user_status(
|
lambda: do_update_user_status(
|
||||||
user_profile=self.user_profile,
|
user_profile=self.user_profile,
|
||||||
away=True,
|
away=away_val,
|
||||||
status_text=None,
|
status_text=None,
|
||||||
emoji_name=None,
|
emoji_name=None,
|
||||||
emoji_code=None,
|
emoji_code=None,
|
||||||
reaction_type=None,
|
reaction_type=None,
|
||||||
client_id=client.id,
|
client_id=client.id,
|
||||||
)
|
),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
|
|
||||||
check_user_status("events[0]", events[0], {"away"})
|
check_user_status("events[0]", events[0], {"away"})
|
||||||
|
check_user_settings_update("events[1]", events[1])
|
||||||
|
check_update_global_notifications("events[2]", events[2], not away_val)
|
||||||
|
check_presence(
|
||||||
|
"events[3]",
|
||||||
|
events[3],
|
||||||
|
has_email=True,
|
||||||
|
presence_key="website",
|
||||||
|
status="active" if not away_val else "idle",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Only set status_text
|
||||||
events = self.verify_action(
|
events = self.verify_action(
|
||||||
lambda: do_update_user_status(
|
lambda: do_update_user_status(
|
||||||
user_profile=self.user_profile,
|
user_profile=self.user_profile,
|
||||||
|
|
|
@ -1722,7 +1722,7 @@ class SingleUserExportTest(ExportFile):
|
||||||
|
|
||||||
do_update_user_status(
|
do_update_user_status(
|
||||||
user_profile=cordelia,
|
user_profile=cordelia,
|
||||||
away=True,
|
away=None,
|
||||||
status_text="on vacation",
|
status_text="on vacation",
|
||||||
client_id=client.id,
|
client_id=client.id,
|
||||||
emoji_name=None,
|
emoji_name=None,
|
||||||
|
@ -1744,7 +1744,7 @@ class SingleUserExportTest(ExportFile):
|
||||||
def zerver_userstatus(records: List[Record]) -> None:
|
def zerver_userstatus(records: List[Record]) -> None:
|
||||||
rec = records[-1]
|
rec = records[-1]
|
||||||
self.assertEqual(rec["status_text"], "on vacation")
|
self.assertEqual(rec["status_text"], "on vacation")
|
||||||
self.assertEqual(rec["status"], UserStatus.AWAY)
|
self.assertEqual(rec["status"], UserStatus.NORMAL)
|
||||||
|
|
||||||
do_mute_topic(cordelia, scotland, "bagpipe music")
|
do_mute_topic(cordelia, scotland, "bagpipe music")
|
||||||
do_mute_topic(othello, scotland, "nessie")
|
do_mute_topic(othello, scotland, "nessie")
|
||||||
|
|
|
@ -174,10 +174,10 @@ class UserStatusTest(ZulipTestCase):
|
||||||
self.assertEqual(away_user_ids, {cordelia.id})
|
self.assertEqual(away_user_ids, {cordelia.id})
|
||||||
|
|
||||||
def update_status_and_assert_event(
|
def update_status_and_assert_event(
|
||||||
self, payload: Dict[str, Any], expected_event: Dict[str, Any]
|
self, payload: Dict[str, Any], expected_event: Dict[str, Any], num_events: int = 1
|
||||||
) -> None:
|
) -> None:
|
||||||
events: List[Mapping[str, Any]] = []
|
events: List[Mapping[str, Any]] = []
|
||||||
with self.tornado_redirected_to_list(events, expected_num_events=1):
|
with self.tornado_redirected_to_list(events, expected_num_events=num_events):
|
||||||
result = self.client_post("/json/users/me/status", payload)
|
result = self.client_post("/json/users/me/status", payload)
|
||||||
self.assert_json_success(result)
|
self.assert_json_success(result)
|
||||||
self.assertEqual(events[0]["event"], expected_event)
|
self.assertEqual(events[0]["event"], expected_event)
|
||||||
|
@ -232,6 +232,7 @@ class UserStatusTest(ZulipTestCase):
|
||||||
expected_event=dict(
|
expected_event=dict(
|
||||||
type="user_status", user_id=hamlet.id, away=True, status_text="on vacation"
|
type="user_status", user_id=hamlet.id, away=True, status_text="on vacation"
|
||||||
),
|
),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
user_status_info(hamlet),
|
user_status_info(hamlet),
|
||||||
|
@ -252,6 +253,7 @@ class UserStatusTest(ZulipTestCase):
|
||||||
emoji_code="1f697",
|
emoji_code="1f697",
|
||||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||||
),
|
),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
user_status_info(hamlet),
|
user_status_info(hamlet),
|
||||||
|
@ -278,6 +280,7 @@ class UserStatusTest(ZulipTestCase):
|
||||||
emoji_code="",
|
emoji_code="",
|
||||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||||
),
|
),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
user_status_info(hamlet),
|
user_status_info(hamlet),
|
||||||
|
@ -288,6 +291,7 @@ class UserStatusTest(ZulipTestCase):
|
||||||
self.update_status_and_assert_event(
|
self.update_status_and_assert_event(
|
||||||
payload=dict(away=orjson.dumps(False).decode()),
|
payload=dict(away=orjson.dumps(False).decode()),
|
||||||
expected_event=dict(type="user_status", user_id=hamlet.id, away=False),
|
expected_event=dict(type="user_status", user_id=hamlet.id, away=False),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
away_user_ids = get_away_user_ids(realm_id=realm_id)
|
away_user_ids = get_away_user_ids(realm_id=realm_id)
|
||||||
self.assertEqual(away_user_ids, set())
|
self.assertEqual(away_user_ids, set())
|
||||||
|
@ -318,6 +322,7 @@ class UserStatusTest(ZulipTestCase):
|
||||||
self.update_status_and_assert_event(
|
self.update_status_and_assert_event(
|
||||||
payload=dict(away=orjson.dumps(True).decode()),
|
payload=dict(away=orjson.dumps(True).decode()),
|
||||||
expected_event=dict(type="user_status", user_id=hamlet.id, away=True),
|
expected_event=dict(type="user_status", user_id=hamlet.id, away=True),
|
||||||
|
num_events=4,
|
||||||
)
|
)
|
||||||
away_user_ids = get_away_user_ids(realm_id=realm_id)
|
away_user_ids = get_away_user_ids(realm_id=realm_id)
|
||||||
self.assertEqual(away_user_ids, {hamlet.id})
|
self.assertEqual(away_user_ids, {hamlet.id})
|
||||||
|
|
Loading…
Reference in New Issue