diff --git a/Gemfile b/Gemfile index 219dc2532..28406380e 100644 --- a/Gemfile +++ b/Gemfile @@ -65,7 +65,7 @@ gem 'messagebus_ruby_api', '1.0.3' gem 'nokogiri', '1.6.1' gem 'rails_autolink', '1.1.5' -gem 'redcarpet', '3.0.0' +gem 'redcarpet', '3.1.1' gem 'roxml', '3.1.6' gem 'ruby-oembed', '0.8.9' gem 'opengraph_parser', '0.2.3' diff --git a/Gemfile.lock b/Gemfile.lock index b6c729d42..cd593f48b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -345,7 +345,7 @@ GEM rb-inotify (0.9.3) rdoc (3.12.2) json (~> 1.4) - redcarpet (3.0.0) + redcarpet (3.1.1) redis (3.0.6) redis-namespace (1.4.1) redis (~> 3.0.4) @@ -512,7 +512,7 @@ DEPENDENCIES rails_autolink (= 1.1.5) rb-fsevent (= 0.9.4) rb-inotify (= 0.9.3) - redcarpet (= 3.0.0) + redcarpet (= 3.1.1) remotipart (= 1.2.1) rmagick (= 2.13.2) roxml (= 3.1.6) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 97ed376eb..886b905b1 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -98,7 +98,11 @@ class UsersController < ApplicationController if @user = User.find_by_username(params[:username]) respond_to do |format| format.atom do - @posts = Post.where(:author_id => @user.person_id, :public => true).order('created_at DESC').limit(25) + @posts = Post.where(author_id: @user.person_id, public: true) + .order('created_at DESC') + .limit(25) + .map {|post| post.is_a?(Reshare) ? post.absolute_root : post } + .compact end format.any { redirect_to person_path(@user.person) } diff --git a/app/helpers/markdownify_helper.rb b/app/helpers/markdownify_helper.rb deleted file mode 100644 index b59537a1e..000000000 --- a/app/helpers/markdownify_helper.rb +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (c) 2010-2011, Diaspora Inc. This file is -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. - -module MarkdownifyHelper - - def markdown_options - { - :autolink => true, - :fenced_code_blocks => true, - :space_after_headers => true, - :strikethrough => true, - :tables => true, - :no_intra_emphasis => true, - } - end - - def markdownify(target, render_options={}) - - render_options[:filter_html] = true - render_options[:hard_wrap] ||= true - render_options[:safe_links_only] = true - - # This ugly little hack basically means - # "Give me the rawest contents of target available" - if target.respond_to?(:raw_message) - message = target.raw_message - elsif target.respond_to?(:text) - message = target.text - else - message = target.to_s - end - - return '' if message.blank? - - renderer = Diaspora::Markdownify::HTML.new(render_options) - markdown = Redcarpet::Markdown.new(renderer, markdown_options) - - message = markdown.render(message).html_safe - - if target.respond_to?(:mentioned_people) - message = Diaspora::Mentionable.format(message, target.mentioned_people) - end - - message = Diaspora::Taggable.format_tags(message, :no_escape => true) - - return message.html_safe - end - - def strip_markdown(text) - renderer = Redcarpet::Markdown.new(Redcarpet::Render::StripDown, markdown_options) - renderer.render(text).strip - end - - def process_newlines(message) - # in very clear cases, let newlines become
tags - # Grabbed from Github flavored Markdown - message.gsub(/^[\w\<][^\n]*\n+/) do |x| - x =~ /\n{2}/ ? x : (x.strip!; x << " \n") - end - end -end diff --git a/app/helpers/notifier_helper.rb b/app/helpers/notifier_helper.rb index d2d56d7bd..44de54f1c 100644 --- a/app/helpers/notifier_helper.rb +++ b/app/helpers/notifier_helper.rb @@ -1,28 +1,20 @@ module NotifierHelper - + # @param post [Post] The post object. - # @param opts [Hash] Optional hash. Accepts :length and :process_newlines parameters. + # @param opts [Hash] Optional hash. Accepts :length parameters. # @return [String] The truncated and formatted post. def post_message(post, opts={}) - opts[:length] ||= 200 - if post.respond_to? :formatted_message - message = strip_markdown(post.formatted_message(:plain_text => true)) - message = truncate(message, :length => opts[:length]) - message = process_newlines(message) if opts[:process_newlines] - message + if post.respond_to? :message + post.message.plain_text_without_markdown truncate: opts.fetch(:length, 200) else I18n.translate 'notifier.a_post_you_shared' end end # @param comment [Comment] The comment to process. - # @param opts [Hash] Optional hash. Accepts :length and :process_newlines parameters. + # @param opts [Hash] Optional hash. Accepts :length parameters. # @return [String] The truncated and formatted comment. def comment_message(comment, opts={}) - opts[:length] ||= 600 - text = strip_markdown(comment.text) - text = truncate(text, :length => opts[:length]) - text = process_newlines(text) if opts[:process_newlines] - text + comment.message.plain_text_without_markdown truncate: opts.fetch(:length, 600) end end diff --git a/app/helpers/posts_helper.rb b/app/helpers/posts_helper.rb index ddd8d19d1..6a4758a73 100644 --- a/app/helpers/posts_helper.rb +++ b/app/helpers/posts_helper.rb @@ -9,19 +9,8 @@ module PostsHelper elsif post.is_a?(Reshare) I18n.t "posts.show.reshare_by", :author => post.author_name else - if post.text.present? - if opts.has_key?(:length) - truncate(post.text(:plain_text => true), :length => opts.fetch(:length)) - elsif /\A(?: # Regexp to match a Markdown header present on first line : - (?.{1,200}\n(?:={1,200}|-{1,200}))(?:\r?\n|$) # Setext-style header - | # or - (?\#{1,6}\s.{1,200})(?:\r?\n|$) # Atx-style header - )/x =~ post.text(:plain_text => true) - return setext_content unless setext_content.nil? - return atx_content unless atx_content.nil? - else - truncate(post.text(:plain_text => true), :length => 20 ) - end + if post.message.present? + post.message.title opts elsif post.respond_to?(:photos) && post.photos.present? I18n.t "posts.show.photos_by", :count => post.photos.size, :author => post.author_name end diff --git a/app/mailers/notification_mailers/also_commented.rb b/app/mailers/notification_mailers/also_commented.rb index c0957e5aa..d5ef2d3f4 100644 --- a/app/mailers/notification_mailers/also_commented.rb +++ b/app/mailers/notification_mailers/also_commented.rb @@ -1,8 +1,5 @@ module NotificationMailers class AlsoCommented < NotificationMailers::Base - include ActionView::Helpers::TextHelper - include MarkdownifyHelper - attr_accessor :comment delegate :post, to: :comment, prefix: true @@ -11,8 +8,7 @@ module NotificationMailers if mail? @headers[:from] = "\"#{@comment.author_name} (diaspora*)\" <#{AppConfig.mail.sender_address}>" - @headers[:subject] = truncate(strip_markdown(@comment.comment_email_subject.squish), :length => TRUNCATION_LEN) - @headers[:subject] = "Re: #{@headers[:subject]}" + @headers[:subject] = "Re: #{@comment.comment_email_subject}" end end diff --git a/app/mailers/notification_mailers/base.rb b/app/mailers/notification_mailers/base.rb index 06d21ad5d..ec2950bfb 100644 --- a/app/mailers/notification_mailers/base.rb +++ b/app/mailers/notification_mailers/base.rb @@ -1,6 +1,4 @@ module NotificationMailers - TRUNCATION_LEN = 70 - class Base attr_accessor :recipient, :sender diff --git a/app/mailers/notification_mailers/comment_on_post.rb b/app/mailers/notification_mailers/comment_on_post.rb index 18faa2df7..de01804bb 100644 --- a/app/mailers/notification_mailers/comment_on_post.rb +++ b/app/mailers/notification_mailers/comment_on_post.rb @@ -1,16 +1,12 @@ module NotificationMailers class CommentOnPost < NotificationMailers::Base - include ActionView::Helpers::TextHelper - include MarkdownifyHelper - attr_accessor :comment def set_headers(comment_id) @comment = Comment.find(comment_id) @headers[:from] = "\"#{@comment.author_name} (diaspora*)\" <#{AppConfig.mail.sender_address}>" - @headers[:subject] = truncate(strip_markdown(@comment.comment_email_subject.squish), :length => TRUNCATION_LEN) - @headers[:subject] = "Re: #{@headers[:subject]}" + @headers[:subject] = "Re: #{@comment.comment_email_subject}" end end end diff --git a/app/mailers/notifier.rb b/app/mailers/notifier.rb index c922f2744..5abce9ee0 100644 --- a/app/mailers/notifier.rb +++ b/app/mailers/notifier.rb @@ -1,9 +1,8 @@ class Notifier < ActionMailer::Base helper :application - helper :markdownify helper :notifier helper :people - + def self.admin(string, recipients, opts = {}) mails = [] recipients.each do |rec| @@ -16,7 +15,7 @@ class Notifier < ActionMailer::Base def single_admin(string, recipient, opts={}) @receiver = recipient @string = string.html_safe - + if attach = opts.delete(:attachments) attach.each{ |f| attachments[f[:name]] = f[:file] diff --git a/app/models/comment.rb b/app/models/comment.rb index 92c56929c..5fe754c8b 100644 --- a/app/models/comment.rb +++ b/app/models/comment.rb @@ -5,7 +5,7 @@ class Comment < ActiveRecord::Base include Diaspora::Federated::Base - + include Diaspora::Guid include Diaspora::Relayable @@ -22,7 +22,7 @@ class Comment < ActiveRecord::Base belongs_to :commentable, :touch => true, :polymorphic => true alias_attribute :post, :commentable belongs_to :author, :class_name => 'Person' - + delegate :name, to: :author, prefix: true delegate :comment_email_subject, to: :parent delegate :author_name, to: :parent, prefix: true @@ -79,6 +79,10 @@ class Comment < ActiveRecord::Base self.post = parent end + def message + @message ||= Diaspora::MessageRenderer.new text + end + def text= text self[:text] = text.to_s.strip #to_s if for nil, for whatever reason end diff --git a/app/models/message.rb b/app/models/message.rb index 60de53d3d..f73fc87b9 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -18,7 +18,7 @@ class Message < ActiveRecord::Base validate :participant_of_parent_conversation after_create do # don't use 'after_commit' here since there is a call to 'save!' - # inside, which would cause an infinite recursion + # inside, which would cause an infinite recursion #sign comment as commenter self.author_signature = self.sign_with_key(self.author.owner.encryption_key) if self.author.owner @@ -71,8 +71,8 @@ class Message < ActiveRecord::Base Notifications::PrivateMessage unless user.person == person end - def formatted_message(opts={}) - opts[:plain_text] ? self.text: ERB::Util.h(self.text) + def message + @message ||= Diaspora::MessageRenderer.new text end private diff --git a/app/models/profile.rb b/app/models/profile.rb index 8224a973b..3e0e425e1 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -55,7 +55,7 @@ class Profile < ActiveRecord::Base def receive(user, person) Rails.logger.info("event=receive payload_type=profile sender=#{person} to=#{user}") profiles_attr = self.attributes.merge('tag_string' => self.tag_string).slice('diaspora_handle', 'first_name', 'last_name', 'image_url', 'image_url_small', 'image_url_medium', 'birthday', 'gender', 'bio', 'location', 'searchable', 'nsfw', 'tag_string') - person.profile.update_attributes(profiles_attr) + person.profile.update_attributes(profiles_attr) person.profile end @@ -78,13 +78,13 @@ class Profile < ActiveRecord::Base def from_omniauth_hash(omniauth_user_hash) mappings = {"description" => "bio", - 'image' => 'image_url', - 'name' => 'first_name', + 'image' => 'image_url', + 'name' => 'first_name', 'location' => 'location', } update_hash = Hash[ omniauth_user_hash.map {|k, v| [mappings[k], v] } ] - + self.attributes.merge(update_hash){|key, old, new| old.blank? ? new : old} end @@ -132,6 +132,13 @@ class Profile < ActiveRecord::Base birthday.to_s(:long).gsub(', 1000', '') if birthday.present? end + def bio_message + @bio_message ||= Diaspora::MessageRenderer.new(bio) + end + + def location_message + @location_message ||= Diaspora::MessageRenderer.new(location) + end def tag_string if @tag_string diff --git a/app/models/reshare.rb b/app/models/reshare.rb index b597dea71..da902dc3d 100644 --- a/app/models/reshare.rb +++ b/app/models/reshare.rb @@ -41,6 +41,10 @@ class Reshare < Post self.root ? root.raw_message : super end + def message + absolute_root.message if root.present? + end + def mentioned_people self.root ? root.mentioned_people : super end diff --git a/app/models/service.rb b/app/models/service.rb index 463bd8389..4e443cf50 100644 --- a/app/models/service.rb +++ b/app/models/service.rb @@ -3,11 +3,8 @@ # the COPYRIGHT file. class Service < ActiveRecord::Base - include ActionView::Helpers::TextHelper - include MarkdownifyHelper - attr_accessor :provider, :info, :access_level - + belongs_to :user validates_uniqueness_of :uid, :scope => :type @@ -26,12 +23,12 @@ class Service < ActiveRecord::Base end def first_from_omniauth( auth_hash ) - @@auth = auth_hash + @@auth = auth_hash where( type: service_type, uid: options[:uid] ).first end def initialize_from_omniauth( auth_hash ) - @@auth = auth_hash + @@auth = auth_hash service_type.constantize.new( options ) end @@ -44,7 +41,7 @@ class Service < ActiveRecord::Base end def options - { + { nickname: auth['info']['nickname'], access_token: auth['credentials']['token'], access_secret: auth['credentials']['secret'], diff --git a/app/models/services/facebook.rb b/app/models/services/facebook.rb index a8a9bf0b7..f49fd2e51 100644 --- a/app/models/services/facebook.rb +++ b/app/models/services/facebook.rb @@ -1,9 +1,8 @@ class Services::Facebook < Service include Rails.application.routes.url_helpers - include MarkdownifyHelper OVERRIDE_FIELDS_ON_FB_UPDATE = [:contact_id, :person_id, :request_id, :invitation_id, :photo_url, :name, :username] - MAX_CHARACTERS = 63206 + MAX_CHARACTERS = 63206 def provider "facebook" @@ -22,11 +21,16 @@ class Services::Facebook < Service end def create_post_params(post) - message = strip_markdown(post.text(:plain_text => true)) + message = post.message.plain_text_without_markdown if post.photos.any? - message += " " + Rails.application.routes.url_helpers.short_post_url(post, :protocol => AppConfig.pod_uri.scheme, :host => AppConfig.pod_uri.authority) + message += " " + short_post_url(post, protocol: AppConfig.pod_uri.scheme, + host: AppConfig.pod_uri.authority) end - {:message => message, :access_token => self.access_token, :link => URI.extract(message, ['https', 'http']).first} + + {message: message, + access_token: access_token, + link: URI.extract(message, ['https', 'http']).first + } end def profile_photo_url diff --git a/app/models/services/tumblr.rb b/app/models/services/tumblr.rb index 6fef57617..65cecedef 100644 --- a/app/models/services/tumblr.rb +++ b/app/models/services/tumblr.rb @@ -1,7 +1,4 @@ class Services::Tumblr < Service - include ActionView::Helpers::TextHelper - include ActionView::Helpers::TagHelper - MAX_CHARACTERS = 1000 def provider @@ -38,10 +35,10 @@ class Services::Tumblr < Service def tumblr_template(post, url) html = '' post.photos.each do |photo| - html += "![photo](#{photo.url(:scaled_full)})\n\n" + html << "![photo](#{photo.url(:scaled_full)})\n\n" end - html += post.text - html += "\n\n[original post](#{url})" + html << post.message.html(mentioned_people: []) + html << "\n\n[original post](#{url})" end def delete_post(post) diff --git a/app/models/services/twitter.rb b/app/models/services/twitter.rb index efa13799e..7c5d246ec 100644 --- a/app/models/services/twitter.rb +++ b/app/models/services/twitter.rb @@ -1,7 +1,5 @@ class Services::Twitter < Service - include ActionView::Helpers::TextHelper include Rails.application.routes.url_helpers - include MarkdownifyHelper MAX_CHARACTERS = 140 SHORTENED_URL_LENGTH = 21 @@ -40,7 +38,7 @@ class Services::Twitter < Service def attempt_post post, retry_count=0 message = build_twitter_post post, retry_count - tweet = client.update message + client.update message rescue Twitter::Error::Forbidden => e if ! e.message.include? 'is over 140' || retry_count == 20 raise e @@ -52,7 +50,7 @@ class Services::Twitter < Service def build_twitter_post post, retry_count=0 max_characters = MAX_CHARACTERS - retry_count - post_text = strip_markdown post.text(plain_text: true) + post_text = post.message.plain_text_without_markdown truncate_and_add_post_link post, post_text, max_characters end @@ -65,7 +63,7 @@ class Services::Twitter < Service host: AppConfig.pod_uri.authority ) - truncated_text = truncate post_text, length: max_characters - SHORTENED_URL_LENGTH + 1 + truncated_text = post_text.truncate max_characters - SHORTENED_URL_LENGTH + 1 truncated_text = restore_truncated_url truncated_text, post_text, max_characters "#{truncated_text} #{post_url}" @@ -95,11 +93,9 @@ class Services::Twitter < Service return truncated_text if truncated_text !~ /#{LINK_PATTERN}\Z/ url = post_text.match(LINK_PATTERN, truncated_text.rindex('http'))[0] - truncated_text = truncate( - post_text, - length: max_characters - SHORTENED_URL_LENGTH + 2, - separator: ' ', - omission: '' + truncated_text = post_text.truncate( + max_characters - SHORTENED_URL_LENGTH + 2, + separator: ' ', omission: '' ) "#{truncated_text} #{url} ..." diff --git a/app/models/services/wordpress.rb b/app/models/services/wordpress.rb index 048cf03f5..0764f7146 100644 --- a/app/models/services/wordpress.rb +++ b/app/models/services/wordpress.rb @@ -1,32 +1,30 @@ class Services::Wordpress < Service - include ActionView::Helpers::TextHelper - include MarkdownifyHelper - MAX_CHARACTERS = 1000 - + attr_accessor :username, :password, :host, :path - + # uid = blog_id - + def provider "wordpress" end - - def post(post, url='') - res = Faraday.new(:url => "https://public-api.wordpress.com").post do |req| + + def post post, url='' + res = Faraday.new(url: "https://public-api.wordpress.com").post do |req| req.url "/rest/v1/sites/#{self.uid}/posts/new" req.body = post_body(post).to_json req.headers['Authorization'] = "Bearer #{self.access_token}" req.headers['Content-Type'] = 'application/json' end + JSON.parse res.env[:body] end - - def post_body(post, url='') - post_text = markdownify(post.text) - post_title = truncate(strip_markdown(post.text(:plain_text => true)), :length => 40, :separator => ' ') - - {:title => post_title, :content => post_text.html_safe} + + def post_body post + { + title: post.message.title(length: 40), + content: post.message.markdownified(disable_hovercards: true) + } end - + end diff --git a/app/models/status_message.rb b/app/models/status_message.rb index 4e0dfd127..7d1431cf8 100644 --- a/app/models/status_message.rb +++ b/app/models/status_message.rb @@ -5,7 +5,6 @@ class StatusMessage < Post include Diaspora::Taggable - include ActionView::Helpers::TextHelper include PeopleHelper acts_as_taggable_on :tags @@ -56,10 +55,6 @@ class StatusMessage < Post tag_stream(tag_ids) end - def text(opts = {}) - self.formatted_message(opts) - end - def raw_message read_attribute(:text) end @@ -77,12 +72,8 @@ class StatusMessage < Post self.raw_message.match(/#nsfw/i) || super end - def formatted_message(opts={}) - return self.raw_message unless self.raw_message - - escaped_message = opts[:plain_text] ? self.raw_message : ERB::Util.h(self.raw_message) - mentioned_message = Diaspora::Mentionable.format(escaped_message, self.mentioned_people, opts) - Diaspora::Taggable.format_tags(mentioned_message, opts.merge(:no_escape => true)) + def message + @message ||= Diaspora::MessageRenderer.new raw_message, mentioned_people: mentioned_people end def mentioned_people @@ -134,7 +125,7 @@ class StatusMessage < Post end def comment_email_subject - formatted_message(:plain_text => true) + message.title length: 70 end def first_photo_url(*args) @@ -142,7 +133,7 @@ class StatusMessage < Post end def text_and_photos_blank? - self.text.blank? && self.photos.blank? + self.raw_message.blank? && self.photos.blank? end def queue_gather_oembed_data diff --git a/app/presenters/o_embed_presenter.rb b/app/presenters/o_embed_presenter.rb index a3e875d30..b3788ca50 100644 --- a/app/presenters/o_embed_presenter.rb +++ b/app/presenters/o_embed_presenter.rb @@ -1,6 +1,5 @@ class OEmbedPresenter include PostsHelper - include ActionView::Helpers::TextHelper def initialize(post, opts = {}) @post = post @@ -13,14 +12,14 @@ class OEmbedPresenter def as_json(opts={}) { - :provider_name => "Diaspora", + :provider_name => "Diaspora", :provider_url => AppConfig.pod_uri.to_s, :type => 'rich', :version => '1.0', :title => post_title, :author_name => post_author, :author_url => post_author_url, - :width => @opts.fetch(:maxwidth, 516), + :width => @opts.fetch(:maxwidth, 516), :height => @opts.fetch(:maxheight, 320), :html => iframe_html } diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index fa179250a..5c6e410d2 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -1,6 +1,5 @@ class PostPresenter include PostsHelper - include ActionView::Helpers::TextHelper attr_accessor :post, :current_user @@ -47,7 +46,7 @@ class PostPresenter end def title - @post.text.present? ? post_page_title(@post) : I18n.translate('posts.presenter.title', :name => @post.author_name) + @post.message.present? ? @post.message.title : I18n.t('posts.presenter.title', name: @post.author_name) end def root diff --git a/app/views/comments/_comment.mobile.haml b/app/views/comments/_comment.mobile.haml index 342d2f777..abe2dddbf 100644 --- a/app/views/comments/_comment.mobile.haml +++ b/app/views/comments/_comment.mobile.haml @@ -16,4 +16,4 @@ = timeago(comment.created_at ? comment.created_at : Time.now) %div{:class => direction_for(comment.text)} - = markdownify(comment) + = comment.message.markdownified diff --git a/app/views/messages/_message.haml b/app/views/messages/_message.haml index 8c38eafa2..94b23aaa1 100644 --- a/app/views/messages/_message.haml +++ b/app/views/messages/_message.haml @@ -11,4 +11,4 @@ = timeago(message.created_at) %div{ :class => direction_for(message.text) } - = markdownify(message, :oembed => true) + = message.message.markdownified diff --git a/app/views/people/_profile_sidebar.html.haml b/app/views/people/_profile_sidebar.html.haml index 81827ea4b..1cb71e448 100644 --- a/app/views/people/_profile_sidebar.html.haml +++ b/app/views/people/_profile_sidebar.html.haml @@ -15,35 +15,35 @@ .profile_button = link_to content_tag(:div, nil, :class => 'icons-mention', :title => t('people.show.mention'), :id => 'mention_button'), new_status_message_path(:person_id => @person.id), :rel => 'facebox' .white_bar - + - if @contact.mutual? - - + + .profile_button = link_to content_tag(:div, nil, :class => 'icons-message', :title => t('people.show.message'), :id => 'message_button'), new_conversation_path(:contact_id => @contact.id, :name => @contact.person.name), :rel => 'facebox' .white_bar - + .profile_button = link_to content_tag(:div, nil, :class => 'icons-ignoreuser block_user', :title => t('ignore'), :id => 'block_user_button', :data => { :person_id => @person.id }), '#', :rel => "nofollow" if @block.blank? - - %br + + %br -if contact.sharing? || person == current_user.person %ul#profile_information - + - unless person.bio.blank? %li %h4 =t('.bio') %div{ :class => direction_for(person.bio) } - = markdownify(person.profile.bio, :oembed => true, :newlines => true) + = person.profile.bio_message.markdownified - unless person.profile.location.blank? %li %h4 =t('.location') %div{ :class => direction_for(person.location) } - = markdownify(person.location, :oembed => true, :newlines => true) + = person.profile.location_message.markdownified - unless person.gender.blank? %li @@ -66,7 +66,7 @@ = image_tag(photo.url(:thumb_small)) %br = link_to t('layouts.header.view_all'), person_photos_path(person) - + - if person == current_user.person %li.image_list %h4 diff --git a/app/views/status_messages/_status_message.mobile.haml b/app/views/status_messages/_status_message.mobile.haml index dbed137d2..5aba5358d 100644 --- a/app/views/status_messages/_status_message.mobile.haml +++ b/app/views/status_messages/_status_message.mobile.haml @@ -15,7 +15,7 @@ = image_tag post.image_url %div{:class => direction_for(post.text)} - != markdownify(post) + != post.message.markdownified - if post.o_embed_cache != o_embed_html post.o_embed_cache -if post.open_graph_cache diff --git a/app/views/users/public.atom.builder b/app/views/users/public.atom.builder index 90cbb1422..8dfd609d1 100644 --- a/app/views/users/public.atom.builder +++ b/app/views/users/public.atom.builder @@ -27,12 +27,11 @@ atom_feed({'xmlns:thr' => 'http://purl.org/syndication/thread/1.0', end @posts.each do |post| - post = post.absolute_root unless post.absolute_root.nil? if post.is_a? Reshare feed.entry post, :url => "#{@user.url}p/#{post.id}", :id => "#{@user.url}p/#{post.id}" do |entry| - entry.title post_page_title(post) - entry.content markdownify(post), :type => 'html' + entry.title post.message.title + entry.content post.message.markdownified(disable_hovercards: true), :type => 'html' entry.tag! 'activity:verb', 'http://activitystrea.ms/schema/1.0/post' entry.tag! 'activity:object-type', 'http://activitystrea.ms/schema/1.0/note' end diff --git a/config/initializers/load_libraries.rb b/config/initializers/load_libraries.rb index 327616125..29271dcfc 100644 --- a/config/initializers/load_libraries.rb +++ b/config/initializers/load_libraries.rb @@ -13,9 +13,6 @@ require 'typhoeus' # Presenters require 'post_presenter' -# Helpers -require 'markdownify_helper' - # Our libs require 'collect_user_photos' require 'diaspora' diff --git a/lib/diaspora.rb b/lib/diaspora.rb index db63f94c8..161dbae8f 100644 --- a/lib/diaspora.rb +++ b/lib/diaspora.rb @@ -7,6 +7,7 @@ module Diaspora require 'diaspora/parser' require 'diaspora/fetcher' require 'diaspora/markdownify' + require 'diaspora/message_renderer' require 'diaspora/mentionable' require 'diaspora/exporter' require 'diaspora/federated' diff --git a/lib/diaspora/markdownify/html.rb b/lib/diaspora/markdownify/html.rb index c31ddbc0c..60209dcd6 100644 --- a/lib/diaspora/markdownify/html.rb +++ b/lib/diaspora/markdownify/html.rb @@ -2,12 +2,10 @@ module Diaspora module Markdownify class HTML < Redcarpet::Render::HTML include ActionView::Helpers::TextHelper - include ActionView::Helpers::TagHelper - def autolink(link, type) - auto_link(link, :link => :urls, :html => { :target => "_blank" }) + def autolink link, type + auto_link(link, link: :urls, html: { target: "_blank" }) end - end end end diff --git a/lib/diaspora/message_renderer.rb b/lib/diaspora/message_renderer.rb new file mode 100644 index 000000000..9a62fe661 --- /dev/null +++ b/lib/diaspora/message_renderer.rb @@ -0,0 +1,233 @@ +module Diaspora + # Takes a raw message text and converts it to + # various desired target formats, respecting + # all possible formatting options supported + # by Diaspora + class MessageRenderer + class Processor + class << self + private :new + + def process message, options, &block + return '' if message.blank? # Optimize for empty message + processor = new message, options + processor.instance_exec(&block) + processor.message + end + end + + attr_reader :message, :options + + def initialize message, options + @message = message + @options = options + end + + def squish + @message = message.squish if options[:squish] + end + + def append_and_truncate + if options[:truncate] + @message = message.truncate options[:truncate]-options[:append].to_s.size + end + + message << options[:append].to_s + message << options[:append_after_truncate].to_s + end + + include ActionView::Helpers::TagHelper + def escape + if options[:escape] + # TODO: On Rails 4 port change this to ERB::Util.html_escape_once + # and remove the include + @message = escape_once message + + # Special case Hex entities since escape_once + # doesn't catch them. + # TODO: Watch for https://github.com/rails/rails/pull/9102 + # on whether this can be removed + @message = message.gsub(/&(#[xX][\dA-Fa-f]{1,4});/, '&\1;') + end + end + + def strip_markdown + renderer = Redcarpet::Markdown.new Redcarpet::Render::StripDown, options[:markdown_options] + @message = renderer.render(message).strip + end + + def markdownify + renderer = Diaspora::Markdownify::HTML.new options[:markdown_render_options] + markdown = Redcarpet::Markdown.new renderer, options[:markdown_options] + + @message = markdown.render message + end + + # In very clear cases, let newlines become
tags + # Grabbed from Github flavored Markdown + def process_newlines + message.gsub(/^[\w\<][^\n]*\n+/) do |x| + x =~ /\n{2}/ ? x : (x.strip!; x << " \n") + end + end + + def render_mentions + unless options[:disable_hovercards] || options[:mentioned_people].empty? + @message = Diaspora::Mentionable.format message, options[:mentioned_people] + end + + if options[:disable_hovercards] || options[:link_all_mentions] + @message = Diaspora::Mentionable.filter_for_aspects message, nil + else + make_mentions_plain_text + end + end + + def make_mentions_plain_text + @message = Diaspora::Mentionable.format message, [], plain_text: true + end + + def render_tags + @message = Diaspora::Taggable.format_tags message, no_escape: !options[:escape_tags] + end + end + + DEFAULTS = {mentioned_people: [], + link_all_mentions: false, + disable_hovercards: false, + truncate: false, + append: nil, + append_after_truncate: nil, + squish: false, + escape: true, + escape_tags: false, + markdown_options: { + autolink: true, + fenced_code_blocks: true, + space_after_headers: true, + strikethrough: true, + tables: true, + no_intra_emphasis: true, + }, + markdown_render_options: { + filter_html: true, + hard_wrap: true, + safe_links_only: true + }}.freeze + + delegate :empty?, :blank?, :present?, to: :raw + + # @param [String] raw_message Raw input text + # @param [Hash] opts Global options affecting output + # @option opts [Array] :mentioned_people ([]) List of people + # allowed to mention + # @option opts [Boolean] :link_all_mentions (false) Whether to link + # all mentions. This makes plain links to profiles for people not in + # :mentioned_people + # @option opts [Boolean] :disable_hovercards (true) Render all mentions + # as profile links. This implies :link_all_mentions and ignores + # :mentioned_people + # @option opts [#to_i, Boolean] :truncate (false) Truncate message to + # the specified length + # @option opts [String] :append (nil) Append text to the end of + # the (truncated) message, counts into truncation length + # @option opts [String] :append_after_truncate (nil) Append text to the end + # of the (truncated) message, doesn't count into the truncation length + # @option opts [Boolean] :squish (false) Squish the message, that is + # remove all surrounding and consecutive whitespace + # @option opts [Boolean] :escape (true) Escape HTML relevant characters + # in the message. Note that his option is ignored in the plaintext + # renderers. + # @option opts [Boolean] :escape_tags (false) Escape HTML relevant + # characters in tags when rendering them + # @option opts [Hash] :markdown_options Override default options passed + # to Redcarpet + # @option opts [Hash] :markdown_render_options Override default options + # passed to the Redcarpet renderer + def initialize raw_message, opts={} + @raw_message = raw_message + @options = DEFAULTS.deep_merge opts + end + + # @param [Hash] opts Override global output options, see {#initialize} + def plain_text opts={} + process(opts) { + make_mentions_plain_text + squish + append_and_truncate + } + end + + # @param [Hash] opts Override global output options, see {#initialize} + def plain_text_without_markdown opts={} + process(opts) { + make_mentions_plain_text + strip_markdown + squish + append_and_truncate + } + end + + # @param [Hash] opts Override global output options, see {#initialize} + def html opts={} + process(opts) { + escape + render_mentions + render_tags + squish + append_and_truncate + }.html_safe + end + + # @param [Hash] opts Override global output options, see {#initialize} + def markdownified opts={} + process(opts) { + process_newlines + markdownify + render_mentions + render_tags + squish + append_and_truncate + }.html_safe + end + + # Get a short summary of the message + # @param [Hash] opts Additional options + # @option opts [Integer] :length (20 | first heading) Truncate the title to + # this length. If not given defaults to 20 and to not truncate + # if a heading is found. + def title opts={} + # Setext-style header + heading = if /\A(?.{1,200})\n(?:={1,200}|-{1,200})(?:\r?\n|$)/ =~ @raw_message.lstrip + setext_content + # Atx-style header + elsif /\A\#{1,6}\s+(?.{1,200}?)(?:\s+#+)?(?:\r?\n|$)/ =~ @raw_message.lstrip + atx_content + end + + heading &&= heading.strip + + if heading && opts[:length] + heading.truncate opts[:length] + elsif heading + heading + else + plain_text_without_markdown squish: true, truncate: opts.fetch(:length, 20) + end + end + + def raw + @raw_message + end + + def to_s + plain_text + end + + private + + def process opts, &block + Processor.process(@raw_message, @options.deep_merge(opts), &block) + end + end +end diff --git a/spec/helpers/markdownify_helper_spec.rb b/spec/helpers/markdownify_helper_spec.rb deleted file mode 100644 index 130bc1048..000000000 --- a/spec/helpers/markdownify_helper_spec.rb +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright (c) 2010-2011, Diaspora Inc. This file is -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. - -require 'spec_helper' - -describe MarkdownifyHelper do - describe "#markdownify" do - describe "not doing something dumb" do - it "strips out script tags" do - markdownify("").should == - "

