def get_message_vars(self, notif, event, room_state_ids): if event.type != EventTypes.Message: return sender_state_event_id = room_state_ids[("m.room.member", event.sender)] sender_state_event = yield self.store.get_event(sender_state_event_id) sender_name = name_from_member_event(sender_state_event) sender_avatar_url = sender_state_event.content.get("avatar_url") # 'hash' for deterministically picking default images: use # sender_hash % the number of default images to choose from sender_hash = string_ordinal_total(event.sender) msgtype = event.content.get("msgtype") ret = { "msgtype": msgtype, "is_historical": event.event_id != notif['event_id'], "id": event.event_id, "ts": event.origin_server_ts, "sender_name": sender_name, "sender_avatar_url": sender_avatar_url, "sender_hash": sender_hash, } if msgtype == "m.text": self.add_text_message_vars(ret, event) elif msgtype == "m.image": self.add_image_message_vars(ret, event) if "body" in event.content: ret["body_text_plain"] = event.content["body"] defer.returnValue(ret)
def get_context_for_event(store, state_handler, ev, user_id): ctx = {} room_state_ids = yield store.get_state_ids_for_event(ev.event_id) # we no longer bother setting room_alias, and make room_name the # human-readable name instead, be that m.room.name, an alias or # a list of people in the room name = yield calculate_room_name( store, room_state_ids, user_id, fallback_to_single_member=False ) if name: ctx["name"] = name sender_state_event_id = room_state_ids[("m.room.member", ev.sender)] sender_state_event = yield store.get_event(sender_state_event_id) ctx["sender_display_name"] = name_from_member_event(sender_state_event) return ctx
def get_context_for_event(store, state_handler, ev, user_id): ctx = {} room_state_ids = yield state_handler.get_current_state_ids(ev.room_id) # we no longer bother setting room_alias, and make room_name the # human-readable name instead, be that m.room.name, an alias or # a list of people in the room name = yield calculate_room_name( store, room_state_ids, user_id, fallback_to_single_member=False ) if name: ctx['name'] = name sender_state_event_id = room_state_ids[("m.room.member", ev.sender)] sender_state_event = yield store.get_event(sender_state_event_id) ctx['sender_display_name'] = name_from_member_event(sender_state_event) defer.returnValue(ctx)
async def get_message_vars( self, notif: Dict[str, Any], event: EventBase, room_state_ids: StateMap[str]) -> Optional[Dict[str, Any]]: if event.type != EventTypes.Message and event.type != EventTypes.Encrypted: return None sender_state_event_id = room_state_ids[("m.room.member", event.sender)] sender_state_event = await self.store.get_event(sender_state_event_id) sender_name = name_from_member_event(sender_state_event) sender_avatar_url = sender_state_event.content.get("avatar_url") # 'hash' for deterministically picking default images: use # sender_hash % the number of default images to choose from sender_hash = string_ordinal_total(event.sender) ret = { "event_type": event.type, "is_historical": event.event_id != notif["event_id"], "id": event.event_id, "ts": event.origin_server_ts, "sender_name": sender_name, "sender_avatar_url": sender_avatar_url, "sender_hash": sender_hash, } # Encrypted messages don't have any additional useful information. if event.type == EventTypes.Encrypted: return ret msgtype = event.content.get("msgtype") ret["msgtype"] = msgtype if msgtype == "m.text": self.add_text_message_vars(ret, event) elif msgtype == "m.image": self.add_image_message_vars(ret, event) if "body" in event.content: ret["body_text_plain"] = event.content["body"] return ret
async def get_context_for_event(storage: Storage, ev: EventBase, user_id: str) -> Dict[str, str]: ctx = {} room_state_ids = await storage.state.get_state_ids_for_event(ev.event_id) # we no longer bother setting room_alias, and make room_name the # human-readable name instead, be that m.room.name, an alias or # a list of people in the room name = await calculate_room_name(storage.main, room_state_ids, user_id, fallback_to_single_member=False) if name: ctx["name"] = name sender_state_event_id = room_state_ids[("m.room.member", ev.sender)] sender_state_event = await storage.main.get_event(sender_state_event_id) ctx["sender_display_name"] = name_from_member_event(sender_state_event) return ctx
def make_summary_text(self, notifs_by_room, room_state_ids, notif_events, user_id, reason): if len(notifs_by_room) == 1: # Only one room has new stuff room_id = notifs_by_room.keys()[0] # If the room has some kind of name, use it, but we don't # want the generated-from-names one here otherwise we'll # end up with, "new message from Bob in the Bob room" room_name = yield calculate_room_name(self.store, room_state_ids[room_id], user_id, fallback_to_members=False) my_member_event_id = room_state_ids[room_id][("m.room.member", user_id)] my_member_event = yield self.store.get_event(my_member_event_id) if my_member_event.content["membership"] == "invite": inviter_member_event_id = room_state_ids[room_id][( "m.room.member", my_member_event.sender)] inviter_member_event = yield self.store.get_event( inviter_member_event_id) inviter_name = name_from_member_event(inviter_member_event) if room_name is None: defer.returnValue(INVITE_FROM_PERSON % { "person": inviter_name, "app": self.app_name }) else: defer.returnValue( INVITE_FROM_PERSON_TO_ROOM % { "person": inviter_name, "room": room_name, "app": self.app_name, }) sender_name = None if len(notifs_by_room[room_id]) == 1: # There is just the one notification, so give some detail event = notif_events[notifs_by_room[room_id][0]["event_id"]] if ("m.room.member", event.sender) in room_state_ids[room_id]: state_event_id = room_state_ids[room_id][("m.room.member", event.sender)] state_event = yield self.store.get_event(state_event_id) sender_name = name_from_member_event(state_event) if sender_name is not None and room_name is not None: defer.returnValue( MESSAGE_FROM_PERSON_IN_ROOM % { "person": sender_name, "room": room_name, "app": self.app_name, }) elif sender_name is not None: defer.returnValue(MESSAGE_FROM_PERSON % { "person": sender_name, "app": self.app_name, }) else: # There's more than one notification for this room, so just # say there are several if room_name is not None: defer.returnValue(MESSAGES_IN_ROOM % { "room": room_name, "app": self.app_name, }) else: # If the room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" sender_ids = list( set([ notif_events[n['event_id']].sender for n in notifs_by_room[room_id] ])) member_events = yield self.store.get_events([ room_state_ids[room_id][("m.room.member", s)] for s in sender_ids ]) defer.returnValue( MESSAGES_FROM_PERSON % { "person": descriptor_from_member_events( member_events.values()), "app": self.app_name, }) else: # Stuff's happened in multiple different rooms # ...but we still refer to the 'reason' room which triggered the mail if reason['room_name'] is not None: defer.returnValue(MESSAGES_IN_ROOM_AND_OTHERS % { "room": reason['room_name'], "app": self.app_name, }) else: # If the reason room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" sender_ids = list( set([ notif_events[n['event_id']].sender for n in notifs_by_room[reason['room_id']] ])) member_events = yield self.store.get_events([ room_state_ids[room_id][("m.room.member", s)] for s in sender_ids ]) defer.returnValue( MESSAGES_FROM_PERSON_AND_OTHERS % { "person": descriptor_from_member_events(member_events.values()), "app": self.app_name, })
async def make_summary_text( self, notifs_by_room, room_state_ids, notif_events, user_id, reason ): if len(notifs_by_room) == 1: # Only one room has new stuff room_id = list(notifs_by_room.keys())[0] # If the room has some kind of name, use it, but we don't # want the generated-from-names one here otherwise we'll # end up with, "new message from Bob in the Bob room" room_name = await calculate_room_name( self.store, room_state_ids[room_id], user_id, fallback_to_members=False ) my_member_event_id = room_state_ids[room_id][("m.room.member", user_id)] my_member_event = await self.store.get_event(my_member_event_id) if my_member_event.content["membership"] == "invite": inviter_member_event_id = room_state_ids[room_id][ ("m.room.member", my_member_event.sender) ] inviter_member_event = await self.store.get_event( inviter_member_event_id ) inviter_name = name_from_member_event(inviter_member_event) if room_name is None: return self.email_subjects.invite_from_person % { "person": inviter_name, "app": self.app_name, } else: return self.email_subjects.invite_from_person_to_room % { "person": inviter_name, "room": room_name, "app": self.app_name, } sender_name = None if len(notifs_by_room[room_id]) == 1: # There is just the one notification, so give some detail event = notif_events[notifs_by_room[room_id][0]["event_id"]] if ("m.room.member", event.sender) in room_state_ids[room_id]: state_event_id = room_state_ids[room_id][ ("m.room.member", event.sender) ] state_event = await self.store.get_event(state_event_id) sender_name = name_from_member_event(state_event) if sender_name is not None and room_name is not None: return self.email_subjects.message_from_person_in_room % { "person": sender_name, "room": room_name, "app": self.app_name, } elif sender_name is not None: return self.email_subjects.message_from_person % { "person": sender_name, "app": self.app_name, } else: # There's more than one notification for this room, so just # say there are several if room_name is not None: return self.email_subjects.messages_in_room % { "room": room_name, "app": self.app_name, } else: # If the room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" sender_ids = list( { notif_events[n["event_id"]].sender for n in notifs_by_room[room_id] } ) member_events = await self.store.get_events( [ room_state_ids[room_id][("m.room.member", s)] for s in sender_ids ] ) return self.email_subjects.messages_from_person % { "person": descriptor_from_member_events(member_events.values()), "app": self.app_name, } else: # Stuff's happened in multiple different rooms # ...but we still refer to the 'reason' room which triggered the mail if reason["room_name"] is not None: return self.email_subjects.messages_in_room_and_others % { "room": reason["room_name"], "app": self.app_name, } else: # If the reason room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" room_id = reason["room_id"] sender_ids = list( { notif_events[n["event_id"]].sender for n in notifs_by_room[room_id] } ) member_events = await self.store.get_events( [room_state_ids[room_id][("m.room.member", s)] for s in sender_ids] ) return self.email_subjects.messages_from_person_and_others % { "person": descriptor_from_member_events(member_events.values()), "app": self.app_name, }
async def _make_summary_text_single_room( self, room_id: str, notifs: List[EmailPushAction], room_state_ids: StateMap[str], notif_events: Dict[str, EventBase], user_id: str, ) -> str: """ Make a summary text for the email when only a single room has notifications. Args: room_id: The ID of the room. notifs: The push actions for this room. room_state_ids: The state map for the room. notif_events: A map of event ID -> notification event. user_id: The user receiving the notification. Returns: The summary text. """ # If the room has some kind of name, use it, but we don't # want the generated-from-names one here otherwise we'll # end up with, "new message from Bob in the Bob room" room_name = await calculate_room_name(self.store, room_state_ids, user_id, fallback_to_members=False) # See if one of the notifs is an invite event for the user invite_event = None for n in notifs: ev = notif_events[n.event_id] if ev.type == EventTypes.Member and ev.state_key == user_id: if ev.content.get("membership") == Membership.INVITE: invite_event = ev break if invite_event: inviter_member_event_id = room_state_ids.get( ("m.room.member", invite_event.sender)) inviter_name = invite_event.sender if inviter_member_event_id: inviter_member_event = await self.store.get_event( inviter_member_event_id, allow_none=True) if inviter_member_event: inviter_name = name_from_member_event(inviter_member_event) if room_name is None: return self.email_subjects.invite_from_person % { "person": inviter_name, "app": self.app_name, } # If the room is a space, it gets a slightly different topic. create_event_id = room_state_ids.get(("m.room.create", "")) if create_event_id: create_event = await self.store.get_event(create_event_id, allow_none=True) if (create_event and create_event.content.get("room_type") == RoomTypes.SPACE): return self.email_subjects.invite_from_person_to_space % { "person": inviter_name, "space": room_name, "app": self.app_name, } return self.email_subjects.invite_from_person_to_room % { "person": inviter_name, "room": room_name, "app": self.app_name, } if len(notifs) == 1: # There is just the one notification, so give some detail sender_name = None event = notif_events[notifs[0].event_id] if ("m.room.member", event.sender) in room_state_ids: state_event_id = room_state_ids[("m.room.member", event.sender)] state_event = await self.store.get_event(state_event_id) sender_name = name_from_member_event(state_event) if sender_name is not None and room_name is not None: return self.email_subjects.message_from_person_in_room % { "person": sender_name, "room": room_name, "app": self.app_name, } elif sender_name is not None: return self.email_subjects.message_from_person % { "person": sender_name, "app": self.app_name, } # The sender is unknown, just use the room name (or ID). return self.email_subjects.messages_in_room % { "room": room_name or room_id, "app": self.app_name, } else: # There's more than one notification for this room, so just # say there are several if room_name is not None: return self.email_subjects.messages_in_room % { "room": room_name, "app": self.app_name, } return await self._make_summary_text_from_member_events( room_id, notifs, room_state_ids, notif_events)
async def _get_message_vars( self, notif: EmailPushAction, event: EventBase, room_state_ids: StateMap[str]) -> Optional[MessageVars]: """ Generate the variables for a single event, if possible. Args: notif: The outstanding notification for this room. event: The event under consideration. room_state_ids: The event IDs of the current room state. Returns: A dictionary to be added to the template context, or None if the event cannot be processed. """ if event.type != EventTypes.Message and event.type != EventTypes.Encrypted: return None # Get the sender's name and avatar from the room state. type_state_key = ("m.room.member", event.sender) sender_state_event_id = room_state_ids.get(type_state_key) if sender_state_event_id: sender_state_event: Optional[ EventBase] = await self.store.get_event(sender_state_event_id) else: # Attempt to check the historical state for the room. historical_state = await self._state_storage_controller.get_state_for_event( event.event_id, StateFilter.from_types((type_state_key, ))) sender_state_event = historical_state.get(type_state_key) if sender_state_event: sender_name = name_from_member_event(sender_state_event) sender_avatar_url: Optional[str] = sender_state_event.content.get( "avatar_url") else: # No state could be found, fallback to the MXID. sender_name = event.sender sender_avatar_url = None # 'hash' for deterministically picking default images: use # sender_hash % the number of default images to choose from sender_hash = string_ordinal_total(event.sender) ret: MessageVars = { "event_type": event.type, "is_historical": event.event_id != notif.event_id, "id": event.event_id, "ts": event.origin_server_ts, "sender_name": sender_name, "sender_avatar_url": sender_avatar_url, "sender_hash": sender_hash, } # Encrypted messages don't have any additional useful information. if event.type == EventTypes.Encrypted: return ret msgtype = event.content.get("msgtype") if not isinstance(msgtype, str): msgtype = None ret["msgtype"] = msgtype if msgtype == "m.text": self._add_text_message_vars(ret, event) elif msgtype == "m.image": self._add_image_message_vars(ret, event) if "body" in event.content: ret["body_text_plain"] = event.content["body"] return ret
async def make_summary_text( self, notifs_by_room: Dict[str, List[Dict[str, Any]]], room_state_ids: Dict[str, StateMap[str]], notif_events: Dict[str, EventBase], user_id: str, reason: Dict[str, Any], ): if len(notifs_by_room) == 1: # Only one room has new stuff room_id = list(notifs_by_room.keys())[0] # If the room has some kind of name, use it, but we don't # want the generated-from-names one here otherwise we'll # end up with, "new message from Bob in the Bob room" room_name = await calculate_room_name(self.store, room_state_ids[room_id], user_id, fallback_to_members=False) # See if one of the notifs is an invite event for the user invite_event = None for n in notifs_by_room[room_id]: ev = notif_events[n["event_id"]] if ev.type == EventTypes.Member and ev.state_key == user_id: if ev.content.get("membership") == Membership.INVITE: invite_event = ev break if invite_event: inviter_member_event_id = room_state_ids[room_id].get( ("m.room.member", invite_event.sender)) inviter_name = invite_event.sender if inviter_member_event_id: inviter_member_event = await self.store.get_event( inviter_member_event_id, allow_none=True) if inviter_member_event: inviter_name = name_from_member_event( inviter_member_event) if room_name is None: return self.email_subjects.invite_from_person % { "person": inviter_name, "app": self.app_name, } else: return self.email_subjects.invite_from_person_to_room % { "person": inviter_name, "room": room_name, "app": self.app_name, } sender_name = None if len(notifs_by_room[room_id]) == 1: # There is just the one notification, so give some detail event = notif_events[notifs_by_room[room_id][0]["event_id"]] if ("m.room.member", event.sender) in room_state_ids[room_id]: state_event_id = room_state_ids[room_id][("m.room.member", event.sender)] state_event = await self.store.get_event(state_event_id) sender_name = name_from_member_event(state_event) if sender_name is not None and room_name is not None: return self.email_subjects.message_from_person_in_room % { "person": sender_name, "room": room_name, "app": self.app_name, } elif sender_name is not None: return self.email_subjects.message_from_person % { "person": sender_name, "app": self.app_name, } else: # There's more than one notification for this room, so just # say there are several if room_name is not None: return self.email_subjects.messages_in_room % { "room": room_name, "app": self.app_name, } else: # If the room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" sender_ids = list({ notif_events[n["event_id"]].sender for n in notifs_by_room[room_id] }) member_events = await self.store.get_events([ room_state_ids[room_id][("m.room.member", s)] for s in sender_ids ]) return self.email_subjects.messages_from_person % { "person": descriptor_from_member_events(member_events.values()), "app": self.app_name, } else: # Stuff's happened in multiple different rooms # ...but we still refer to the 'reason' room which triggered the mail if reason["room_name"] is not None: return self.email_subjects.messages_in_room_and_others % { "room": reason["room_name"], "app": self.app_name, } else: # If the reason room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" room_id = reason["room_id"] sender_ids = list({ notif_events[n["event_id"]].sender for n in notifs_by_room[room_id] }) member_events = await self.store.get_events([ room_state_ids[room_id][("m.room.member", s)] for s in sender_ids ]) return self.email_subjects.messages_from_person_and_others % { "person": descriptor_from_member_events( member_events.values()), "app": self.app_name, }
def make_summary_text(self, notifs_by_room, state_by_room, notif_events, user_id, reason): if len(notifs_by_room) == 1: # Only one room has new stuff room_id = notifs_by_room.keys()[0] # If the room has some kind of name, use it, but we don't # want the generated-from-names one here otherwise we'll # end up with, "new message from Bob in the Bob room" room_name = yield calculate_room_name( self.store, state_by_room[room_id], user_id, fallback_to_members=False ) my_member_event = state_by_room[room_id][("m.room.member", user_id)] if my_member_event.content["membership"] == "invite": inviter_member_event = state_by_room[room_id][ ("m.room.member", my_member_event.sender) ] inviter_name = name_from_member_event(inviter_member_event) if room_name is None: defer.returnValue(INVITE_FROM_PERSON % { "person": inviter_name, "app": self.app_name }) else: defer.returnValue(INVITE_FROM_PERSON_TO_ROOM % { "person": inviter_name, "room": room_name, "app": self.app_name, }) sender_name = None if len(notifs_by_room[room_id]) == 1: # There is just the one notification, so give some detail event = notif_events[notifs_by_room[room_id][0]["event_id"]] if ("m.room.member", event.sender) in state_by_room[room_id]: state_event = state_by_room[room_id][("m.room.member", event.sender)] sender_name = name_from_member_event(state_event) if sender_name is not None and room_name is not None: defer.returnValue(MESSAGE_FROM_PERSON_IN_ROOM % { "person": sender_name, "room": room_name, "app": self.app_name, }) elif sender_name is not None: defer.returnValue(MESSAGE_FROM_PERSON % { "person": sender_name, "app": self.app_name, }) else: # There's more than one notification for this room, so just # say there are several if room_name is not None: defer.returnValue(MESSAGES_IN_ROOM % { "room": room_name, "app": self.app_name, }) else: # If the room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" sender_ids = list(set([ notif_events[n['event_id']].sender for n in notifs_by_room[room_id] ])) defer.returnValue(MESSAGES_FROM_PERSON % { "person": descriptor_from_member_events([ state_by_room[room_id][("m.room.member", s)] for s in sender_ids ]), "app": self.app_name, }) else: # Stuff's happened in multiple different rooms # ...but we still refer to the 'reason' room which triggered the mail if reason['room_name'] is not None: defer.returnValue(MESSAGES_IN_ROOM_AND_OTHERS % { "room": reason['room_name'], "app": self.app_name, }) else: # If the reason room doesn't have a name, say who the messages # are from explicitly to avoid, "messages in the Bob room" sender_ids = list(set([ notif_events[n['event_id']].sender for n in notifs_by_room[reason['room_id']] ])) defer.returnValue(MESSAGES_FROM_PERSON_AND_OTHERS % { "person": descriptor_from_member_events([ state_by_room[reason['room_id']][("m.room.member", s)] for s in sender_ids ]), "app": self.app_name, })