diff --git a/zerver/lib/display_recipient.py b/zerver/lib/display_recipient.py index 656f15ac8a..1ea9af19fa 100644 --- a/zerver/lib/display_recipient.py +++ b/zerver/lib/display_recipient.py @@ -1,10 +1,10 @@ -from typing import Any, Dict, List, Optional, Set, Tuple, Union +from typing import Dict, List, Optional, Set, Tuple +from zerver.lib.types import DisplayRecipientCacheT, UserDisplayRecipient from zerver.lib.cache import cache_with_key, display_recipient_cache_key, generic_bulk_cached_fetch, \ display_recipient_bulk_get_users_by_id_cache_key from zerver.models import Recipient, Stream, UserProfile, bulk_get_huddle_user_ids -DisplayRecipientCacheT = Union[str, List[Dict[str, Any]]] @cache_with_key(lambda *args: display_recipient_cache_key(args[0]), timeout=3600*24*7) def get_display_recipient_remote_cache(recipient_id: int, recipient_type: int, @@ -27,7 +27,7 @@ def get_display_recipient_remote_cache(recipient_id: int, recipient_type: int, .order_by('id')) return [user_profile_to_display_recipient_dict(user_profile) for user_profile in user_profile_list] -def user_profile_to_display_recipient_dict(user_profile: 'UserProfile') -> Dict[str, Any]: +def user_profile_to_display_recipient_dict(user_profile: 'UserProfile') -> UserDisplayRecipient: return {'email': user_profile.email, 'full_name': user_profile.full_name, 'short_name': user_profile.short_name, @@ -133,7 +133,7 @@ def bulk_fetch_display_recipients(recipient_tuples: Set[Tuple[int, int, int]] return result def personal_and_huddle_cache_transformer(db_object: Tuple[int, List[UserProfile]] - ) -> List[Dict[str, Any]]: + ) -> List[UserDisplayRecipient]: """ Takes an element of the list returned by the query_function, maps it to the final display_recipient list. @@ -149,7 +149,7 @@ def bulk_fetch_display_recipients(recipient_tuples: Set[Tuple[int, int, int]] return db_object[0] # ItemT = Tuple[int, List[UserProfile]] (recipient_id, list of corresponding users) - # CacheItemT = List[Dict[str, Any]] (display_recipient list) + # CacheItemT = List[UserDisplayRecipient] (display_recipient list) # ObjKT = int (recipient_id) personal_and_huddle_display_recipients = generic_bulk_cached_fetch( cache_key_function=display_recipient_cache_key, diff --git a/zerver/lib/email_notifications.py b/zerver/lib/email_notifications.py index 49dbe1cbb1..41c67811d1 100644 --- a/zerver/lib/email_notifications.py +++ b/zerver/lib/email_notifications.py @@ -1,4 +1,5 @@ from typing import Any, Dict, Iterable, List, Optional, Tuple, Union +from zerver.lib.types import UserDisplayRecipient from confirmation.models import one_click_unsubscribe_link from django.conf import settings @@ -250,7 +251,7 @@ def build_message_list(user_profile: UserProfile, messages: List[Message]) -> Li return messages_to_render def get_narrow_url(user_profile: UserProfile, message: Message, - display_recipient: Optional[Union[str, List[Dict[str, Any]]]]=None, + display_recipient: Optional[Union[str, List[UserDisplayRecipient]]]=None, stream: Optional[Stream]=None) -> str: """The display_recipient and stream arguments are optional. If not provided, we'll compute them from the message; they exist as a diff --git a/zerver/lib/message.py b/zerver/lib/message.py index dbdad3a020..8aa8eb4246 100644 --- a/zerver/lib/message.py +++ b/zerver/lib/message.py @@ -18,7 +18,8 @@ from zerver.lib.cache import ( to_dict_cache_key, to_dict_cache_key_id, ) -from zerver.lib.display_recipient import DisplayRecipientCacheT, bulk_fetch_display_recipients +from zerver.lib.display_recipient import UserDisplayRecipient, DisplayRecipientCacheT, \ + bulk_fetch_display_recipients from zerver.lib.request import JsonableError from zerver.lib.stream_subscription import ( get_stream_subscriptions_for_user, @@ -448,7 +449,7 @@ class MessageDict: 'full_name': sender_full_name, 'short_name': sender_short_name, 'id': sender_id, - 'is_mirror_dummy': sender_is_mirror_dummy} + 'is_mirror_dummy': sender_is_mirror_dummy} # type: UserDisplayRecipient if recip['email'] < display_recipient[0]['email']: display_recipient = [recip, display_recipient[0]] elif recip['email'] > display_recipient[0]['email']: @@ -666,7 +667,7 @@ def do_render_markdown(message: Message, def huddle_users(recipient_id: int) -> str: display_recipient = get_display_recipient_by_id(recipient_id, Recipient.HUDDLE, - None) # type: Union[str, List[Dict[str, Any]]] + None) # type: Union[str, List[UserDisplayRecipient]] # str is for streams. assert not isinstance(display_recipient, str) diff --git a/zerver/lib/types.py b/zerver/lib/types.py index 2133dd8b55..490c9008d8 100644 --- a/zerver/lib/types.py +++ b/zerver/lib/types.py @@ -27,3 +27,7 @@ ExtendedFieldElement = Tuple[int, str, ExtendedValidator, Callable[[Any], Any], UserFieldElement = Tuple[int, str, RealmUserValidator, Callable[[Any], Any], str] ProfileFieldData = Dict[str, Union[Dict[str, str], str]] + +UserDisplayRecipient = TypedDict('UserDisplayRecipient', {'email': str, 'full_name': str, 'short_name': str, + 'id': int, 'is_mirror_dummy': bool}) +DisplayRecipientCacheT = Union[str, List[UserDisplayRecipient]] diff --git a/zerver/models.py b/zerver/models.py index 7b10806b80..c054c025ad 100644 --- a/zerver/models.py +++ b/zerver/models.py @@ -36,7 +36,8 @@ from zerver.lib.validator import check_int, \ from zerver.lib.name_restrictions import is_disposable_domain from zerver.lib.types import Validator, ExtendedValidator, \ ProfileDataElement, ProfileData, RealmUserValidator, \ - ExtendedFieldElement, UserFieldElement, FieldElement + ExtendedFieldElement, UserFieldElement, FieldElement, \ + UserDisplayRecipient from bitfield import BitField from bitfield.types import BitHandler @@ -80,9 +81,9 @@ def query_for_ids(query: QuerySet, user_ids: List[int], field: str) -> QuerySet: # could be replaced with smarter bulk-fetching logic that deduplicates # queries for the same recipient; this is just a convenient way to # write that code. -per_request_display_recipient_cache = {} # type: Dict[int, Union[str, List[Dict[str, Any]]]] +per_request_display_recipient_cache = {} # type: Dict[int, Union[str, List[UserDisplayRecipient]]] def get_display_recipient_by_id(recipient_id: int, recipient_type: int, - recipient_type_id: Optional[int]) -> Union[str, List[Dict[str, Any]]]: + recipient_type_id: Optional[int]) -> Union[str, List[UserDisplayRecipient]]: """ returns: an object describing the recipient (using a cache). If the type is a stream, the type_id must be an int; a string is returned. @@ -96,7 +97,7 @@ def get_display_recipient_by_id(recipient_id: int, recipient_type: int, per_request_display_recipient_cache[recipient_id] = result return per_request_display_recipient_cache[recipient_id] -def get_display_recipient(recipient: 'Recipient') -> Union[str, List[Dict[str, Any]]]: +def get_display_recipient(recipient: 'Recipient') -> Union[str, List[UserDisplayRecipient]]: return get_display_recipient_by_id( recipient.id, recipient.type, diff --git a/zerver/tests/test_messages.py b/zerver/tests/test_messages.py index 7696f62b18..d723bf6928 100644 --- a/zerver/tests/test_messages.py +++ b/zerver/tests/test_messages.py @@ -74,6 +74,7 @@ from zerver.lib.topic import ( DB_TOPIC_NAME, ) +from zerver.lib.types import UserDisplayRecipient from zerver.lib.soft_deactivation import ( add_missing_messages, do_soft_activate_users, @@ -4207,8 +4208,11 @@ class MessageHydrationTest(ZulipTestCase): dict( email='aaron@example.com', full_name='Aaron Smith', + short_name='Aaron', + id=999, + is_mirror_dummy=False ), - ] + ] # type: List[UserDisplayRecipient] obj = dict( recipient_type=Recipient.PERSONAL, @@ -4228,6 +4232,9 @@ class MessageHydrationTest(ZulipTestCase): dict( email='aaron@example.com', full_name='Aaron Smith', + short_name='Aaron', + id=999, + is_mirror_dummy=False ), dict( email=cordelia.email, @@ -4328,7 +4335,7 @@ class MessageHydrationTest(ZulipTestCase): self.assertEqual(cordelia_display_recipient['email'], cordelia_new_email) class TestMessageForIdsDisplayRecipientFetching(ZulipTestCase): - def _verify_display_recipient(self, display_recipient: Union[str, List[Dict[str, Any]]], + def _verify_display_recipient(self, display_recipient: Union[str, List[UserDisplayRecipient]], expected_recipient_objects: Union[Stream, List[UserProfile]]) -> None: if isinstance(expected_recipient_objects, Stream): self.assertEqual(display_recipient, expected_recipient_objects.name) @@ -4339,7 +4346,7 @@ class TestMessageForIdsDisplayRecipientFetching(ZulipTestCase): 'full_name': user_profile.full_name, 'short_name': user_profile.short_name, 'id': user_profile.id, - 'is_mirror_dummy': user_profile.is_mirror_dummy} + 'is_mirror_dummy': user_profile.is_mirror_dummy} # type: UserDisplayRecipient self.assertTrue(recipient_dict in display_recipient) def test_display_recipient_personal(self) -> None: diff --git a/zerver/tests/test_narrow.py b/zerver/tests/test_narrow.py index 47fc8225b9..d1d06869d1 100644 --- a/zerver/tests/test_narrow.py +++ b/zerver/tests/test_narrow.py @@ -37,6 +37,7 @@ from zerver.lib.topic import ( from zerver.lib.topic_mutes import ( set_topic_mutes, ) +from zerver.lib.types import UserDisplayRecipient from zerver.views.messages import ( exclude_muting_conditions, get_messages_backend, ok_to_include_history, @@ -1068,11 +1069,11 @@ class GetOldMessagesTest(ZulipTestCase): """ me = self.example_email('hamlet') - def dr_emails(dr: Union[str, List[Dict[str, Any]]]) -> str: + def dr_emails(dr: Union[str, List[UserDisplayRecipient]]) -> str: assert isinstance(dr, list) return ','.join(sorted(set([r['email'] for r in dr] + [me]))) - def dr_ids(dr: Union[str, List[Dict[str, Any]]]) -> List[int]: + def dr_ids(dr: Union[str, List[UserDisplayRecipient]]) -> List[int]: assert isinstance(dr, list) return list(sorted(set([r['id'] for r in dr] + [self.example_user('hamlet').id])))