From aa4205482a4af317ec26fc686793b57f02a6864a Mon Sep 17 00:00:00 2001 From: Tom Hughes Date: Wed, 15 Feb 2012 00:48:52 +0000 Subject: [PATCH] Treat all newly entered blocks of text as Markdown --- Gemfile | 3 + Gemfile.lock | 2 + app/helpers/application_helper.rb | 8 --- app/models/diary_comment.rb | 12 ++++ app/models/diary_entry.rb | 12 ++++ app/models/message.rb | 12 ++++ app/models/user.rb | 9 ++- app/models/user_block.rb | 17 +++++- app/views/diary_entry/_diary_comment.html.erb | 2 +- app/views/diary_entry/_diary_entry.html.erb | 2 +- app/views/diary_entry/comments.html.erb | 2 +- app/views/diary_entry/rss.rss.builder | 2 +- app/views/message/read.html.erb | 4 +- .../diary_comment_notification.text.erb | 2 +- .../notifier/message_notification.html.erb | 2 +- .../notifier/message_notification.text.erb | 2 +- app/views/user/_user.html.erb | 2 +- app/views/user/view.html.erb | 2 +- app/views/user_blocks/show.html.erb | 2 +- db/migrate/20120214210114_add_text_format.rb | 21 +++++++ lib/rich_text.rb | 57 +++++++++++++++++++ 21 files changed, 154 insertions(+), 23 deletions(-) create mode 100644 db/migrate/20120214210114_add_text_format.rb create mode 100644 lib/rich_text.rb diff --git a/Gemfile b/Gemfile index c1bb2f50b..e28317997 100644 --- a/Gemfile +++ b/Gemfile @@ -22,6 +22,9 @@ gem 'http_accept_language', '>= 1.0.2' gem 'paperclip', '~> 2.0' gem 'deadlock_retry', '>= 1.2.0' +# Markdown formatting support +gem 'redcarpet' + # Character conversion support for ruby 1.8 gem 'iconv', :platforms => :ruby_18 diff --git a/Gemfile.lock b/Gemfile.lock index 4709cd195..0dcb5ccff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -120,6 +120,7 @@ GEM rake (0.9.2.2) rdoc (3.12) json (~> 1.4) + redcarpet (2.1.0) rinku (1.5.1) ruby-openid (2.1.8) sanitize (2.0.3) @@ -168,6 +169,7 @@ DEPENDENCIES pg rails (= 3.2.2) rails-i18n (>= 0.5.1) + redcarpet rinku (>= 1.2.2) sanitize sass-rails (~> 3.2.3) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4aec9f5c1..7a72932f5 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,14 +1,6 @@ module ApplicationHelper require 'rexml/document' - def sanitize(text) - Sanitize.clean(text, Sanitize::Config::OSM).html_safe - end - - def htmlize(text) - return linkify(sanitize(simple_format(text))) - end - def linkify(text) if text.html_safe? Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")).html_safe diff --git a/app/models/diary_comment.rb b/app/models/diary_comment.rb index b915e027a..075d288ed 100644 --- a/app/models/diary_comment.rb +++ b/app/models/diary_comment.rb @@ -7,6 +7,12 @@ class DiaryComment < ActiveRecord::Base attr_accessible :body + after_initialize :set_defaults + + def body + RichText.new(read_attribute(:body_format), read_attribute(:body)) + end + def digest md5 = Digest::MD5.new md5 << diary_entry_id.to_s @@ -15,4 +21,10 @@ class DiaryComment < ActiveRecord::Base md5 << body md5.hexdigest end + +private + + def set_defaults + self.body_format = "markdown" unless self.attribute_present?(:body_format) + end end diff --git a/app/models/diary_entry.rb b/app/models/diary_entry.rb index 1d836353f..64a412d28 100644 --- a/app/models/diary_entry.rb +++ b/app/models/diary_entry.rb @@ -25,4 +25,16 @@ class DiaryEntry < ActiveRecord::Base validates_associated :language attr_accessible :title, :body, :language_code, :latitude, :longitude + + after_initialize :set_defaults + + def body + RichText.new(read_attribute(:body_format), read_attribute(:body)) + end + +private + + def set_defaults + self.body_format = "markdown" unless self.attribute_present?(:body_format) + end end diff --git a/app/models/message.rb b/app/models/message.rb index 0b3416003..feceec5c0 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -11,6 +11,12 @@ class Message < ActiveRecord::Base attr_accessible :title, :body + after_initialize :set_defaults + + def body + RichText.new(read_attribute(:body_format), read_attribute(:body)) + end + def digest md5 = Digest::MD5.new md5 << from_user_id.to_s @@ -20,4 +26,10 @@ class Message < ActiveRecord::Base md5 << body md5.hexdigest end + +private + + def set_defaults + self.body_format = "markdown" unless self.attribute_present?(:body_format) + end end diff --git a/app/models/user.rb b/app/models/user.rb index 0c9e76d54..3b55040c6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -44,7 +44,7 @@ class User < ActiveRecord::Base attr_accessible :display_name, :email, :email_confirmation, :openid_url, :pass_crypt, :pass_crypt_confirmation, :consider_pd - after_initialize :set_creation_time + after_initialize :set_defaults before_save :encrypt_password has_attached_file :image, @@ -101,6 +101,10 @@ class User < ActiveRecord::Base return el1 end + def description + RichText.new(read_attribute(:description_format), read_attribute(:description)) + end + def languages attribute_present?(:languages) ? read_attribute(:languages).split(/ *, */) : [] end @@ -220,8 +224,9 @@ class User < ActiveRecord::Base private - def set_creation_time + def set_defaults self.creation_time = Time.now.getutc unless self.attribute_present?(:creation_time) + self.description_format = "markdown" unless self.attribute_present?(:description_format) end def encrypt_password diff --git a/app/models/user_block.rb b/app/models/user_block.rb index 7bf8f86b5..8821926bb 100644 --- a/app/models/user_block.rb +++ b/app/models/user_block.rb @@ -5,8 +5,16 @@ class UserBlock < ActiveRecord::Base belongs_to :creator, :class_name => "User", :foreign_key => :creator_id belongs_to :revoker, :class_name => "User", :foreign_key => :revoker_id + after_initialize :set_defaults + PERIODS = USER_BLOCK_PERIODS + ## + # return a renderable version of the reason text. + def reason + RichText.new(read_attribute(:reason_format), read_attribute(:reason)) + end + ## # returns true if the block is currently active (i.e: the user can't # use the API). @@ -25,7 +33,14 @@ class UserBlock < ActiveRecord::Base }, :without_protection => true) end - private +private + + ## + # set default values for new records. + def set_defaults + self.reason_format = "markdown" unless self.attribute_present?(:reason_format) + end + ## # validate that only moderators are allowed to change the # block. this should be caught and dealt with in the controller, diff --git a/app/views/diary_entry/_diary_comment.html.erb b/app/views/diary_entry/_diary_comment.html.erb index 05cb80157..463c2ad81 100644 --- a/app/views/diary_entry/_diary_comment.html.erb +++ b/app/views/diary_entry/_diary_comment.html.erb @@ -1,6 +1,6 @@ <%= user_thumbnail diary_comment.user %>

