diff --git a/res/templates/notif.html b/res/templates/notif.html
index 648ff034b3..aee52ec8c9 100644
--- a/res/templates/notif.html
+++ b/res/templates/notif.html
@@ -1,7 +1,8 @@
- {{ summaryText }}
+ Hi {{ user_display_name }},
+ {{ summary_text }}
{% for room in rooms %}
{% include 'room.html' with context %}
diff --git a/synapse/push/mailer.py b/synapse/push/mailer.py
index 9212d36b84..9e2297a03b 100644
--- a/synapse/push/mailer.py
+++ b/synapse/push/mailer.py
@@ -21,11 +21,19 @@ import email.mime.multipart
from email.mime.text import MIMEText
from synapse.util.async import concurrently_execute
-from synapse.util.room_name import calculate_room_name
+from synapse.util.presentable_names import calculate_room_name, name_from_member_event
+from synapse.types import UserID
+from synapse.api.errors import StoreError
import jinja2
+MESSAGE_FROM_PERSON_IN_ROOM = "You have a message from %s in the %s room"
+MESSAGE_FROM_PERSON = "You have a message from %s"
+MESSAGES_IN_ROOM = "There are some messages for you in the %s room"
+MESSAGES_IN_ROOMS = "Here are some messages you may have missed"
+
+
class Mailer(object):
def __init__(self, hs):
self.hs = hs
@@ -55,6 +63,13 @@ class Mailer(object):
# notifications
state_by_room = {}
+ try:
+ user_display_name = yield self.store.get_profile_displayname(
+ UserID.from_string(user_id).localpart
+ )
+ except StoreError:
+ user_display_name = user_id
+
@defer.inlineCallbacks
def _fetch_room_state(room_id):
room_state = yield self.state_handler.get_current_state(room_id)
@@ -70,8 +85,14 @@ class Mailer(object):
) for r in rooms_in_order
]
+ summary_text = yield self.make_summary_text(
+ notifs_by_room, state_by_room, user_id
+ )
+
template_vars = {
+ "user_display_name": user_display_name,
"unsubscribe_link": self.make_unsubscribe_link(),
+ "summary_text": summary_text,
"rooms": rooms,
}
@@ -93,6 +114,38 @@ class Mailer(object):
room_vars['title'] = calculate_room_name(room_state, user_id)
return room_vars
+ @defer.inlineCallbacks
+ def make_summary_text(self, notifs_by_room, state_by_room, user_id):
+ if len(notifs_by_room) == 1:
+ room_id = notifs_by_room.keys()[0]
+ sender_name = None
+ if len(notifs_by_room[room_id]) == 1:
+ # 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 = calculate_room_name(
+ state_by_room[room_id], user_id, fallback_to_members=False
+ )
+ event = yield self.store.get_event(
+ 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 % (sender_name, room_name)
+ )
+ elif sender_name is not None:
+ defer.returnValue(MESSAGE_FROM_PERSON % (sender_name,))
+ else:
+ room_name = calculate_room_name(state_by_room[room_id], user_id)
+ defer.returnValue(MESSAGES_IN_ROOM % (room_name,))
+ else:
+ defer.returnValue(MESSAGES_IN_ROOMS)
+
+ defer.returnValue("Some thing have occurred in some rooms")
+
def make_unsubscribe_link(self):
return "https://vector.im/#/settings" # XXX: matrix.to
@@ -104,4 +157,4 @@ def deduped_ordered_list(l):
if item not in seen:
seen.add(item)
ret.append(item)
- return ret
\ No newline at end of file
+ return ret
diff --git a/synapse/util/room_name.py b/synapse/util/presentable_names.py
similarity index 91%
rename from synapse/util/room_name.py
rename to synapse/util/presentable_names.py
index f55ef293b6..2ae01e453d 100644
--- a/synapse/util/room_name.py
+++ b/synapse/util/presentable_names.py
@@ -22,7 +22,7 @@ ALIAS_RE = re.compile(r"^#.*:.+$")
ALL_ALONE = "Empty Room"
-def calculate_room_name(room_state, user_id):
+def calculate_room_name(room_state, user_id, fallback_to_members=True):
# does it have a name?
if ("m.room.name", "") in room_state:
m_room_name = room_state[("m.room.name", "")]
@@ -34,13 +34,13 @@ def calculate_room_name(room_state, user_id):
canon_alias = room_state[("m.room.canonical_alias", "")]
if (
canon_alias.content and canon_alias.content["alias"] and
- looks_like_an_alias(canon_alias.content["alias"])
+ _looks_like_an_alias(canon_alias.content["alias"])
):
return canon_alias.content["alias"]
# at this point we're going to need to search the state by all state keys
# for an event type, so rearrange the data structure
- room_state_bytype = state_as_two_level_dict(room_state)
+ room_state_bytype = _state_as_two_level_dict(room_state)
# right then, any aliases at all?
if "m.room.aliases" in room_state_bytype:
@@ -49,7 +49,7 @@ def calculate_room_name(room_state, user_id):
first_alias_event = m_room_aliases.values()[0]
if first_alias_event.content and first_alias_event.content["aliases"]:
the_aliases = first_alias_event.content["aliases"]
- if len(the_aliases) > 0 and looks_like_an_alias(the_aliases[0]):
+ if len(the_aliases) > 0 and _looks_like_an_alias(the_aliases[0]):
return the_aliases[0]
my_member_event = None
@@ -66,6 +66,9 @@ def calculate_room_name(room_state, user_id):
else:
return "Room Invite"
+ if not fallback_to_members:
+ return None
+
# we're going to have to generate a name based on who's in the room,
# so find out who is in the room that isn't the user.
if "m.room.member" in room_state_bytype:
@@ -105,17 +108,6 @@ def calculate_room_name(room_state, user_id):
return descriptor_from_member_events(other_members)
-def state_as_two_level_dict(state):
- ret = {}
- for k, v in state.items():
- ret.setdefault(k[0], {})[k[1]] = v
- return ret
-
-
-def looks_like_an_alias(string):
- return ALIAS_RE.match(string) is not None
-
-
def descriptor_from_member_events(member_events):
if len(member_events) == 0:
return "nobody"
@@ -139,4 +131,15 @@ def name_from_member_event(member_event):
member_event.content["displayname"]
):
return member_event.content["displayname"]
- return member_event.state_key
\ No newline at end of file
+ return member_event.state_key
+
+
+def _state_as_two_level_dict(state):
+ ret = {}
+ for k, v in state.items():
+ ret.setdefault(k[0], {})[k[1]] = v
+ return ret
+
+
+def _looks_like_an_alias(string):
+ return ALIAS_RE.match(string) is not None
\ No newline at end of file