alert('XSS is evil')

\n" - end - - it 'strips onClick handlers from links' do - omghax = '[XSS](http://joindiaspora.com/" onClick="$\(\'a\'\).remove\(\))' - markdownify(omghax).should_not match(/ onClick/i) - end - end - - it 'does not barf if message is nil' do - markdownify(nil).should == '' - end - - it 'autolinks standard url links' do - markdownified = markdownify("http://joindiaspora.com/") - - doc = Nokogiri.parse(markdownified) - - link = doc.css("a") - - link.attr("href").value.should == "http://joindiaspora.com/" - end - - context 'when formatting status messages' do - it "should leave tags intact" do - message = FactoryGirl.create(:status_message, - :author => alice.person, - :text => "I love #markdown") - formatted = markdownify(message) - formatted.should =~ %r{#markdown} - end - - it 'should leave multi-underscore tags intact' do - message = FactoryGirl.create( - :status_message, - :author => alice.person, - :text => "Here is a #multi_word tag" - ) - formatted = markdownify(message) - formatted.should =~ %r{Here is a #multi_word tag} - - message = FactoryGirl.create( - :status_message, - :author => alice.person, - :text => "Here is a #multi_word_tag yo" - ) - formatted = markdownify(message) - formatted.should =~ %r{Here is a #multi_word_tag yo} - end - - it "should leave mentions intact" do - message = FactoryGirl.create(:status_message, - :author => alice.person, - :text => "Hey @{Bob; #{bob.diaspora_handle}}!") - formatted = markdownify(message) - formatted.should =~ /hovercard/ - end - - it "should leave mentions intact for real diaspora handles" do - new_person = FactoryGirl.create(:person, :diaspora_handle => 'maxwell@joindiaspora.com') - message = FactoryGirl.create(:status_message, - :author => alice.person, - :text => "Hey @{maxwell@joindiaspora.com; #{new_person.diaspora_handle}}!") - formatted = markdownify(message) - formatted.should =~ /hovercard/ - end - - it 'should process text with both a hashtag and a link' do - message = FactoryGirl.create(:status_message, - :author => alice.person, - :text => "Test #tag?\nhttps://joindiaspora.com\n") - formatted = markdownify(message) - formatted.should == %{

