diff --git a/app/models/note.rb b/app/models/note.rb index c7527105ac..882b89e6d8 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -15,7 +15,7 @@ class Note < Content belongs_to :user validates_presence_of :body validates_uniqueness_of :permalink, :guid - attr_accessor :push_to_twitter, :twitter_message + attr_accessor :push_to_twitter after_create :set_permalink, :shorten_url before_create :create_guid @@ -53,6 +53,15 @@ def initialize(*args) end end + def twitter_message + base_message = self.body.strip_html + if too_long?(base_message) + "#{base_message[0..113]}... (#{self.redirects.first.to_url})" + else + "#{base_message} (#{short_link})" + end + end + def send_to_twitter return false unless self.push_to_twitter # Then, what are we doing here?! return false unless Blog.default.has_twitter_configured? @@ -65,8 +74,6 @@ def send_to_twitter :oauth_token_secret => self.user.twitter_oauth_token_secret ) - build_twitter_message - begin options = {} @@ -76,7 +83,7 @@ def send_to_twitter end tweet = twitter.update(self.twitter_message, options) - self.twitter_id = tweet.attrs[:id_str] + self.twitter_id = tweet.attrs[:id_str] self.save @@ -107,10 +114,17 @@ def permalink_url(anchor=nil, only_path=false) ) end + def short_link + path = self.redirects.first.from_path + blog = Blog.default + prefix = blog.custom_url_shortener.present? ? blog.custom_url_shortener : blog.base_url + prefix.sub!(/^https?\:\/\//, '') + "#{prefix} #{path}" + end + private - def calculate_real_length - message = self.twitter_message + def too_long?(message) uris = URI.extract(message, ['http', 'https', 'ftp']) uris.each do |uri| case uri.split(":")[0] @@ -121,34 +135,8 @@ def calculate_real_length when "ftp" payload = "-" * TWITTER_FTP_URL_LEGTH end - message = message.gsub(uri, payload) end - - return message.length - end - - def build_short_link(length) - if length > 115 - return "... #{self.redirects.first.to_url}" - else - path = self.redirects.first.from_path - blog = Blog.default - prefix = (blog.custom_url_shortener) ? blog.custom_url_shortener : blog.base_url - prefix.sub!(/^https?\:\/\//, '') - return " (#{prefix} #{path})" - end - end - - def build_twitter_message - self.twitter_message = self.body.strip_html - - length = calculate_real_length - - if length > 114 - self.twitter_message = "#{self.twitter_message[0..113]}#{build_short_link(length)}" - else - self.twitter_message = "#{self.twitter_message}#{build_short_link(length)}" - end + message.length > 114 end end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index b2a1632d0a..50bb2b36f6 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -2,229 +2,156 @@ require 'spec_helper' describe Note do - let!(:blog) { create(:blog) } - - describe "validations" do - it { expect(create(:note)).to be_valid } - - context "with an existing note" do - let(:existing_note) { create(:note) } - - it { expect(build(:note, guid: existing_note.guid)).to be_invalid } + context "with a simple blog" do + let!(:blog) { create(:blog) } + + describe "validations" do + it { expect(build(:note)).to be_valid } + it { expect(build(:note, body:nil)).to be_invalid } + + it "with a nil body, return default error message" do + note = build(:note, body:nil) + note.save + expect(note.errors[:body]).to eq(["can't be blank"]) + end + + context "with an existing note" do + let(:existing_note) { create(:note) } + it { expect(build(:note, guid: existing_note.guid)).to be_invalid } + end end - end -end -describe "Testing redirects" do - it "a new published status gets a redirect" do - FactoryGirl.create(:blog) - a = Note.create(:body => "some text", :published => true) - a.should be_valid - a.redirects.first.should_not be_nil - a.redirects.first.to_path.should == a.permalink_url - end -end - -describe "Testing hashtag and @mention replacement in html postprocessing" do - before(:each) do - FactoryGirl.create(:blog, :dofollowify => true) - end + describe :permalink do + let(:note) { create(:note, body:"àé") } - it "should replace a hashtag with a proper URL to Twitter search" do - note = FactoryGirl.create(:note, :body => "A test tweet with a #hashtag") - text = note.html_preprocess(note.body, note.body) - text.should == "A test tweet with a #hashtag" - end - - it "should replace a @mention by a proper URL to the twitter account" do - note = FactoryGirl.create(:note, :body => "A test tweet with a @mention") - text = note.html_preprocess(note.body, note.body) - text.should == "A test tweet with a @mention" - end - - it "should replace a http URL by a proper link" do - note = FactoryGirl.create(:note, :body => "A test tweet with a http://link.com") - text = note.html_preprocess(note.body, note.body) - text.should == "A test tweet with a http://link.com" - end - - it "should replace a https URL with a proper link" do - note = FactoryGirl.create(:note, :body => "A test tweet with a https://link.com") - text = note.html_preprocess(note.body, note.body) - text.should == "A test tweet with a https://link.com" - end -end - -describe 'Testing notes scopes' do - before(:each) do - FactoryGirl.create(:blog) - Note.delete_all - end - - it 'Published scope should not bring unpublished statuses' do - FactoryGirl.create(:note) - FactoryGirl.create(:unpublished_note) - - notes = Note.published - notes.count.should == 1 - end - - it 'Published scope should not bring notes published in the future' do - FactoryGirl.create(:note) - FactoryGirl.create(:note, published_at: Time.now + 3.days ) - - notes = Note.published - notes.count.should == 1 - end -end - - -describe 'Given the factory :status' do - before(:each) do - FactoryGirl.create(:blog) - @note = FactoryGirl.create(:note) - end - - describe "#permalink_url" do - subject { @note.permalink_url } - it { should == "http://myblog.net/note/#{@note.id}-this-is-a-note" } - end - - it "should give a sanitized title" do - note = FactoryGirl.build(:note, :body => 'body with accents éèà') - note.body.to_permalink.should == 'body-with-accents-eea' - end -end + it { expect(note.permalink).to eq("#{note.id}-ae") } + it { expect(note.permalink_url).to eq("#{blog.base_url}/note/#{note.id}-ae") } -class Hash - def except(*keys) - self.reject { |k,v| keys.include? k.to_sym } - end + context "with a particular blog" do + before(:each) do + Blog.any_instance.stub(:custom_url_shortener).and_return(url_shortener) + Blog.any_instance.stub(:base_url).and_return("http://mybaseurl.net") + end - def only(*keys) - self.dup.reject { |k, v| !keys.include? k.to_sym } - end -end + context "with a blog that have a custome url shortener" do + let(:url_shortener) { "shor.tl" } + it { expect(note.short_link).to eq("#{url_shortener} #{note.redirects.first.from_path}") } + end -describe 'Given no notes' do - def valid_attributes - { :body => 'body'} - end + context "with a blog that have a custome url shortener" do + let(:url_shortener) { nil } + it { expect(note.short_link).to eq("mybaseurl.net #{note.redirects.first.from_path}") } + end + end + end - before(:each) do - Note.delete_all - @note = Note.new - end + describe :redirects do + let(:note) { create(:note) } + it { expect(note.redirects.map(&:to_path)).to eq([note.permalink_url]) } + end - it 'An empty note is invalid' do - @note.should_not be_valid - end + describe :scopes do - it 'A note is valid with a body' do - @note.attributes = valid_attributes - @note.should be_valid - end + describe :published do + let(:now) { DateTime.new(2012,5,20,14,23) } + let(:note) { create(:note, published_at: now - 1.minute) } - it 'A note is invalid without a body' do - @note.attributes = valid_attributes.except(:body) - @note.should_not be_valid - @note.errors[:body].should == ["can't be blank"] - @note.body = 'somebody' - @note.should be_valid - end + before(:each) { Time.stub(:now).and_return(now) } - it "should use sanitize title to set note name" do - @note.attributes = valid_attributes.except(:body) - @note.body = 'title with accents éèà' - @note.should be_valid - @note.save - @note.permalink.should == "#{@note.id}-title-with-accents-eea" - end + context "with a unpubilshed note" do + let(:unpublished_note) { create(:unpublished_note) } + it { expect(Note.published).to eq([note]) } + end -end + context "with a note to publish later" do + let(:later_note) { create(:note, published_at: now + 3.days) } + it { expect(Note.published).to eq([note]) } + end + end + end -describe 'Given a note page' do - it 'default filter should be fetched from the blog' do - FactoryGirl.create(:blog) - @note = Note.new() - @note.default_text_filter.name.should == Blog.default.text_filter - end -end + describe :send_to_twitter do + context "with a push to twitter note" do + let(:note) { build(:note, push_to_twitter: false) } + it { expect(note.send_to_twitter).to be_false } + end -describe "Checking Twitter message length..." do - it "A twitter message without URL should not be changed" do - note = FactoryGirl.build(:note, twitter_message: "A message without URL") - note.instance_eval{ calculate_real_length }.should == 21 - end + context "with a push to twitter note" do + before(:each) { Blog.any_instance.should_receive(:has_twitter_configured?).and_return(false) } + let(:note) { build(:note, push_to_twitter: true) } - it "A twitter message with a short http URL should have its URL expanded to 20 chars" do - note = FactoryGirl.build(:note, twitter_message: "A message with a short URL http://foo.com") - note.instance_eval{ calculate_real_length }.should == 47 - end + it { expect(note.send_to_twitter).to be_false } + end - it "A twitter message with a short https URL should have its URL expanded to 21 chars" do - note = FactoryGirl.build(:note, twitter_message: "A message with a short URL https://foo.com") - note.instance_eval{ calculate_real_length }.should == 48 - end + context "with a push to twitter note" do + before(:each) do + Blog.any_instance.should_receive(:has_twitter_configured?).and_return(true) + User.any_instance.should_receive(:has_twitter_configured?).and_return(false) + end - it "A twitter message with a short https URL should have its URL expanded to 19 chars" do - note = FactoryGirl.build(:note, twitter_message: "A message with a short URL ftp://foo.com") - note.instance_eval{ calculate_real_length }.should == 46 - end + let(:note) { build(:note, push_to_twitter: true) } + it { expect(note.send_to_twitter).to be_false } + end - it "A twitter message with a long http URL should have its URL shortened to 20 chars" do - note = FactoryGirl.build(:note, twitter_message: "A message with a long URL http://foobarsomething.com?blablablablabla") - note.instance_eval{ calculate_real_length }.should == 46 - end + end - it "A twitter message with a short https URL should have its URL expanded to 21 chars" do - note = FactoryGirl.build(:note, twitter_message: "A message with a long URL https://foobarsomething.com?blablablablabla") - note.instance_eval{ calculate_real_length }.should == 47 - end + describe :default_text_filter do + let(:note) { build(:note) } + it { expect(note.default_text_filter.name).to eq(Blog.default.text_filter) } + end - it "A twitter message with a short https URL should have its URL expanded to 19 chars" do - note = FactoryGirl.build(:note, twitter_message: "A message with a long URL ftp://foobarsomething.com?blablablablabla") - note.instance_eval{ calculate_real_length }.should == 45 - end -end + describe :twitter_message do + let(:note) { create(:note, body: tweet) } -describe 'Pushing a note to Twitter' do - before :each do - Blog.delete_all - end - it 'A note without push to twitter defined should not push to Twitter' do - FactoryGirl.create(:blog) - note = FactoryGirl.build(:note, :push_to_twitter => 0) - note.send_to_twitter.should == false - end + context "with a short simple message" do + let(:tweet) { "A message without URL" } - it 'a non configured blog and non configured user should not send a note to Twitter' do - FactoryGirl.create(:blog) - note = FactoryGirl.create(:note) - note.send_to_twitter.should == false - end + it { expect(note.twitter_message).to start_with(tweet) } + it { expect(note.twitter_message).to end_with(" (#{note.short_link})") } + end - it 'a configured blog and non configured user should not send a note to Twitter' do - FactoryGirl.build(:blog, twitter_consumer_key: "12345", twitter_consumer_secret: "67890") - user = FactoryGirl.build(:user) - note = FactoryGirl.build(:note, user: user) - note.send_to_twitter.should == false - end + context "with a short message with short HTTP url" do + let(:tweet) { "A message with a short URL http://foo.com" } + it { expect(note.twitter_message).to start_with(tweet) } + end - it 'a non configured blog and a configured user should not send a note to Twitter' do - FactoryGirl.build(:blog) - user = FactoryGirl.build(:user, twitter_oauth_token: "12345", twitter_oauth_token_secret: "67890") - note = FactoryGirl.build(:note, user: user) - note.send_to_twitter.should == false + context "with a short message much more than 114 char" do + let(:tweet) { "A very big(10) message with lot of text (40)inside just to try the shortener and (80)the new link that publify must construct(124)" } + it { expect(note.twitter_message).to start_with(tweet[0..113]) } + it { expect(note.twitter_message).to_not include(tweet[113..-1]) } + it { expect(note.twitter_message).to end_with(" (#{note.redirects.first.to_url})") } + end + end end - it 'a configured blog and a configured user should send a note to Twitter' do - FactoryGirl.build(:blog, twitter_consumer_key: "12345", twitter_consumer_secret: "67890") - user = FactoryGirl.build(:user, twitter_oauth_token: "12345", twitter_oauth_token_secret: "67890") - note = FactoryGirl.build(:note, user: user) - pending "Need to find a way to fake the Twitter API behavior" - # status.send_to_twitter.should == false + context "with a dofollowify blog" do + let!(:blog) { create(:blog, dofollowify: true) } + + describe "Testing hashtag and @mention replacement in html postprocessing" do + it "should replace a hashtag with a proper URL to Twitter search" do + note = build(:note, body: "A test tweet with a #hashtag") + expected = "A test tweet with a #hashtag" + expect(note.html_preprocess(nil, note.body)).to eq(expected) + end + + it "should replace a @mention by a proper URL to the twitter account" do + note = create(:note, body: "A test tweet with a @mention") + expected = "A test tweet with a @mention" + expect(note.html_preprocess(nil, note.body)).to eq(expected) + end + + it "should replace a http URL by a proper link" do + note = create(:note, body: "A test tweet with a http://link.com") + expected = "A test tweet with a http://link.com" + expect(note.html_preprocess(nil, note.body)).to eq(expected) + end + + it "should replace a https URL with a proper link" do + note = create(:note, body: "A test tweet with a https://link.com") + expected = "A test tweet with a https://link.com" + expect(note.html_preprocess(nil, note.body)).to eq(expected) + end + end end end -