Merge pull request #4187 from jaywink/2758-twitter-crossposting

Fix Twitter crossposting by correctly calculating URL shortening
This commit is contained in:
Jonne Haß 2013-06-08 12:20:14 -07:00
commit c60738654c
7 changed files with 55 additions and 67 deletions

View file

@ -16,6 +16,7 @@
* Add back-to-top button on tag and user pages [#4185](https://github.com/diaspora/diaspora/issues/4185) * Add back-to-top button on tag and user pages [#4185](https://github.com/diaspora/diaspora/issues/4185)
* Fix reopened issue by changing the comment/post submit keyboard sortcut to ctrl+enter from shift+enter [#3897](https://github.com/diaspora/diaspora/issues/3897) * Fix reopened issue by changing the comment/post submit keyboard sortcut to ctrl+enter from shift+enter [#3897](https://github.com/diaspora/diaspora/issues/3897)
* Show medium avatar in hovercard [#4203](https://github.com/diaspora/diaspora/pull/4203) * Show medium avatar in hovercard [#4203](https://github.com/diaspora/diaspora/pull/4203)
* Fix posting to Twitter [#2758](https://github.com/diaspora/diaspora/issues/2758)
## Features ## Features

View file

@ -13,26 +13,6 @@ class Service < ActiveRecord::Base
service_strings.map{|s| "Services::#{s.titleize}"} service_strings.map{|s| "Services::#{s.titleize}"}
end end
def public_message(post, length, url = "", always_include_post_url = true, markdown = false)
Rails.logger.info("Posting out to #{self.class}")
if ! markdown
post_text = strip_markdown(post.text(:plain_text => true))
else
post_text = post.text(:plain_text => true)
end
if post_text.length <= length && ! always_include_post_url
# include url to diaspora when posting only when it exceeds length
url = ""
space_for_url = 0
else
url = " " + Rails.application.routes.url_helpers.short_post_url(post, :protocol => AppConfig.pod_uri.scheme, :host => AppConfig.pod_uri.authority)
space_for_url = 21 + 1
end
truncated = truncate(post_text, :length => (length - space_for_url))
truncated = "#{truncated}#{url}"
return truncated
end
def profile_photo_url def profile_photo_url
nil nil
end end
@ -42,5 +22,3 @@ class Service < ActiveRecord::Base
end end
end end
require 'services/facebook'
require 'services/twitter'

View file

@ -29,10 +29,6 @@ class Services::Facebook < Service
{:message => message, :access_token => self.access_token, :link => URI.extract(message, ['https', 'http']).first} {:message => message, :access_token => self.access_token, :link => URI.extract(message, ['https', 'http']).first}
end end
def public_message(post, url)
super(post, MAX_CHARACTERS, url)
end
def profile_photo_url def profile_photo_url
"https://graph.facebook.com/#{self.uid}/picture?type=large&access_token=#{URI.escape(self.access_token)}" "https://graph.facebook.com/#{self.uid}/picture?type=large&access_token=#{URI.escape(self.access_token)}"
end end

View file

@ -1,4 +1,7 @@
class Services::Twitter < Service class Services::Twitter < Service
include ActionView::Helpers::TextHelper
include MarkdownifyHelper
MAX_CHARACTERS = 140 MAX_CHARACTERS = 140
SHORTENED_URL_LENGTH = 21 SHORTENED_URL_LENGTH = 21
@ -8,21 +11,53 @@ class Services::Twitter < Service
def post(post, url='') def post(post, url='')
Rails.logger.debug("event=post_to_service type=twitter sender_id=#{self.user_id}") Rails.logger.debug("event=post_to_service type=twitter sender_id=#{self.user_id}")
message = public_message(post, url) (0...20).each do |retry_count|
tweet = client.update(message) begin
post.tweet_id = tweet.id message = build_twitter_post(post, url, retry_count)
@tweet = client.update(message)
break
rescue Twitter::Error::Forbidden => e
if e.message != 'Status is over 140 characters' || retry_count == 20
raise e
end
end
end
post.tweet_id = @tweet.id
post.save post.save
end end
def adjust_length_for_urls(post_text)
def public_message(post, url) real_length = post_text.length
buffer_amt = 0 URI.extract( post_text, ['http','https'] ) do |a_url|
URI.extract( post.text(:plain_text => true), ['http','https'] ) do |a_url| # add or subtract from real length - urls for tweets are always
buffer_amt += (a_url.length - SHORTENED_URL_LENGTH) # shortened to SHORTENED_URL_LENGTH
if a_url.length >= SHORTENED_URL_LENGTH
real_length -= a_url.length - SHORTENED_URL_LENGTH
else
real_length += SHORTENED_URL_LENGTH - a_url.length
end
end end
return real_length
end
def add_post_link(post, post_text, maxchars)
post_url = Rails.application.routes.url_helpers.short_post_url(
post,
:protocol => AppConfig.pod_uri.scheme,
:host => AppConfig.pod_uri.authority
)
truncated = truncate(post_text, :length => (maxchars - (SHORTENED_URL_LENGTH+1) ))
post_text = "#{truncated} #{post_url}"
end
def build_twitter_post(post, url, retry_count=0)
maxchars = MAX_CHARACTERS - retry_count*5
post_text = strip_markdown(post.text(:plain_text => true))
#if photos, always include url, otherwise not for short posts #if photos, always include url, otherwise not for short posts
super(post, MAX_CHARACTERS + buffer_amt, url, post.photos.any?) if adjust_length_for_urls(post_text) > maxchars || post.photos.any?
post_text = add_post_link(post, post_text, maxchars)
end
return post_text
end end
def profile_photo_url def profile_photo_url

View file

@ -22,17 +22,4 @@ describe Service do
Service.new.profile_photo_url.should be_nil Service.new.profile_photo_url.should be_nil
end end
it 'removes text formatting markdown from post text' do
service = Service.new
message = "Text with some **bolded** and _italic_ parts."
post = stub(:text => message)
service.public_message(post, 200, '', false).should match "Text with some bolded and italic parts."
end
it 'keeps markdown in post text when specified' do
service = Service.new
message = "Text with some **bolded** and _italic_ parts."
post = stub(:text => message)
service.public_message(post, 200, '', false, true).should match 'Text with some \*\*bolded\*\* and _italic_ parts.'
end
end end

View file

@ -24,14 +24,6 @@ describe Services::Facebook do
@service.post(@post) @service.post(@post)
end end
it 'should call public message' do
stub_request(:post, "https://graph.facebook.com/me/feed").
to_return(:status => 200, :body => '{"id": "12345"}', :headers => {})
url = "foo"
@service.should_not_receive(:public_message)
@service.post(@post, url)
end
it 'removes text formatting markdown from post text' do it 'removes text formatting markdown from post text' do
message = "Text with some **bolded** and _italic_ parts." message = "Text with some **bolded** and _italic_ parts."
post = stub(:text => message, :photos => []) post = stub(:text => message, :photos => [])

View file

@ -31,16 +31,16 @@ describe Services::Twitter do
@service.post(@post) @service.post(@post)
end end
it 'should call public message' do it 'should call build_twitter_post' do
url = "foo" url = "foo"
@service.should_receive(:public_message).with(@post, url) @service.should_receive(:build_twitter_post).with(@post, url, 0)
@service.post(@post, url) @service.post(@post, url)
end end
it 'removes text formatting markdown from post text' do it 'removes text formatting markdown from post text' do
message = "Text with some **bolded** and _italic_ parts." message = "Text with some **bolded** and _italic_ parts."
post = stub(:text => message, :photos => []) post = stub(:text => message, :photos => [])
@service.public_message(post, '').should match "Text with some bolded and italic parts." @service.build_twitter_post(post, '').should match "Text with some bolded and italic parts."
end end
end end
@ -54,21 +54,20 @@ describe Services::Twitter do
it "should not truncate a short message" do it "should not truncate a short message" do
short_message = SecureRandom.hex(20) short_message = SecureRandom.hex(20)
short_post = stub(:text => short_message, :photos => []) short_post = stub(:text => short_message, :photos => [])
@service.public_message(short_post, '').should match short_message @service.build_twitter_post(short_post, '').should match short_message
end end
it "should truncate a long message" do it "should truncate a long message" do
long_message = SecureRandom.hex(220) long_message = SecureRandom.hex(220)
long_post = stub(:text => long_message, :id => 1, :photos => []) long_post = stub(:text => long_message, :id => 1, :photos => [])
@service.public_message(long_post, '').should match long_message.first(100) @service.build_twitter_post(long_post, '').length.should be < long_message.length
end end
it "should not truncate a long message with an http url" do it "should not truncate a long message with an http url" do
long_message = " http://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + @long_message_end long_message = " http://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + @long_message_end
long_post = stub(:text => long_message, :id => 1, :photos => []) long_post = stub(:text => long_message, :id => 1, :photos => [])
@post.text = long_message @post.text = long_message
answer = @service.public_message(@post, '') answer = @service.build_twitter_post(@post, '')
answer.should_not match /\.\.\./ answer.should_not match /\.\.\./
end end
@ -76,14 +75,14 @@ describe Services::Twitter do
it "should not truncate a long message with an https url" do it "should not truncate a long message with an https url" do
long_message = " https://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + @long_message_end long_message = " https://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + @long_message_end
@post.text = long_message @post.text = long_message
answer = @service.public_message(@post, '') answer = @service.build_twitter_post(@post, '')
answer.should_not match /\.\.\./ answer.should_not match /\.\.\./
end end
it "should truncate a long message with an ftp url" do it "should truncate a long message with an ftp url" do
long_message = @long_message_start + " ftp://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + @long_message_end long_message = @long_message_start + " ftp://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + @long_message_end
long_post = stub(:text => long_message, :id => 1, :photos => []) long_post = stub(:text => long_message, :id => 1, :photos => [])
answer = @service.public_message(long_post, '') answer = @service.build_twitter_post(long_post, '')
answer.should match /\.\.\./ answer.should match /\.\.\./
end end
@ -91,7 +90,7 @@ describe Services::Twitter do
it "should not truncate a message of maximum length" do it "should not truncate a message of maximum length" do
exact_size_message = SecureRandom.hex(70) exact_size_message = SecureRandom.hex(70)
exact_size_post = stub(:text => exact_size_message, :id => 1, :photos => []) exact_size_post = stub(:text => exact_size_message, :id => 1, :photos => [])
answer = @service.public_message(exact_size_post, '') answer = @service.build_twitter_post(exact_size_post, '')
answer.should match exact_size_message answer.should match exact_size_message
end end
@ -113,7 +112,7 @@ describe Services::Twitter do
end end
it "should include post url in short message with photos" do it "should include post url in short message with photos" do
answer = @service.public_message(@status_message, '') answer = @service.build_twitter_post(@status_message, '')
answer.should include 'http' answer.should include 'http'
end end