diff --git a/Gemfile b/Gemfile index 525d238fd..05d9ec2e9 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,7 @@ gem 'omniauth-google-oauth2' gem 'kaminari' gem 'ancestry' gem 'acts-as-taggable-on' -gem "responders" +gem 'responders' gem 'foundation-rails' gem 'foundation_rails_helper' gem 'acts_as_votable' @@ -40,6 +40,7 @@ gem 'social-share-button' gem 'initialjs-rails', '0.2.0' gem 'unicorn' gem 'paranoia' +gem 'rinku', require: 'rails_rinku' gem 'savon' gem 'dalli' gem 'rollbar', '~> 2.2.1' diff --git a/Gemfile.lock b/Gemfile.lock index 7da5c9fe2..6dfcba2b0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -294,6 +294,7 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 3.0) netrc (~> 0.7) + rinku (1.7.3) rollbar (2.2.1) rspec (3.3.0) rspec-core (~> 3.3.0) @@ -444,6 +445,7 @@ DEPENDENCIES quiet_assets rails (= 4.2.4) responders + rinku rollbar (~> 2.2.1) rspec-rails (~> 3.0) sass-rails (~> 5.0) diff --git a/app/helpers/comments_helper.rb b/app/helpers/comments_helper.rb index 36952af7d..67c347ced 100644 --- a/app/helpers/comments_helper.rb +++ b/app/helpers/comments_helper.rb @@ -17,4 +17,4 @@ module CommentsHelper comments.select{|c| c.parent_id == parent.id} end -end \ No newline at end of file +end diff --git a/app/helpers/text_with_links_helper.rb b/app/helpers/text_with_links_helper.rb new file mode 100644 index 000000000..55281e89e --- /dev/null +++ b/app/helpers/text_with_links_helper.rb @@ -0,0 +1,9 @@ +module TextWithLinksHelper + + def text_with_links(text) + return unless text + sanitized = sanitize text, tags: [], attributes: [] + Rinku.auto_link(sanitized, :all, 'target="_blank" rel="nofollow"').html_safe + end + +end diff --git a/app/mailers/mailer.rb b/app/mailers/mailer.rb index a3db690a8..15a8eb54a 100644 --- a/app/mailers/mailer.rb +++ b/app/mailers/mailer.rb @@ -1,4 +1,5 @@ class Mailer < ApplicationMailer + helper :text_with_links def comment(comment) @comment = comment diff --git a/app/views/admin/comments/index.html.erb b/app/views/admin/comments/index.html.erb index ec0fddc1a..ce4bfa293 100644 --- a/app/views/admin/comments/index.html.erb +++ b/app/views/admin/comments/index.html.erb @@ -9,7 +9,7 @@
  • - <%= comment.body %> + <%= text_with_links comment.body %> <%= link_to comment.commentable.title, comment.commentable %>
    diff --git a/app/views/admin/users/show.html.erb b/app/views/admin/users/show.html.erb index 79a4b223e..6d98d4e38 100644 --- a/app/views/admin/users/show.html.erb +++ b/app/views/admin/users/show.html.erb @@ -31,7 +31,7 @@
  • - <%= comment.body %> + <%= text_with_links comment.body %>
  • diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb index 3997efdaf..25d7585f3 100644 --- a/app/views/comments/_comment.html.erb +++ b/app/views/comments/_comment.html.erb @@ -63,17 +63,17 @@ <% if comment.as_administrator? %> -

    <%= comment.body %>

    +

    <%= text_with_links comment.body %>

    <% elsif comment.as_moderator? %> -

    <%= comment.body %>

    +

    <%= text_with_links comment.body %>

    <% elsif comment.user.official? && comment.user_id == @commentable.author_id %> -

    <%= comment.body %>

    +

    <%= text_with_links comment.body %>

    <% elsif comment.user.official? %> -

    <%= comment.body %>

    +

    <%= text_with_links comment.body %>

    <% elsif comment.user_id == @commentable.author_id %> -

    <%= comment.body %>

    +

    <%= text_with_links comment.body %>

    <% else %> -

    <%= comment.body %>

    +

    <%= text_with_links comment.body %>

    <% end %> <%= render 'comments/votes', comment: comment %> @@ -101,4 +101,4 @@ -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/mailer/comment.html.erb b/app/views/mailer/comment.html.erb index 959b8e0a0..16ace7990 100644 --- a/app/views/mailer/comment.html.erb +++ b/app/views/mailer/comment.html.erb @@ -13,6 +13,6 @@

    - <%= @comment.body %> + <%= text_with_links @comment.body %>

    diff --git a/app/views/mailer/reply.html.erb b/app/views/mailer/reply.html.erb index 924234f02..d006e205a 100644 --- a/app/views/mailer/reply.html.erb +++ b/app/views/mailer/reply.html.erb @@ -13,6 +13,6 @@

    - <%= @reply.body %> + <%= text_with_links @reply.body %>

    diff --git a/app/views/moderation/comments/index.html.erb b/app/views/moderation/comments/index.html.erb index ec642077b..d18dca8e8 100644 --- a/app/views/moderation/comments/index.html.erb +++ b/app/views/moderation/comments/index.html.erb @@ -23,7 +23,7 @@ <%= comment.commentable_type.constantize.model_name.human %> <%= l comment.updated_at.to_date %> - <%= comment.body %> + <%= text_with_links comment.body %> <%= comment.flags_count %> <%= link_to t("moderation.comments.index.hide"), hide_in_moderation_screen_moderation_comment_path(comment, request.query_parameters), method: :put, class: "delete" %> diff --git a/spec/features/comments_spec.rb b/spec/features/comments_spec.rb index 40e75a281..437286bf7 100644 --- a/spec/features/comments_spec.rb +++ b/spec/features/comments_spec.rb @@ -2,9 +2,10 @@ require 'rails_helper' include ActionView::Helpers::DateHelper feature 'Comments' do + let(:user) { create :user } + let(:debate) { create :debate } scenario 'Index' do - debate = create(:debate) 3.times { create(:comment, commentable: debate) } visit debate_path(debate) @@ -19,8 +20,32 @@ feature 'Comments' do end end + scenario 'Turns links into html links' do + create :comment, commentable: debate, body: 'Built with http://rubyonrails.org/' + + visit debate_path(debate) + + within first('.comment') do + expect(page).to have_content 'Built with http://rubyonrails.org/' + expect(page).to have_link('http://rubyonrails.org/', href: 'http://rubyonrails.org/') + expect(find_link('http://rubyonrails.org/')[:rel]).to eq('nofollow') + expect(find_link('http://rubyonrails.org/')[:target]).to eq('_blank') + end + end + + scenario 'Sanitizes comment body for security' do + create :comment, commentable: debate, body: " click me http://madrid.es" + + visit debate_path(debate) + + within first('.comment') do + expect(page).to have_content "click me http://madrid.es" + expect(page).to have_link('http://madrid.es', href: 'http://madrid.es') + expect(page).not_to have_link('click me') + end + end + scenario 'Paginated comments' do - debate = create(:debate) per_page = 10 (per_page + 2).times { create(:comment, commentable: debate)} @@ -39,7 +64,6 @@ feature 'Comments' do feature 'Not logged user' do scenario 'can not see comments forms' do - debate = create(:debate) create(:comment, commentable: debate) visit debate_path(debate) @@ -53,9 +77,6 @@ feature 'Comments' do end scenario 'Create', :js do - user = create(:user) - debate = create(:debate) - login_as(user) visit debate_path(debate) @@ -68,9 +89,6 @@ feature 'Comments' do end scenario 'Errors on create', :js do - user = create(:user) - debate = create(:debate) - login_as(user) visit debate_path(debate) @@ -82,7 +100,6 @@ feature 'Comments' do scenario 'Reply', :js do citizen = create(:user, username: 'Ana') manuela = create(:user, username: 'Manuela') - debate = create(:debate) comment = create(:comment, commentable: debate, user: citizen) login_as(manuela) @@ -103,8 +120,6 @@ feature 'Comments' do end scenario 'Errors on reply', :js do - user = create(:user) - debate = create(:debate) comment = create(:comment, commentable: debate, user: user) login_as(user) @@ -120,7 +135,6 @@ feature 'Comments' do end scenario "N replies", :js do - debate = create(:debate) parent = create(:comment, commentable: debate) 7.times do @@ -133,8 +147,6 @@ feature 'Comments' do end scenario "Flagging as inappropriate", :js do - user = create(:user) - debate = create(:debate) comment = create(:comment, commentable: debate) login_as(user) @@ -151,8 +163,6 @@ feature 'Comments' do end scenario "Undoing flagging as inappropriate", :js do - user = create(:user) - debate = create(:debate) comment = create(:comment, commentable: debate) Flag.flag(user, comment) @@ -170,7 +180,6 @@ feature 'Comments' do end scenario "Flagging turbolinks sanity check", :js do - user = create(:user) debate = create(:debate, title: "Should we change the world?") comment = create(:comment, commentable: debate) @@ -187,7 +196,6 @@ feature 'Comments' do feature "Moderators" do scenario "can create comment as a moderator", :js do moderator = create(:moderator) - debate = create(:debate) login_as(moderator.user) visit debate_path(debate) @@ -208,7 +216,6 @@ feature 'Comments' do citizen = create(:user, username: "Ana") manuela = create(:user, username: "Manuela") moderator = create(:moderator, user: manuela) - debate = create(:debate) comment = create(:comment, commentable: debate, user: citizen) login_as(manuela) @@ -234,7 +241,6 @@ feature 'Comments' do scenario "can not comment as an administrator" do moderator = create(:moderator) - debate = create(:debate) login_as(moderator.user) visit debate_path(debate) @@ -246,7 +252,6 @@ feature 'Comments' do feature "Administrators" do scenario "can create comment as an administrator", :js do admin = create(:administrator) - debate = create(:debate) login_as(admin.user) visit debate_path(debate) @@ -267,7 +272,6 @@ feature 'Comments' do citizen = create(:user, username: "Ana") manuela = create(:user, username: "Manuela") admin = create(:administrator, user: manuela) - debate = create(:debate) comment = create(:comment, commentable: debate, user: citizen) login_as(manuela) @@ -293,7 +297,6 @@ feature 'Comments' do scenario "can not comment as a moderator" do admin = create(:administrator) - debate = create(:debate) login_as(admin.user) visit debate_path(debate)