mirror of https://github.com/zulip/zulip.git
Add custom markdown tag to render a stream subscribe button
When new streams are created we now send a message with a custom markdown tag that renders a subscribe button. (imported from commit 9dfba280b3b4ff4f32f6431ef9227867c8bf4b40)
This commit is contained in:
parent
033e0e5969
commit
c30a411c10
|
@ -507,6 +507,26 @@ class Emoji(markdown.inlinepatterns.Pattern):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
class StreamSubscribeButton(markdown.inlinepatterns.Pattern):
|
||||||
|
# This markdown extension has required javascript in
|
||||||
|
# static/js/custom_markdown.js
|
||||||
|
def handleMatch(self, match):
|
||||||
|
stream_name = match.group('stream_name')
|
||||||
|
stream_name = stream_name.replace('\\)', ')').replace('\\\\', '\\')
|
||||||
|
|
||||||
|
span = markdown.util.etree.Element('span')
|
||||||
|
span.set('class', 'inline-subscribe')
|
||||||
|
span.set('data-stream-name', stream_name)
|
||||||
|
|
||||||
|
button = markdown.util.etree.SubElement(span, 'button')
|
||||||
|
button.text = 'Subscribe to ' + stream_name
|
||||||
|
button.set('class', 'inline-subscribe-button zulip-button')
|
||||||
|
|
||||||
|
error = markdown.util.etree.SubElement(span, 'span')
|
||||||
|
error.set('class', 'inline-subscribe-error')
|
||||||
|
|
||||||
|
return span
|
||||||
|
|
||||||
upload_re = re.compile(r"^(?:https://%s.s3.amazonaws.com|/user_uploads/\d+)/[^/]*/([^/]*)$" % (settings.S3_BUCKET,))
|
upload_re = re.compile(r"^(?:https://%s.s3.amazonaws.com|/user_uploads/\d+)/[^/]*/([^/]*)$" % (settings.S3_BUCKET,))
|
||||||
def url_filename(url):
|
def url_filename(url):
|
||||||
"""Extract the filename if a URL is an uploaded file, or return the original URL"""
|
"""Extract the filename if a URL is an uploaded file, or return the original URL"""
|
||||||
|
@ -791,6 +811,8 @@ class Bugdown(markdown.Extension):
|
||||||
md.inlinePatterns.add('avatar', Avatar(r'!avatar\((?P<email>[^)]*)\)'), '_begin')
|
md.inlinePatterns.add('avatar', Avatar(r'!avatar\((?P<email>[^)]*)\)'), '_begin')
|
||||||
md.inlinePatterns.add('gravatar', Avatar(r'!gravatar\((?P<email>[^)]*)\)'), '_begin')
|
md.inlinePatterns.add('gravatar', Avatar(r'!gravatar\((?P<email>[^)]*)\)'), '_begin')
|
||||||
|
|
||||||
|
md.inlinePatterns.add('stream_subscribe_button', StreamSubscribeButton(r'!_stream_subscribe_button\((?P<stream_name>(?:[^)\\]|\\\)|\\)*)\)'), '_begin')
|
||||||
|
|
||||||
md.inlinePatterns.add('usermention', UserMentionPattern(mention.find_mentions), '>backtick')
|
md.inlinePatterns.add('usermention', UserMentionPattern(mention.find_mentions), '>backtick')
|
||||||
md.inlinePatterns.add('emoji', Emoji(r'(?<!\w)(?P<syntax>:[^:\s]+:)(?!\w)'), '_end')
|
md.inlinePatterns.add('emoji', Emoji(r'(?<!\w)(?P<syntax>:[^:\s]+:)(?!\w)'), '_end')
|
||||||
md.inlinePatterns.add('link', AtomicLinkPattern(markdown.inlinepatterns.LINK_RE, md), '>backtick')
|
md.inlinePatterns.add('link', AtomicLinkPattern(markdown.inlinepatterns.LINK_RE, md), '>backtick')
|
||||||
|
|
107
zerver/tests.py
107
zerver/tests.py
|
@ -2043,6 +2043,61 @@ class SubscriptionAPITest(AuthedTestCase):
|
||||||
add_streams, self.streams, self.test_email, self.streams + add_streams)
|
add_streams, self.streams, self.test_email, self.streams + add_streams)
|
||||||
self.assertEqual(len(events), 1)
|
self.assertEqual(len(events), 1)
|
||||||
|
|
||||||
|
def test_successful_subscriptions_notifies(self):
|
||||||
|
"""
|
||||||
|
Calling /json/subscriptions/add should notify when a new stream is created.
|
||||||
|
"""
|
||||||
|
invitee = "iago@zulip.com"
|
||||||
|
invitee_full_name = 'Iago'
|
||||||
|
|
||||||
|
current_stream = self.get_streams(invitee)[0]
|
||||||
|
invite_streams = self.make_random_stream_names(current_stream)[:1]
|
||||||
|
result = self.common_subscribe_to_streams(
|
||||||
|
invitee,
|
||||||
|
invite_streams,
|
||||||
|
extra_post_data={
|
||||||
|
'announce': 'true',
|
||||||
|
'principals': '["%s"]' % (self.user_profile.email,)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
msg = Message.objects.latest('id')
|
||||||
|
self.assertEqual(msg.sender_id,
|
||||||
|
get_user_profile_by_email('notification-bot@zulip.com').id)
|
||||||
|
expected_msg = "Hi there! %s just created a new stream '%s'. " \
|
||||||
|
"!_stream_subscribe_button(%s)" % (invitee_full_name,
|
||||||
|
invite_streams[0],
|
||||||
|
invite_streams[0])
|
||||||
|
self.assertEqual(msg.content, expected_msg)
|
||||||
|
|
||||||
|
def test_successful_subscriptions_notifies_with_escaping(self):
|
||||||
|
"""
|
||||||
|
Calling /json/subscriptions/add should notify when a new stream is created.
|
||||||
|
"""
|
||||||
|
invitee = "iago@zulip.com"
|
||||||
|
invitee_full_name = 'Iago'
|
||||||
|
|
||||||
|
invite_streams = ['strange ) \\ test']
|
||||||
|
result = self.common_subscribe_to_streams(
|
||||||
|
invitee,
|
||||||
|
invite_streams,
|
||||||
|
extra_post_data={
|
||||||
|
'announce': 'true',
|
||||||
|
'principals': '["%s"]' % (self.user_profile.email,)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
self.assert_json_success(result)
|
||||||
|
|
||||||
|
msg = Message.objects.latest('id')
|
||||||
|
self.assertEqual(msg.sender_id,
|
||||||
|
get_user_profile_by_email('notification-bot@zulip.com').id)
|
||||||
|
expected_msg = "Hi there! %s just created a new stream '%s'. " \
|
||||||
|
"!_stream_subscribe_button(strange \\) \\\\ test)" % (
|
||||||
|
invitee_full_name,
|
||||||
|
invite_streams[0])
|
||||||
|
self.assertEqual(msg.content, expected_msg)
|
||||||
|
|
||||||
def test_non_ascii_stream_subscription(self):
|
def test_non_ascii_stream_subscription(self):
|
||||||
"""
|
"""
|
||||||
Subscribing to a stream name with non-ASCII characters succeeds.
|
Subscribing to a stream name with non-ASCII characters succeeds.
|
||||||
|
@ -4825,6 +4880,58 @@ Content Cell | Content Cell
|
||||||
|
|
||||||
self.assertEqual(converted, expected)
|
self.assertEqual(converted, expected)
|
||||||
|
|
||||||
|
def test_stream_subscribe_button_simple(self):
|
||||||
|
msg = '!_stream_subscribe_button(simple)'
|
||||||
|
converted = bugdown_convert(msg)
|
||||||
|
self.assertEqual(
|
||||||
|
converted,
|
||||||
|
'<p>'
|
||||||
|
'<span class="inline-subscribe" data-stream-name="simple">'
|
||||||
|
'<button class="inline-subscribe-button zulip-button">Subscribe to simple</button>'
|
||||||
|
'<span class="inline-subscribe-error"></span>'
|
||||||
|
'</span>'
|
||||||
|
'</p>'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_stream_subscribe_button_in_name(self):
|
||||||
|
msg = '!_stream_subscribe_button(simple (not\\))'
|
||||||
|
converted = bugdown_convert(msg)
|
||||||
|
self.assertEqual(
|
||||||
|
converted,
|
||||||
|
'<p>'
|
||||||
|
'<span class="inline-subscribe" data-stream-name="simple (not)">'
|
||||||
|
'<button class="inline-subscribe-button zulip-button">Subscribe to simple (not)</button>'
|
||||||
|
'<span class="inline-subscribe-error"></span>'
|
||||||
|
'</span>'
|
||||||
|
'</p>'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_stream_subscribe_button_after_name(self):
|
||||||
|
msg = '!_stream_subscribe_button(simple) (not)'
|
||||||
|
converted = bugdown_convert(msg)
|
||||||
|
self.assertEqual(
|
||||||
|
converted,
|
||||||
|
'<p>'
|
||||||
|
'<span class="inline-subscribe" data-stream-name="simple">'
|
||||||
|
'<button class="inline-subscribe-button zulip-button">Subscribe to simple</button>'
|
||||||
|
'<span class="inline-subscribe-error"></span>'
|
||||||
|
'</span>'
|
||||||
|
' (not)</p>'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_stream_subscribe_button_slash(self):
|
||||||
|
msg = '!_stream_subscribe_button(simple\\\\)'
|
||||||
|
converted = bugdown_convert(msg)
|
||||||
|
self.assertEqual(
|
||||||
|
converted,
|
||||||
|
'<p>'
|
||||||
|
'<span class="inline-subscribe" data-stream-name="simple\\">'
|
||||||
|
'<button class="inline-subscribe-button zulip-button">Subscribe to simple\\</button>'
|
||||||
|
'<span class="inline-subscribe-error"></span>'
|
||||||
|
'</span>'
|
||||||
|
'</p>'
|
||||||
|
)
|
||||||
|
|
||||||
class UserPresenceTests(AuthedTestCase):
|
class UserPresenceTests(AuthedTestCase):
|
||||||
def test_get_empty(self):
|
def test_get_empty(self):
|
||||||
self.login("hamlet@zulip.com")
|
self.login("hamlet@zulip.com")
|
||||||
|
|
|
@ -1145,6 +1145,11 @@ def stream_link(stream_name):
|
||||||
"Escapes a stream name to make a #narrow/stream/stream_name link"
|
"Escapes a stream name to make a #narrow/stream/stream_name link"
|
||||||
return "#narrow/stream/%s" % (urllib.quote(stream_name.encode('utf-8')),)
|
return "#narrow/stream/%s" % (urllib.quote(stream_name.encode('utf-8')),)
|
||||||
|
|
||||||
|
def stream_button(stream_name):
|
||||||
|
stream_name = stream_name.replace('\\', '\\\\')
|
||||||
|
stream_name = stream_name.replace(')', '\\)')
|
||||||
|
return '!_stream_subscribe_button(%s)' % (stream_name,)
|
||||||
|
|
||||||
@has_request_variables
|
@has_request_variables
|
||||||
def add_subscriptions_backend(request, user_profile,
|
def add_subscriptions_backend(request, user_profile,
|
||||||
streams_raw = REQ("subscriptions",
|
streams_raw = REQ("subscriptions",
|
||||||
|
@ -1236,16 +1241,17 @@ def add_subscriptions_backend(request, user_profile,
|
||||||
(", ".join('`%s`' % (s.name,) for s in created_streams),)
|
(", ".join('`%s`' % (s.name,) for s in created_streams),)
|
||||||
else:
|
else:
|
||||||
stream_msg = "a new stream `%s`" % (created_streams[0].name)
|
stream_msg = "a new stream `%s`" % (created_streams[0].name)
|
||||||
msg = ("%s just created %s. To join, visit your [Streams page](#subscriptions)."
|
|
||||||
% (user_profile.full_name, stream_msg))
|
stream_buttons = ' '.join(stream_button(s.name for s in created_streams))
|
||||||
|
msg = ("%s just created %s. %s" % (user_profile.full_name,
|
||||||
|
stream_msg, stream_buttons))
|
||||||
notifications.append(internal_prep_message(settings.NOTIFICATION_BOT,
|
notifications.append(internal_prep_message(settings.NOTIFICATION_BOT,
|
||||||
"stream",
|
"stream",
|
||||||
notifications_stream.name, "Streams", msg,
|
notifications_stream.name, "Streams", msg,
|
||||||
realm=notifications_stream.realm))
|
realm=notifications_stream.realm))
|
||||||
else:
|
else:
|
||||||
msg = ("Hi there! %s just created a new stream '%s'. "
|
msg = ("Hi there! %s just created a new stream '%s'. %s"
|
||||||
"To join, click the gear in the left-side streams list."
|
% (user_profile.full_name, created_streams[0].name, stream_button(created_streams[0].name)))
|
||||||
% (user_profile.full_name, created_streams[0].name))
|
|
||||||
for realm_user_dict in get_active_user_dicts_in_realm(user_profile.realm):
|
for realm_user_dict in get_active_user_dicts_in_realm(user_profile.realm):
|
||||||
# Don't announce to yourself or to people you explicitly added
|
# Don't announce to yourself or to people you explicitly added
|
||||||
# (who will get the notification above instead).
|
# (who will get the notification above instead).
|
||||||
|
|
Loading…
Reference in New Issue