Test #tag?
\nhttps://joindiaspora.com

\n} - end - - it 'should process text with a header' do - message = "# I love markdown" - markdownify(message).should match "I love markdown" - end - end - end - - describe "#strip_markdown" do - it 'does not remove markdown in links' do - message = "some text and here comes http://exampe.org/foo_bar_baz a link" - strip_markdown(message).should match message - end - - it 'does not destroy hashtag that starts a line' do - message = "#hashtag message" - strip_markdown(message).should match message - end - end -end diff --git a/spec/helpers/notifier_helper_spec.rb b/spec/helpers/notifier_helper_spec.rb index 23b178101..9f3e887e9 100644 --- a/spec/helpers/notifier_helper_spec.rb +++ b/spec/helpers/notifier_helper_spec.rb @@ -5,8 +5,6 @@ require 'spec_helper' describe NotifierHelper do - include MarkdownifyHelper - describe '#post_message' do before do # post for truncate test diff --git a/spec/helpers/posts_helper_spec.rb b/spec/helpers/posts_helper_spec.rb index 3d31563cc..1d1d6edee 100644 --- a/spec/helpers/posts_helper_spec.rb +++ b/spec/helpers/posts_helper_spec.rb @@ -12,30 +12,11 @@ describe PostsHelper do end context 'with posts with text' do - context 'when :length is passed in parameters' do - it 'returns string of size less or equal to :length' do - @sm = double(:text => "## My title\n Post content...") - string_size = 12 - post_page_title(@sm, :length => string_size ).size.should <= string_size - end - end - context 'when :length is not passed in parameters' do - context 'with a Markdown header of less than 200 characters on first line'do - it 'returns atx style header' do - @sm = double(:text => "## My title\n Post content...") - post_page_title(@sm).should == "## My title" - end - it 'returns setext style header' do - @sm = double(:text => "My title \n======\n Post content...") - post_page_title(@sm).should == "My title \n======" - end - end - context 'without a Markdown header of less than 200 characters on first line 'do - it 'truncates posts to the 20 first characters' do - @sm = double(:text => "Very, very, very long post") - post_page_title(@sm).should == "Very, very, very ..." - end - end + it "delegates to message.title" do + message = double + message.should_receive(:title) + post = double(message: message) + post_page_title(post) end end end diff --git a/spec/lib/diaspora/message_renderer_spec.rb b/spec/lib/diaspora/message_renderer_spec.rb new file mode 100644 index 000000000..0366720eb --- /dev/null +++ b/spec/lib/diaspora/message_renderer_spec.rb @@ -0,0 +1,175 @@ +require 'spec_helper' + +describe Diaspora::MessageRenderer do + def message text, opts={} + Diaspora::MessageRenderer.new(text, opts) + end + + describe '#title' do + context 'when :length is passed in parameters' do + it 'returns string of size less or equal to :length' do + string_size = 12 + title = message("## My title\n Post content...").title(length: string_size) + expect(title.size).to be <= string_size + end + end + + context 'when :length is not passed in parameters' do + context 'with a Markdown header of less than 200 characters on first line' do + it 'returns atx style header' do + expect(message("## My title\n Post content...").title).to eq "My title" + expect(message("## My title ##\n Post content...").title).to eq "My title" + end + + it 'returns setext style header' do + expect(message("My title \n======\n Post content...").title).to eq "My title" + end + end + + context 'without a Markdown header of less than 200 characters on first line ' do + it 'truncates posts to the 20 first characters' do + expect(message("Very, very, very long post").title).to eq "Very, very, very ..." + end + end + end + end + + describe '#html' do + it 'escapes the message' do + xss = " " + + expect(message(xss).html).to_not include xss + end + + it 'is html_safe' do + expect(message("hey guys").html).to be_html_safe + end + + it 'should leave HTML entities intact' do + entities = '& ß ' ' "' + expect(message(entities).html).to eq entities + end + + context 'with mentions' do + it 'makes hovercard links for mentioned people' do + expect( + message( + "@{Bob; #{bob.person.diaspora_handle}}", + mentioned_people: [bob.person] + ).html + ).to include 'hovercard' + end + + it 'makes plaintext out of mentions of people not in the posts aspects' do + expect( + message("@{Bob; #{bob.person.diaspora_handle}}").html + ).to_not include 'href' + end + + context 'linking all mentions' do + it 'makes plain links for people not in the post aspects' do + message = message("@{Bob; #{bob.person.diaspora_handle}}", link_all_mentions: true).html + expect(message).to_not include 'hovercard' + expect(message).to include '/u/bob' + end + + it "makes no hovercards if they're disabled" do + message = message( + "@{Bob; #{bob.person.diaspora_handle}}", + mentioned_people: [bob.person], + disable_hovercards: true + ).html + expect(message).to_not include 'hovercard' + expect(message).to include '/u/bob' + end + end + end + end + + describe "#markdownified" do + describe "not doing something dumb" do + it "strips out script tags" do + expect( + message("").markdownified + ).to eq "