<%= raw(t('diary_entry.diary_comment.comment_from', :link_user => (link_to h(diary_comment.user.display_name), :controller => 'user', :action => 'view', :display_name => diary_comment.user.display_name), :comment_created_at => l(diary_comment.created_at, :format => :friendly))) %>

-<%= htmlize(diary_comment.body) %> +<%= diary_comment.body.to_html %> <%= if_administrator(:span) do %> <%= link_to t('diary_entry.diary_comment.hide_link'), {:action => 'hidecomment', :display_name => diary_comment.diary_entry.user.display_name, :id => diary_comment.diary_entry.id, :comment => diary_comment.id}, {:confirm => t('diary_entry.diary_comment.confirm')} %> <% end %> diff --git a/app/views/diary_entry/_diary_entry.html.erb b/app/views/diary_entry/_diary_entry.html.erb index 297f74ef9..21c3ef622 100644 --- a/app/views/diary_entry/_diary_entry.html.erb +++ b/app/views/diary_entry/_diary_entry.html.erb @@ -1,7 +1,7 @@ <%= link_to h(diary_entry.title), :action => 'view', :display_name => diary_entry.user.display_name, :id => diary_entry.id %>
- <%= htmlize(diary_entry.body) %> + <%= diary_entry.body.to_html %>
<% if diary_entry.latitude and diary_entry.longitude %> diff --git a/app/views/diary_entry/comments.html.erb b/app/views/diary_entry/comments.html.erb index b506ddfb0..f477ab8b6 100644 --- a/app/views/diary_entry/comments.html.erb +++ b/app/views/diary_entry/comments.html.erb @@ -11,7 +11,7 @@ <%= link_to comment.diary_entry.title, :action => :view, :display_name => comment.diary_entry.user.display_name, :id => comment.diary_entry.id %> <%= t 'diary_entry.comments.ago', :ago => time_ago_in_words(comment.created_at) %> - <%= htmlize(comment.body) %> + <%= comment.body.to_html %> <% end -%> diff --git a/app/views/diary_entry/rss.rss.builder b/app/views/diary_entry/rss.rss.builder index 4c9670a6d..7ee36e9bd 100644 --- a/app/views/diary_entry/rss.rss.builder +++ b/app/views/diary_entry/rss.rss.builder @@ -20,7 +20,7 @@ xml.rss("version" => "2.0", xml.title h(entry.title) xml.link url_for(:action => "view", :id => entry.id, :display_name => entry.user.display_name, :only_path => false) xml.guid url_for(:action => "view", :id => entry.id, :display_name => entry.user.display_name, :only_path => false) - xml.description htmlize(entry.body) + xml.description entry.body.to_html xml.author entry.user.display_name xml.pubDate entry.created_at.to_s(:rfc822) xml.comments url_for(:action => "view", :id => entry.id, :display_name => entry.user.display_name, :anchor => "comments", :only_path => false) diff --git a/app/views/message/read.html.erb b/app/views/message/read.html.erb index 6bad015cc..d829c79e9 100644 --- a/app/views/message/read.html.erb +++ b/app/views/message/read.html.erb @@ -20,7 +20,7 @@ - <%= htmlize(@message.body) %> + <%= @message.body.to_html %> @@ -57,7 +57,7 @@ - <%= htmlize(@message.body) %> + <%= @message.body.to_html %> diff --git a/app/views/notifier/diary_comment_notification.text.erb b/app/views/notifier/diary_comment_notification.text.erb index 193e10de9..7d112a42b 100644 --- a/app/views/notifier/diary_comment_notification.text.erb +++ b/app/views/notifier/diary_comment_notification.text.erb @@ -3,7 +3,7 @@ <%= t'notifier.diary_comment_notification.header', :from_user => @from_user, :subject => @title %> == -<%= raw @text %> +<%= raw @text.to_text %> == <%= t'notifier.diary_comment_notification.footer', :readurl => @readurl, :commenturl => @commenturl, :replyurl => @replyurl %> diff --git a/app/views/notifier/message_notification.html.erb b/app/views/notifier/message_notification.html.erb index ef55b9b96..0b2ff9e69 100644 --- a/app/views/notifier/message_notification.html.erb +++ b/app/views/notifier/message_notification.html.erb @@ -3,7 +3,7 @@

<%= raw t'notifier.message_notification.header', :from_user => link_to(@from_user, :host => SERVER_URL, :controller => :user, :action => :view, :display_name => @from_user), :subject => @title %>

== -<%= htmlize @text %> +<%= @text.to_html %> ==

diff --git a/app/views/notifier/message_notification.text.erb b/app/views/notifier/message_notification.text.erb index 25b3c0498..10a9ff361 100644 --- a/app/views/notifier/message_notification.text.erb +++ b/app/views/notifier/message_notification.text.erb @@ -3,7 +3,7 @@ <%= raw t'notifier.message_notification.header', :from_user => @from_user, :subject => @title %> == -<%= raw @text %> +<%= raw @text.to_text %> == <%= raw t'notifier.message_notification.footer1', :readurl => @readurl %> diff --git a/app/views/user/_user.html.erb b/app/views/user/_user.html.erb index 4f62a51e9..4f2f59c92 100644 --- a/app/views/user/_user.html.erb +++ b/app/views/user/_user.html.erb @@ -19,7 +19,7 @@ %> <% end %>

- <%= htmlize(user.description) %> + <%= user.description.to_html %> <%= check_box_tag "user_#{user.id}", "", false, :name => "user[#{user.id}]" %> diff --git a/app/views/user/view.html.erb b/app/views/user/view.html.erb index b323ff158..d9a65b342 100644 --- a/app/views/user/view.html.erb +++ b/app/views/user/view.html.erb @@ -103,7 +103,7 @@

<%= t 'user.view.description' %>

-
<%= htmlize(@this_user.description) %>
+
<%= @this_user.description.to_html %>
<% if @user and @this_user.id == @user.id %>
diff --git a/app/views/user_blocks/show.html.erb b/app/views/user_blocks/show.html.erb index 4ba69a73f..2311541d9 100644 --- a/app/views/user_blocks/show.html.erb +++ b/app/views/user_blocks/show.html.erb @@ -18,7 +18,7 @@

<%= t'user_block.show.status' %>: <%= block_status(@user_block) %>

<%= t'user_block.show.reason' %>

-<%= htmlize(@user_block.reason) %> +<%= @user_block.reason.to_html %> <% if @user_block.ends_at > Time.now.getutc %> <% if @user and @user.id == @user_block.creator_id %> diff --git a/db/migrate/20120214210114_add_text_format.rb b/db/migrate/20120214210114_add_text_format.rb new file mode 100644 index 000000000..f448223c3 --- /dev/null +++ b/db/migrate/20120214210114_add_text_format.rb @@ -0,0 +1,21 @@ +require 'migrate' + +class AddTextFormat < ActiveRecord::Migration + def up + create_enumeration :format_enum, ["html", "markdown"] + add_column :users, :description_format, :format_enum, :null => false, :default => "html" + add_column :user_blocks, :reason_format, :format_enum, :null => false, :default => "html" + add_column :diary_entries, :body_format, :format_enum, :null => false, :default => "html" + add_column :diary_comments, :body_format, :format_enum, :null => false, :default => "html" + add_column :messages, :body_format, :format_enum, :null => false, :default => "html" + end + + def down + remove_column :messages, :body_format + remove_column :diary_comments, :body_format + remove_column :diary_entries, :body_format + remove_column :user_blocks, :reason_format + remove_column :users, :description_format + drop_enumeration :format_enum + end +end diff --git a/lib/rich_text.rb b/lib/rich_text.rb new file mode 100644 index 000000000..ec5e9e473 --- /dev/null +++ b/lib/rich_text.rb @@ -0,0 +1,57 @@ +module RichText + def self.new(format, text) + case format + when "html"; HTML.new(text || "") + when "markdown"; Markdown.new(text || "") + else; nil + end + end + + class HTML < String + include ActionView::Helpers::TextHelper + include ActionView::Helpers::TagHelper + + def to_html + linkify(sanitize(simple_format(self))) + end + + def to_text + self + end + + private + + def sanitize(text) + Sanitize.clean(text, Sanitize::Config::OSM).html_safe + end + + def linkify(text) + if text.html_safe? + Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")).html_safe + else + Rinku.auto_link(text, :urls, tag_options(:rel => "nofollow")) + end + end + end + + class Markdown < String + def to_html + html_parser.render(self).html_safe + end + + def to_text + self + end + + private + + def html_parser + @@html_renderer ||= Redcarpet::Render::XHTML.new({ + :filter_html => true, :safe_links_only => true + }) + @@html_parser ||= Redcarpet::Markdown.new(@@html_renderer, { + :no_intra_emphasis => true, :autolink => true, :space_after_headers => true + }) + end + end +end -- 2.43.2