Skip to content

Commit

Permalink
twitter create: extended tweets: don't require @-mentions in replies
Browse files Browse the repository at this point in the history
instead, use the new auto_populate_reply_metadata=true query param.

for #89

https://dev.twitter.com/overview/api/upcoming-changes-to-tweets
  • Loading branch information
snarfed committed Oct 1, 2016
1 parent ae567aa commit c7aad33
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 30 deletions.
30 changes: 17 additions & 13 deletions granary/test/test_twitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -1774,22 +1774,21 @@ def test_create_tweet_with_location(self):
def test_create_reply(self):
# tuples: (content, in-reply-to url, expected tweet)
testdata = (
# good reply, with @-mention of author
# reply with @-mention of author
('foo @you', 'http://twitter.com/you/status/100', 'foo @you'),
# no @-mention of in-reply-to author, so we add it
('foo', 'http://twitter.com/you/status/100', '@you foo'),
# @-mention of in-reply-to author has a different capitalization
('foo @You', 'http://twitter.com/you/status/100', 'foo @You'),
# reply without @-mention of in-reply-to author
('foo', 'http://twitter.com/you/status/100', 'foo'),
# photo URL. tests Twitter.base_object()
('foo', 'http://twitter.com/you/status/100/photo/1', '@you foo'),
('foo', 'http://twitter.com/you/status/100/photo/1', 'foo'),
# mobile.twitter.com URL. the mobile should be stripped from embed.
('foo', 'http://mobile.twitter.com/you/status/100', '@you foo'),
('foo', 'http://mobile.twitter.com/you/status/100', 'foo'),
)

for _, _, status in testdata:
self.expect_urlopen(twitter.API_POST_TWEET, TWEET, params={
'status': status,
'in_reply_to_status_id': 100,
'auto_populate_reply_metadata': 'true',
})
self.mox.ReplayAll()

Expand Down Expand Up @@ -1819,13 +1818,14 @@ def test_create_reply_objectType_comment(self):
# test preview
preview = self.twitter.preview_create(obj)
self.assertIn('<span class="verb">@-reply</span> to <a href="http://twitter.com/you/status/100">this tweet</a>:', preview.description)
self.assertEquals('@you my content', preview.content)
self.assertEquals('my content', preview.content)

# test create
self.expect_urlopen(twitter.API_POST_TWEET, {'url': 'http://posted/tweet'},
params={
'status': '@you my content',
'status': 'my content',
'in_reply_to_status_id': '100',
'auto_populate_reply_metadata': 'true',
})
self.mox.ReplayAll()
self.assert_equals({'url': 'http://posted/tweet', 'type': 'comment'},
Expand All @@ -1835,8 +1835,11 @@ def test_create_reply_to_self_omits_mention(self):
for i in range(3):
self.expect_urlopen(
twitter.API_POST_TWEET, {'url': 'http://posted/tweet'},
params={'status': 'my content', 'in_reply_to_status_id': '100'},
)
params={
'status': 'my content',
'in_reply_to_status_id': '100',
'auto_populate_reply_metadata': 'true',
})
self.mox.ReplayAll()

for username, reply_to in ('me', 'me'), ('ME', 'ME'), ('Me', 'mE'):
Expand Down Expand Up @@ -1975,7 +1978,7 @@ def test_create_reply_with_photo(self):
# test preview
preview = self.twitter.preview_create(obj)
self.assertIn('<span class="verb">@-reply</span> to <a href="http://twitter.com/you/status/100">this tweet</a>:', preview.description)
self.assertEquals('@you my content<br /><br /><img src="http://my/picture" />',
self.assertEquals('my content<br /><br /><img src="http://my/picture" />',
preview.content)

# test create
Expand All @@ -1986,9 +1989,10 @@ def test_create_reply_with_photo(self):
headers=mox.IgnoreArg())
self.expect_urlopen(twitter.API_POST_TWEET, {'url': 'http://posted/picture'},
params={
'status': '@you my content',
'status': 'my content',
'in_reply_to_status_id': '100',
'media_ids': '123',
'auto_populate_reply_metadata': 'true',
})
self.mox.ReplayAll()
self.assert_equals({'url': 'http://posted/picture', 'type': 'comment'},
Expand Down
26 changes: 9 additions & 17 deletions granary/twitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,26 +601,15 @@ def _create(self, obj, preview=None, include_link=source.OMIT_LINK,
error_html='No content text found.')

if is_reply and base_url:
# extract username from in-reply-to URL so we can @-mention it, if it's
# not already @-mentioned, since Twitter requires that to make our new
# tweet a reply.
# Twitter *used* to require replies to include an @-mention of the
# original tweet's author
# https://dev.twitter.com/docs/api/1.1/post/statuses/update#api-param-in_reply_to_status_id
# TODO: this doesn't handle an in-reply-to username that's a prefix of
# another username already mentioned, e.g. in reply to @foo when content
# includes @foobar.
parsed = urlparse.urlparse(base_url)
parts = parsed.path.split('/')
if len(parts) < 2 or not parts[1]:
raise ValueError('Could not determine author of in-reply-to URL %s' % base_url)
reply_to = parts[1].lower()
if not self.username or reply_to != self.username.lower():
mention = '@' + reply_to
if mention not in content.lower():
content = mention + ' ' + content
# ...but now we use the auto_populate_reply_metadata query param instead:
# https://dev.twitter.com/overview/api/upcoming-changes-to-tweets

# the embed URL in the preview can't start with mobile. or www., so just
# hard-code it to twitter.com. index #1 is netloc.
parsed = list(parsed)
parsed = list(urlparse.urlparse(base_url))
parsed[1] = self.DOMAIN
base_url = urlparse.urlunparse(parsed)

Expand Down Expand Up @@ -690,7 +679,10 @@ def _create(self, obj, preview=None, include_link=source.OMIT_LINK,
description = \
'<span class="verb">@-reply</span> to <a href="%s">this tweet</a>:\n%s' % (
base_url, self.embed_post(base_obj))
data['in_reply_to_status_id'] = base_id
data.update({
'in_reply_to_status_id': base_id,
'auto_populate_reply_metadata': 'true',
})
else:
description = '<span class="verb">tweet</span>:'

Expand Down

0 comments on commit c7aad33

Please sign in to comment.