mirror of https://github.com/zulip/zulip.git
user_status: Add backend changes to support status emoji.
In this commit: * We update the `UserStatus` model to accept `AbstractReaction` as a base class so, we can get all the fields related to store status emoji. * We update the user status endpoint (`users/me/status`) to accept status emoji fields. * We update the user status event to add status emoji fields. Co-authored-by: Yash Rathore <33805964+YashRE42@users.noreply.github.com>
This commit is contained in:
parent
ed01ffadba
commit
9fadd43830
|
@ -11,6 +11,15 @@ below features are supported.
|
|||
|
||||
## Changes in Zulip 5.0
|
||||
|
||||
**Feature level 86**
|
||||
|
||||
* [`GET /events`](/api/get-events): Added `emoji_name`,
|
||||
`emoji_code`, and `reaction_type` fields to `user_status` objects.
|
||||
* [`POST /register`](/api/register-queue): Added `emoji_name`,
|
||||
`emoji_code`, and `reaction_type` fields to `user_status` objects.
|
||||
* `POST /users/me/status`: Added support for new `emoji_name`,
|
||||
`emoji_code`, and `reaction_type` parameters.
|
||||
|
||||
**Feature level 85**
|
||||
|
||||
* [`POST /register`](/api/register-queue), `PATCH /realm`: Replaced `add_emoji_by_admins_only`
|
||||
|
|
|
@ -33,7 +33,7 @@ DESKTOP_WARNING_VERSION = "5.4.3"
|
|||
# Changes should be accompanied by documentation explaining what the
|
||||
# new level means in templates/zerver/api/changelog.md, as well as
|
||||
# "**Changes**" entries in the endpoint's documentation in `zulip.yaml`.
|
||||
API_FEATURE_LEVEL = 85
|
||||
API_FEATURE_LEVEL = 86
|
||||
|
||||
# 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
|
||||
|
|
|
@ -5401,7 +5401,13 @@ def update_user_presence(
|
|||
|
||||
|
||||
def do_update_user_status(
|
||||
user_profile: UserProfile, away: Optional[bool], status_text: Optional[str], client_id: int
|
||||
user_profile: UserProfile,
|
||||
away: Optional[bool],
|
||||
status_text: Optional[str],
|
||||
client_id: int,
|
||||
emoji_name: Optional[str],
|
||||
emoji_code: Optional[str],
|
||||
reaction_type: Optional[str],
|
||||
) -> None:
|
||||
if away is None:
|
||||
status = None
|
||||
|
@ -5417,6 +5423,9 @@ def do_update_user_status(
|
|||
status=status,
|
||||
status_text=status_text,
|
||||
client_id=client_id,
|
||||
emoji_name=emoji_name,
|
||||
emoji_code=emoji_code,
|
||||
reaction_type=reaction_type,
|
||||
)
|
||||
|
||||
event = dict(
|
||||
|
@ -5430,6 +5439,10 @@ def do_update_user_status(
|
|||
if status_text is not None:
|
||||
event["status_text"] = status_text
|
||||
|
||||
if emoji_name is not None:
|
||||
event["emoji_name"] = emoji_name
|
||||
event["emoji_code"] = emoji_code
|
||||
event["reaction_type"] = reaction_type
|
||||
send_event(realm, event, active_user_ids(realm.id))
|
||||
|
||||
|
||||
|
|
|
@ -1653,6 +1653,9 @@ user_status_event = event_dict_type(
|
|||
# force vertical
|
||||
("away", bool),
|
||||
("status_text", str),
|
||||
("emoji_name", str),
|
||||
("emoji_code", str),
|
||||
("reaction_type", str),
|
||||
],
|
||||
)
|
||||
_check_user_status = make_checker(user_status_event)
|
||||
|
|
|
@ -59,6 +59,7 @@ from zerver.models import (
|
|||
Stream,
|
||||
UserMessage,
|
||||
UserProfile,
|
||||
UserStatus,
|
||||
custom_profile_fields_for_realm,
|
||||
get_default_stream_groups,
|
||||
get_realm_domains,
|
||||
|
@ -1092,6 +1093,9 @@ def apply_event(
|
|||
user_status = state["user_status"]
|
||||
away = event.get("away")
|
||||
status_text = event.get("status_text")
|
||||
emoji_name = event.get("emoji_name")
|
||||
emoji_code = event.get("emoji_code")
|
||||
reaction_type = event.get("reaction_type")
|
||||
|
||||
if user_id_str not in user_status:
|
||||
user_status[user_id_str] = {}
|
||||
|
@ -1108,6 +1112,24 @@ def apply_event(
|
|||
else:
|
||||
user_status[user_id_str]["status_text"] = status_text
|
||||
|
||||
if emoji_name is not None:
|
||||
if emoji_name == "":
|
||||
user_status[user_id_str].pop("emoji_name", None)
|
||||
else:
|
||||
user_status[user_id_str]["emoji_name"] = emoji_name
|
||||
|
||||
if emoji_code is not None:
|
||||
if emoji_code == "":
|
||||
user_status[user_id_str].pop("emoji_code", None)
|
||||
else:
|
||||
user_status[user_id_str]["emoji_code"] = emoji_code
|
||||
|
||||
if reaction_type is not None:
|
||||
if reaction_type == UserStatus.UNICODE_EMOJI and emoji_name == "":
|
||||
user_status[user_id_str].pop("reaction_type", None)
|
||||
else:
|
||||
user_status[user_id_str]["reaction_type"] = reaction_type
|
||||
|
||||
if not user_status[user_id_str]:
|
||||
user_status.pop(user_id_str, None)
|
||||
|
||||
|
|
|
@ -13,12 +13,19 @@ def get_user_info_dict(realm_id: int) -> Dict[str, Dict[str, Any]]:
|
|||
user_profile__is_active=True,
|
||||
)
|
||||
.exclude(
|
||||
Q(status=UserStatus.NORMAL) & Q(status_text=""),
|
||||
Q(status=UserStatus.NORMAL)
|
||||
& Q(status_text="")
|
||||
& Q(emoji_name="")
|
||||
& Q(emoji_code="")
|
||||
& Q(reaction_type=UserStatus.UNICODE_EMOJI),
|
||||
)
|
||||
.values(
|
||||
"user_profile_id",
|
||||
"status",
|
||||
"status_text",
|
||||
"emoji_name",
|
||||
"emoji_code",
|
||||
"reaction_type",
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -27,12 +34,19 @@ def get_user_info_dict(realm_id: int) -> Dict[str, Dict[str, Any]]:
|
|||
away = row["status"] == UserStatus.AWAY
|
||||
status_text = row["status_text"]
|
||||
user_id = row["user_profile_id"]
|
||||
emoji_name = row["emoji_name"]
|
||||
emoji_code = row["emoji_code"]
|
||||
reaction_type = row["reaction_type"]
|
||||
|
||||
dct = {}
|
||||
if away:
|
||||
dct["away"] = away
|
||||
if status_text:
|
||||
dct["status_text"] = status_text
|
||||
if emoji_name:
|
||||
dct["emoji_name"] = emoji_name
|
||||
dct["emoji_code"] = emoji_code
|
||||
dct["reaction_type"] = reaction_type
|
||||
|
||||
user_dict[str(user_id)] = dct
|
||||
|
||||
|
@ -40,7 +54,13 @@ def get_user_info_dict(realm_id: int) -> Dict[str, Dict[str, Any]]:
|
|||
|
||||
|
||||
def update_user_status(
|
||||
user_profile_id: int, status: Optional[int], status_text: Optional[str], client_id: int
|
||||
user_profile_id: int,
|
||||
status: Optional[int],
|
||||
status_text: Optional[str],
|
||||
client_id: int,
|
||||
emoji_name: Optional[str],
|
||||
emoji_code: Optional[str],
|
||||
reaction_type: Optional[str],
|
||||
) -> None:
|
||||
|
||||
timestamp = timezone_now()
|
||||
|
@ -56,6 +76,15 @@ def update_user_status(
|
|||
if status_text is not None:
|
||||
defaults["status_text"] = status_text
|
||||
|
||||
if emoji_name is not None:
|
||||
defaults["emoji_name"] = emoji_name
|
||||
|
||||
if emoji_code is not None:
|
||||
defaults["emoji_code"] = emoji_code
|
||||
|
||||
if reaction_type is not None:
|
||||
defaults["reaction_type"] = reaction_type
|
||||
|
||||
UserStatus.objects.update_or_create(
|
||||
user_profile_id=user_profile_id,
|
||||
defaults=defaults,
|
||||
|
|
|
@ -1430,6 +1430,24 @@ paths:
|
|||
type: string
|
||||
description: |
|
||||
The text content of the status message.
|
||||
emoji_name:
|
||||
type: string
|
||||
description: |
|
||||
The [emoji name](/api/add-reaction#parameters) for the emoji associated with the new status.
|
||||
|
||||
**Changes**; New in Zulip 5.0 (feature level 86).
|
||||
emoji_code:
|
||||
type: string
|
||||
description: |
|
||||
The [emoji code](/api/add-reaction#parameters) for the emoji associated with the new status.
|
||||
|
||||
**Changes**; New in Zulip 5.0 (feature level 86).
|
||||
reaction_type:
|
||||
type: string
|
||||
description: |
|
||||
The [emoji type](/api/add-reaction#parameters) for the emoji associated with the new status.
|
||||
|
||||
**Changes**; New in Zulip 5.0 (feature level 86).
|
||||
user_id:
|
||||
type: integer
|
||||
description: |
|
||||
|
@ -1440,6 +1458,9 @@ paths:
|
|||
"user_id": 10,
|
||||
"away": true,
|
||||
"status_text": "out to lunch",
|
||||
"emoji_name": "car",
|
||||
"emoji_code": "1f697",
|
||||
"reaction_type": "unicode_emoji",
|
||||
"id": 0,
|
||||
}
|
||||
- type: object
|
||||
|
@ -8360,12 +8381,19 @@ paths:
|
|||
error messages when a search returns limited results because
|
||||
a stop word in the query was ignored.
|
||||
user_status:
|
||||
type: object
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/EmojiBase"
|
||||
description: |
|
||||
Present if `user_status` is present in `fetch_event_types`.
|
||||
|
||||
A dictionary which contains the [status](/help/status-and-availability)
|
||||
of all users in the Zulip organization who have set a status.
|
||||
|
||||
**Changes**: The emoji parameters are new in Zulip 5.0 (feature level 86).
|
||||
Previously, Zulip did not support emoji associated with statuses.
|
||||
|
||||
A status that does not have an emoji associated with it is encoded
|
||||
with `emoji_name=""`.
|
||||
additionalProperties:
|
||||
description: |
|
||||
`{user_id}`: Object containing the status details of a user
|
||||
|
@ -12241,7 +12269,7 @@ components:
|
|||
reaction_type: {}
|
||||
user_id: {}
|
||||
user: {}
|
||||
EmojiReactionBase:
|
||||
EmojiBase:
|
||||
type: object
|
||||
properties:
|
||||
emoji_code:
|
||||
|
@ -12267,42 +12295,47 @@ components:
|
|||
(`emoji_code` will be its ID).
|
||||
* `zulip_extra_emoji`: Special emoji included with Zulip. Exists to
|
||||
namespace the `zulip` emoji.
|
||||
user_id:
|
||||
type: integer
|
||||
description: |
|
||||
The ID of the user who added the reaction.
|
||||
|
||||
**Changes**: New in Zulip 3.0 (feature level 2). The `user`
|
||||
object is deprecated and will be removed in the future.
|
||||
user:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
deprecated: true
|
||||
description: |
|
||||
Dictionary with data on the user who added the reaction, including
|
||||
the user ID as the `id` field. **Note**: In the [events
|
||||
API](/api/get-events), this `user` dictionary
|
||||
confusing had the user ID in a field called `user_id`
|
||||
instead. We recommend ignoring fields other than the user
|
||||
ID. **Deprecated** and to be removed in a future release
|
||||
once core clients have migrated to use the `user_id` field.
|
||||
properties:
|
||||
id:
|
||||
EmojiReactionBase:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/EmojiBase"
|
||||
- properties:
|
||||
user_id:
|
||||
type: integer
|
||||
description: |
|
||||
ID of the user.
|
||||
email:
|
||||
type: string
|
||||
description: |
|
||||
Email of the user.
|
||||
full_name:
|
||||
type: string
|
||||
description: |
|
||||
Full name of the user.
|
||||
is_mirror_dummy:
|
||||
type: boolean
|
||||
The ID of the user who added the reaction.
|
||||
|
||||
**Changes**: New in Zulip 3.0 (feature level 2). The `user`
|
||||
object is deprecated and will be removed in the future.
|
||||
user:
|
||||
type: object
|
||||
additionalProperties: false
|
||||
deprecated: true
|
||||
description: |
|
||||
Whether the user is a mirror dummy.
|
||||
Dictionary with data on the user who added the reaction, including
|
||||
the user ID as the `id` field. **Note**: In the [events
|
||||
API](/api/get-events), this `user` dictionary
|
||||
confusing had the user ID in a field called `user_id`
|
||||
instead. We recommend ignoring fields other than the user
|
||||
ID. **Deprecated** and to be removed in a future release
|
||||
once core clients have migrated to use the `user_id` field.
|
||||
properties:
|
||||
id:
|
||||
type: integer
|
||||
description: |
|
||||
ID of the user.
|
||||
email:
|
||||
type: string
|
||||
description: |
|
||||
Email of the user.
|
||||
full_name:
|
||||
type: string
|
||||
description: |
|
||||
Full name of the user.
|
||||
is_mirror_dummy:
|
||||
type: boolean
|
||||
description: |
|
||||
Whether the user is a mirror dummy.
|
||||
Messages:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/MessagesBase"
|
||||
|
|
|
@ -196,6 +196,7 @@ from zerver.models import (
|
|||
UserMessage,
|
||||
UserPresence,
|
||||
UserProfile,
|
||||
UserStatus,
|
||||
get_client,
|
||||
get_stream,
|
||||
get_user_by_delivery_email,
|
||||
|
@ -954,23 +955,45 @@ class NormalActionsTest(BaseAction):
|
|||
user_profile=self.user_profile,
|
||||
away=True,
|
||||
status_text="out to lunch",
|
||||
emoji_name="car",
|
||||
emoji_code="1f697",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
client_id=client.id,
|
||||
)
|
||||
)
|
||||
|
||||
check_user_status("events[0]", events[0], {"away", "status_text"})
|
||||
|
||||
check_user_status(
|
||||
"events[0]",
|
||||
events[0],
|
||||
{"away", "status_text", "emoji_name", "emoji_code", "reaction_type"},
|
||||
)
|
||||
events = self.verify_action(
|
||||
lambda: do_update_user_status(
|
||||
user_profile=self.user_profile, away=False, status_text="", client_id=client.id
|
||||
user_profile=self.user_profile,
|
||||
away=False,
|
||||
status_text="",
|
||||
emoji_name="",
|
||||
emoji_code="",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
client_id=client.id,
|
||||
)
|
||||
)
|
||||
|
||||
check_user_status("events[0]", events[0], {"away", "status_text"})
|
||||
check_user_status(
|
||||
"events[0]",
|
||||
events[0],
|
||||
{"away", "status_text", "emoji_name", "emoji_code", "reaction_type"},
|
||||
)
|
||||
|
||||
events = self.verify_action(
|
||||
lambda: do_update_user_status(
|
||||
user_profile=self.user_profile, away=True, status_text=None, client_id=client.id
|
||||
user_profile=self.user_profile,
|
||||
away=True,
|
||||
status_text=None,
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client.id,
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -981,6 +1004,9 @@ class NormalActionsTest(BaseAction):
|
|||
user_profile=self.user_profile,
|
||||
away=None,
|
||||
status_text="at the beach",
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client.id,
|
||||
)
|
||||
)
|
||||
|
|
|
@ -36,6 +36,9 @@ class UserStatusTest(ZulipTestCase):
|
|||
user_profile_id=hamlet.id,
|
||||
status=UserStatus.AWAY,
|
||||
status_text=None,
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client1.id,
|
||||
)
|
||||
|
||||
|
@ -52,12 +55,21 @@ class UserStatusTest(ZulipTestCase):
|
|||
user_profile_id=hamlet.id,
|
||||
status=UserStatus.AWAY,
|
||||
status_text="out to lunch",
|
||||
emoji_name="car",
|
||||
emoji_code="1f697",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
client_id=client2.id,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
user_info(hamlet),
|
||||
dict(away=True, status_text="out to lunch"),
|
||||
dict(
|
||||
away=True,
|
||||
status_text="out to lunch",
|
||||
emoji_name="car",
|
||||
emoji_code="1f697",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
),
|
||||
)
|
||||
|
||||
away_user_ids = get_away_user_ids(realm_id=realm_id)
|
||||
|
@ -66,24 +78,35 @@ class UserStatusTest(ZulipTestCase):
|
|||
rec_count = UserStatus.objects.filter(user_profile_id=hamlet.id).count()
|
||||
self.assertEqual(rec_count, 1)
|
||||
|
||||
# Setting status_text to None causes it be ignored.
|
||||
# Setting status_text and emoji_info to None causes it be ignored.
|
||||
update_user_status(
|
||||
user_profile_id=hamlet.id,
|
||||
status=UserStatus.NORMAL,
|
||||
status_text=None,
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client2.id,
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
user_info(hamlet),
|
||||
dict(status_text="out to lunch"),
|
||||
dict(
|
||||
status_text="out to lunch",
|
||||
emoji_name="car",
|
||||
emoji_code="1f697",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
),
|
||||
)
|
||||
|
||||
# Clear the status_text now.
|
||||
# Clear the status_text and emoji_info now.
|
||||
update_user_status(
|
||||
user_profile_id=hamlet.id,
|
||||
status=None,
|
||||
status_text="",
|
||||
emoji_name="",
|
||||
emoji_code="",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
client_id=client2.id,
|
||||
)
|
||||
|
||||
|
@ -101,18 +124,27 @@ class UserStatusTest(ZulipTestCase):
|
|||
user_profile_id=hamlet.id,
|
||||
status=UserStatus.AWAY,
|
||||
status_text=None,
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client1.id,
|
||||
)
|
||||
update_user_status(
|
||||
user_profile_id=cordelia.id,
|
||||
status=UserStatus.AWAY,
|
||||
status_text=None,
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client2.id,
|
||||
)
|
||||
update_user_status(
|
||||
user_profile_id=king_lear.id,
|
||||
status=UserStatus.AWAY,
|
||||
status_text=None,
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client2.id,
|
||||
)
|
||||
|
||||
|
@ -127,6 +159,9 @@ class UserStatusTest(ZulipTestCase):
|
|||
user_profile_id=hamlet.id,
|
||||
status=UserStatus.NORMAL,
|
||||
status_text="in a meeting",
|
||||
emoji_name=None,
|
||||
emoji_code=None,
|
||||
reaction_type=None,
|
||||
client_id=client2.id,
|
||||
)
|
||||
|
||||
|
@ -158,6 +193,31 @@ class UserStatusTest(ZulipTestCase):
|
|||
result = self.client_post("/json/users/me/status", payload)
|
||||
self.assert_json_error(result, "Client did not pass any new values.")
|
||||
|
||||
# Try to omit emoji_name parameter but passing emoji_code --this should be an error.
|
||||
payload = {"status_text": "In a meeting", "emoji_code": "1f4bb"}
|
||||
result = self.client_post("/json/users/me/status", payload)
|
||||
self.assert_json_error(
|
||||
result, "Client must pass emoji_name if they pass either emoji_code or reaction_type."
|
||||
)
|
||||
|
||||
# Invalid emoji requests fail
|
||||
payload = {"status_text": "In a meeting", "emoji_code": "1f4bb", "emoji_name": "invalid"}
|
||||
result = self.client_post("/json/users/me/status", payload)
|
||||
self.assert_json_error(result, "Emoji 'invalid' does not exist")
|
||||
|
||||
payload = {"status_text": "In a meeting", "emoji_code": "1f4bb", "emoji_name": "car"}
|
||||
result = self.client_post("/json/users/me/status", payload)
|
||||
self.assert_json_error(result, "Invalid emoji name.")
|
||||
|
||||
payload = {
|
||||
"status_text": "In a meeting",
|
||||
"emoji_code": "1f4bb",
|
||||
"emoji_name": "car",
|
||||
"reaction_type": "realm_emoji",
|
||||
}
|
||||
result = self.client_post("/json/users/me/status", payload)
|
||||
self.assert_json_error(result, "Invalid custom emoji.")
|
||||
|
||||
# Try a long message.
|
||||
long_text = "x" * 61
|
||||
payload = dict(status_text=long_text)
|
||||
|
@ -178,6 +238,52 @@ class UserStatusTest(ZulipTestCase):
|
|||
dict(away=True, status_text="on vacation"),
|
||||
)
|
||||
|
||||
# Server should fill emoji_code and reaction_type by emoji_name.
|
||||
self.update_status_and_assert_event(
|
||||
payload=dict(
|
||||
away=orjson.dumps(True).decode(),
|
||||
emoji_name="car",
|
||||
),
|
||||
expected_event=dict(
|
||||
type="user_status",
|
||||
user_id=hamlet.id,
|
||||
away=True,
|
||||
emoji_name="car",
|
||||
emoji_code="1f697",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
user_info(hamlet),
|
||||
dict(
|
||||
away=True,
|
||||
status_text="on vacation",
|
||||
emoji_name="car",
|
||||
emoji_code="1f697",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
),
|
||||
)
|
||||
|
||||
# Server should remove emoji_code and reaction_type if emoji_name is empty.
|
||||
self.update_status_and_assert_event(
|
||||
payload=dict(
|
||||
away=orjson.dumps(True).decode(),
|
||||
emoji_name="",
|
||||
),
|
||||
expected_event=dict(
|
||||
type="user_status",
|
||||
user_id=hamlet.id,
|
||||
away=True,
|
||||
emoji_name="",
|
||||
emoji_code="",
|
||||
reaction_type=UserStatus.UNICODE_EMOJI,
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
user_info(hamlet),
|
||||
dict(away=True, status_text="on vacation"),
|
||||
)
|
||||
|
||||
# Now revoke "away" status.
|
||||
self.update_status_and_assert_event(
|
||||
payload=dict(away=orjson.dumps(False).decode()),
|
||||
|
|
|
@ -8,6 +8,7 @@ from django.utils.translation import gettext as _
|
|||
|
||||
from zerver.decorator import human_users_only
|
||||
from zerver.lib.actions import do_update_user_status, update_user_presence
|
||||
from zerver.lib.emoji import check_emoji_request, emoji_name_to_emoji_code
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.presence import get_presence_for_user, get_presence_response
|
||||
from zerver.lib.request import REQ, get_request_notes, has_request_variables
|
||||
|
@ -18,6 +19,7 @@ from zerver.models import (
|
|||
UserActivity,
|
||||
UserPresence,
|
||||
UserProfile,
|
||||
UserStatus,
|
||||
get_active_user,
|
||||
get_active_user_profile_by_id_in_realm,
|
||||
)
|
||||
|
@ -68,14 +70,50 @@ def update_user_status_backend(
|
|||
user_profile: UserProfile,
|
||||
away: Optional[bool] = REQ(json_validator=check_bool, default=None),
|
||||
status_text: Optional[str] = REQ(str_validator=check_capped_string(60), default=None),
|
||||
emoji_name: Optional[str] = REQ(default=None),
|
||||
emoji_code: Optional[str] = REQ(default=None),
|
||||
# TODO: emoji_type is the more appropriate name for this parameter, but changing
|
||||
# that requires nontrivial work on the API documentation, since it's not clear
|
||||
# that the reactions endpoint would prefer such a change.
|
||||
emoji_type: Optional[str] = REQ("reaction_type", default=None),
|
||||
) -> HttpResponse:
|
||||
|
||||
if status_text is not None:
|
||||
status_text = status_text.strip()
|
||||
|
||||
if (away is None) and (status_text is None):
|
||||
if (away is None) and (status_text is None) and (emoji_name is None):
|
||||
raise JsonableError(_("Client did not pass any new values."))
|
||||
|
||||
if emoji_name == "":
|
||||
# Reset the emoji_code and reaction_type if emoji_name is empty.
|
||||
# This should clear the user's configured emoji.
|
||||
emoji_code = ""
|
||||
emoji_type = UserStatus.UNICODE_EMOJI
|
||||
|
||||
elif emoji_name is not None:
|
||||
if emoji_code is None:
|
||||
# The emoji_code argument is only required for rare corner
|
||||
# cases discussed in the long block comment below. For simple
|
||||
# API clients, we allow specifying just the name, and just
|
||||
# look up the code using the current name->code mapping.
|
||||
emoji_code = emoji_name_to_emoji_code(user_profile.realm, emoji_name)[0]
|
||||
|
||||
if emoji_type is None:
|
||||
emoji_type = emoji_name_to_emoji_code(user_profile.realm, emoji_name)[1]
|
||||
|
||||
elif emoji_type or emoji_code:
|
||||
raise JsonableError(
|
||||
_("Client must pass emoji_name if they pass either emoji_code or reaction_type.")
|
||||
)
|
||||
|
||||
# If we're asking to set an emoji (not clear it ("") or not adjust
|
||||
# it (None)), we need to verify the emoji is valid.
|
||||
if emoji_name not in ["", None]:
|
||||
assert emoji_name is not None
|
||||
assert emoji_code is not None
|
||||
assert emoji_type is not None
|
||||
check_emoji_request(user_profile.realm, emoji_name, emoji_code, emoji_type)
|
||||
|
||||
client = get_request_notes(request).client
|
||||
assert client is not None
|
||||
do_update_user_status(
|
||||
|
@ -83,6 +121,9 @@ def update_user_status_backend(
|
|||
away=away,
|
||||
status_text=status_text,
|
||||
client_id=client.id,
|
||||
emoji_name=emoji_name,
|
||||
emoji_code=emoji_code,
|
||||
reaction_type=emoji_type,
|
||||
)
|
||||
|
||||
return json_success()
|
||||
|
|
Loading…
Reference in New Issue