alert('XSS is evil')

\n" + end + + it 'strips onClick handlers from links' do + expect( + message('[XSS](http://joindiaspora.com/" onClick="$\(\'a\'\).remove\(\))').markdownified + ).to_not match(/ onClick/i) + end + end + + it 'does not barf if message is nil' do + expect(message(nil).markdownified).to eq '' + end + + it 'autolinks standard url links' do + expect( + message("http://joindiaspora.com/" + ).markdownified).to include 'href="http://joindiaspora.com/"' + end + + context 'when formatting status messages' do + it "should leave tags intact" do + expect( + message("I love #markdown").markdownified + ).to match %r{#markdown} + end + + it 'should leave multi-underscore tags intact' do + expect( + message("Here is a #multi_word tag").markdownified + ).to match %r{Here is a #multi_word tag} + + expect( + message("Here is a #multi_word_tag yo").markdownified + ).to match %r{Here is a #multi_word_tag yo} + end + + it "should leave mentions intact" do + expect( + message("Hey @{Bob; #{bob.diaspora_handle}}!", mentioned_people: [bob.person]).markdownified + ).to match(/hovercard/) + end + + it "should leave mentions intact for real diaspora handles" do + new_person = FactoryGirl.create(:person, diaspora_handle: 'maxwell@joindiaspora.com') + expect( + message( + "Hey @{maxwell@joindiaspora.com; #{new_person.diaspora_handle}}!", + mentioned_people: [new_person] + ).markdownified + ).to match(/hovercard/) + end + + it 'should process text with both a hashtag and a link' do + expect( + message("Test #tag?\nhttps://joindiaspora.com\n").markdownified + ).to eq %{

Test #tag?
\nhttps://joindiaspora.com

\n} + end + + it 'should process text with a header' do + expect(message("# I love markdown").markdownified).to match "I love markdown" + end + + it 'should leave HTML entities intact' do + entities = '& ß ' ' "' + expect(message(entities).markdownified).to eq "

#{entities}

\n" + end + end + end + + describe "#plain_text_without_markdown" do + it 'does not remove markdown in links' do + text = "some text and here comes http://exampe.org/foo_bar_baz a link" + expect(message(text).plain_text_without_markdown).to eq text + end + + it 'does not destroy hashtag that starts a line' do + text = "#hashtag message" + expect(message(text).plain_text_without_markdown).to eq text + end + end +end diff --git a/spec/mailers/notifier_spec.rb b/spec/mailers/notifier_spec.rb index 47b52139e..1f59a4bb2 100644 --- a/spec/mailers/notifier_spec.rb +++ b/spec/mailers/notifier_spec.rb @@ -1,9 +1,6 @@ require 'spec_helper' describe Notifier do - include ActionView::Helpers::TextHelper - include MarkdownifyHelper - let(:person) { FactoryGirl.create(:person) } before do @@ -120,7 +117,7 @@ describe Notifier do end it 'BODY: contains the truncated original post' do - @mail.body.encoded.should include(@sm.formatted_message) + @mail.body.encoded.should include(@sm.message.plain_text) end it 'BODY: contains the name of person liking' do @@ -150,7 +147,7 @@ describe Notifier do end it 'BODY: contains the truncated original post' do - @mail.body.encoded.should include(@sm.formatted_message) + @mail.body.encoded.should include(@sm.message.plain_text) end it 'BODY: contains the name of person liking' do @@ -224,7 +221,7 @@ describe Notifier do end it 'SUBJECT: has a snippet of the post contents, without markdown and without newlines' do - comment_mail.subject.should == "Re: Headline It's really sunny outside today, and this is a super long ..." + comment_mail.subject.should == "Re: Headline" end context 'BODY' do @@ -265,7 +262,7 @@ describe Notifier do end it 'SUBJECT: has a snippet of the post contents, without markdown and without newlines' do - comment_mail.subject.should == "Re: Headline It's really sunny outside today, and this is a super long ..." + comment_mail.subject.should == "Re: Headline" end context 'BODY' do diff --git a/spec/models/services/facebook_spec.rb b/spec/models/services/facebook_spec.rb index 2c1d9d882..221ea5a3c 100644 --- a/spec/models/services/facebook_spec.rb +++ b/spec/models/services/facebook_spec.rb @@ -25,17 +25,17 @@ describe Services::Facebook do end it 'removes text formatting markdown from post text' do - message = "Text with some **bolded** and _italic_ parts." - post = double(:text => message, :photos => []) + message = double + message.should_receive(:plain_text_without_markdown).and_return("") + post = double(message: message, photos: []) post_params = @service.create_post_params(post) - post_params[:message].should match "Text with some bolded and italic parts." end it 'does not add post link when no photos' do - message = "Text with some **bolded** and _italic_ parts." - post = double(:text => message, :photos => []) + message = "Some text." + post = double(message: double(plain_text_without_markdown: message), photos: []) post_params = @service.create_post_params(post) - post_params[:message].should match "Text with some bolded and italic parts." + post_params[:message].should_not include "http" end it 'sets facebook id on post' do diff --git a/spec/models/services/twitter_spec.rb b/spec/models/services/twitter_spec.rb index 463ae8957..5a6bfecbd 100644 --- a/spec/models/services/twitter_spec.rb +++ b/spec/models/services/twitter_spec.rb @@ -38,9 +38,10 @@ describe Services::Twitter do end it 'removes text formatting markdown from post text' do - message = "Text with some **bolded** and _italic_ parts." - post = double(:text => message, :photos => []) - @service.send(:build_twitter_post, post).should match "Text with some bolded and italic parts." + message = double + message.should_receive(:plain_text_without_markdown).and_return("") + post = double(message: message, photos: []) + @service.send(:build_twitter_post, post) end end @@ -53,19 +54,19 @@ describe Services::Twitter do it "should not truncate a short message" do short_message = SecureRandom.hex(20) - short_post = double(:text => short_message, :photos => []) + short_post = double(message: double(plain_text_without_markdown: short_message), photos: []) @service.send(:build_twitter_post, short_post).should match short_message end it "should truncate a long message" do long_message = SecureRandom.hex(220) - long_post = double(:text => long_message, :id => 1, :photos => []) + long_post = double(message: double(plain_text_without_markdown: long_message), id: 1, photos: []) @service.send(:build_twitter_post, long_post).length.should be < long_message.length end 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_post = double(:text => long_message, :id => 1, :photos => []) + long_post = double(message: double(plain_text_without_markdown: long_message), id: 1, photos: []) @post.text = long_message answer = @service.send(:build_twitter_post, @post) @@ -74,7 +75,7 @@ describe Services::Twitter do it "should not cut links when truncating a post" do long_message = SecureRandom.hex(40) + " http://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + SecureRandom.hex(55) - long_post = double(:text => long_message, :id => 1, :photos => []) + long_post = double(message: double(plain_text_without_markdown: long_message), id: 1, photos: []) answer = @service.send(:build_twitter_post, long_post) answer.should match /\.\.\./ @@ -83,7 +84,7 @@ describe Services::Twitter do it "should append the otherwise-cut link when truncating a post" do long_message = "http://joindiaspora.com/a-very-long-decoy-url.html " + SecureRandom.hex(20) + " http://joindiaspora.com/a-very-long-url-name-that-will-be-shortened.html " + SecureRandom.hex(55) + " http://joindiaspora.com/a-very-long-decoy-url-part-2.html" - long_post = double(:text => long_message, :id => 1, :photos => []) + long_post = double(message: double(plain_text_without_markdown: long_message), id: 1, photos: []) answer = @service.send(:build_twitter_post, long_post) answer.should match /\.\.\./ @@ -99,7 +100,7 @@ describe Services::Twitter 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_post = double(:text => long_message, :id => 1, :photos => []) + long_post = double(message: double(plain_text_without_markdown: long_message), id: 1, photos: []) answer = @service.send(:build_twitter_post, long_post) answer.should match /\.\.\./ @@ -107,7 +108,7 @@ describe Services::Twitter do it "should not truncate a message of maximum length" do exact_size_message = SecureRandom.hex(70) - exact_size_post = double(:text => exact_size_message, :id => 1, :photos => []) + exact_size_post = double(message: double(plain_text_without_markdown: exact_size_message), id: 1, photos: []) answer = @service.send(:build_twitter_post, exact_size_post) answer.should match exact_size_message diff --git a/spec/models/status_message_spec.rb b/spec/models/status_message_spec.rb index 7ee8b4bc5..221bd4966 100644 --- a/spec/models/status_message_spec.rb +++ b/spec/models/status_message_spec.rb @@ -150,18 +150,6 @@ STR @sm = FactoryGirl.create(:status_message, :text => @test_string ) end - describe '#formatted_message' do - it 'escapes the message' do - xss = " " - @sm.text << xss - - @sm.formatted_message.should_not include xss - end - it 'is html_safe' do - @sm.formatted_message.html_safe?.should be_true - end - end - describe '#create_mentions' do it 'creates a mention for everyone mentioned in the message' do Diaspora::Mentionable.should_receive(:people_from_string).and_return(@people) diff --git a/spec/presenters/post_presenter_spec.rb b/spec/presenters/post_presenter_spec.rb index dca62936e..19d2bdafb 100644 --- a/spec/presenters/post_presenter_spec.rb +++ b/spec/presenters/post_presenter_spec.rb @@ -65,32 +65,17 @@ describe PostPresenter do describe '#title' do context 'with posts with text' do - context 'with a Markdown header of less than 200 characters on first line'do - it 'returns atx style header' do - @sm = double(:text => "## My title\n Post content...") - @presenter.post = @sm - @presenter.title.should == "## My title" - end - - it 'returns setext style header' do - @sm = double(:text => "My title \n======\n Post content...") - @presenter.post = @sm - @presenter.title.should == "My title \n======" - end - end - - context 'without a Markdown header of less than 200 characters on first line 'do - it 'truncates post to the 20 first characters' do - @sm = double(:text => "Very, very, very long post") - @presenter.post = @sm - @presenter.title.should == "Very, very, very ..." - end + it "delegates to message.title" do + message = double(present?: true) + message.should_receive(:title) + @presenter.post = double(message: message) + @presenter.title end end context 'with posts without text' do it ' displays a messaage with the post class' do - @sm = double(:text => "", :author => bob.person, :author_name => bob.person.name) + @sm = double(message: double(present?: false), author: bob.person, author_name: bob.person.name) @presenter.post = @sm @presenter.title.should == "A post from #{@sm.author.name}" end