Merge pull request #3749 from consul/sanitize_description
Sanitize descriptions in the views
This commit is contained in:
@@ -36,6 +36,10 @@ module ApplicationHelper
|
|||||||
sanitize(Redcarpet::Markdown.new(renderer, extensions).render(text))
|
sanitize(Redcarpet::Markdown.new(renderer, extensions).render(text))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def wysiwyg(text)
|
||||||
|
WYSIWYGSanitizer.new.sanitize(text)
|
||||||
|
end
|
||||||
|
|
||||||
def author_of?(authorable, user)
|
def author_of?(authorable, user)
|
||||||
return false if authorable.blank? || user.blank?
|
return false if authorable.blank? || user.blank?
|
||||||
authorable.author_id == user.id
|
authorable.author_id == user.id
|
||||||
|
|||||||
@@ -42,8 +42,6 @@ class Budget < ApplicationRecord
|
|||||||
|
|
||||||
has_one :poll
|
has_one :poll
|
||||||
|
|
||||||
before_validation :sanitize_descriptions
|
|
||||||
|
|
||||||
after_create :generate_phases
|
after_create :generate_phases
|
||||||
|
|
||||||
scope :drafting, -> { where(phase: "drafting") }
|
scope :drafting, -> { where(phase: "drafting") }
|
||||||
@@ -79,7 +77,7 @@ class Budget < ApplicationRecord
|
|||||||
if phases.exists? && phases.send(phase).description.present?
|
if phases.exists? && phases.send(phase).description.present?
|
||||||
phases.send(phase).description
|
phases.send(phase).description
|
||||||
else
|
else
|
||||||
send("description_#{phase}")&.html_safe
|
send("description_#{phase}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -205,14 +203,6 @@ class Budget < ApplicationRecord
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def sanitize_descriptions
|
|
||||||
s = WYSIWYGSanitizer.new
|
|
||||||
Budget::Phase::PHASE_KINDS.each do |phase|
|
|
||||||
sanitized = s.sanitize(send("description_#{phase}"))
|
|
||||||
send("description_#{phase}=", sanitized)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def generate_phases
|
def generate_phases
|
||||||
Budget::Phase::PHASE_KINDS.each do |phase|
|
Budget::Phase::PHASE_KINDS.each do |phase|
|
||||||
Budget::Phase.create(
|
Budget::Phase.create(
|
||||||
|
|||||||
@@ -9,17 +9,6 @@ class Budget
|
|||||||
translates :summary, touch: true
|
translates :summary, touch: true
|
||||||
translates :description, touch: true
|
translates :description, touch: true
|
||||||
include Globalizable
|
include Globalizable
|
||||||
|
|
||||||
class Translation
|
|
||||||
before_validation :sanitize_description
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def sanitize_description
|
|
||||||
self.description = WYSIWYGSanitizer.new.sanitize(description)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
include Sanitizable
|
include Sanitizable
|
||||||
|
|
||||||
belongs_to :budget
|
belongs_to :budget
|
||||||
|
|||||||
@@ -9,10 +9,6 @@ module Globalizable
|
|||||||
validate :check_translations_number, on: :update, if: :translations_required?
|
validate :check_translations_number, on: :update, if: :translations_required?
|
||||||
after_validation :copy_error_to_current_translation, on: :update
|
after_validation :copy_error_to_current_translation, on: :update
|
||||||
|
|
||||||
def description
|
|
||||||
self.read_attribute(:description)&.html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def locales_not_marked_for_destruction
|
def locales_not_marked_for_destruction
|
||||||
translations.reject(&:marked_for_destruction?).map(&:locale)
|
translations.reject(&:marked_for_destruction?).map(&:locale)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,49 +2,12 @@ module Sanitizable
|
|||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
included do
|
included do
|
||||||
before_validation :sanitize_description
|
|
||||||
before_validation :sanitize_tag_list
|
before_validation :sanitize_tag_list
|
||||||
|
|
||||||
unless included_modules.include? Globalizable
|
|
||||||
def description
|
|
||||||
super&.html_safe
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def sanitize_description
|
|
||||||
if translatable_description?
|
|
||||||
sanitize_description_translations
|
|
||||||
else
|
|
||||||
self.description = WYSIWYGSanitizer.new.sanitize(description)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def sanitize_tag_list
|
def sanitize_tag_list
|
||||||
self.tag_list = TagSanitizer.new.sanitize_tag_list(tag_list) if self.class.taggable?
|
self.tag_list = TagSanitizer.new.sanitize_tag_list(tag_list) if self.class.taggable?
|
||||||
end
|
end
|
||||||
|
|
||||||
def translatable_description?
|
|
||||||
self.class.included_modules.include?(Globalizable) &&
|
|
||||||
self.class.translated_attribute_names.include?(:description)
|
|
||||||
end
|
|
||||||
|
|
||||||
def sanitize_description_translations
|
|
||||||
# Sanitize description when using attribute accessor in place of nested translations.
|
|
||||||
# This is because Globalize gem create translations on after save callback
|
|
||||||
# https://github.com/globalize/globalize/blob/e37c471775d196cd4318e61954572c300c015467/lib/globalize/active_record/act_macro.rb#L105
|
|
||||||
if translations.empty?
|
|
||||||
Globalize.with_locale(I18n.locale) do
|
|
||||||
self.description = WYSIWYGSanitizer.new.sanitize(description)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
translations.reject(&:_destroy).each do |translation|
|
|
||||||
Globalize.with_locale(translation.locale) do
|
|
||||||
self.description = WYSIWYGSanitizer.new.sanitize(description)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ class Legislation::DraftVersion < ApplicationRecord
|
|||||||
translates :title, touch: true
|
translates :title, touch: true
|
||||||
translates :changelog, touch: true
|
translates :changelog, touch: true
|
||||||
translates :body, touch: true
|
translates :body, touch: true
|
||||||
translates :body_html, touch: true
|
|
||||||
translates :toc_html, touch: true
|
|
||||||
include Globalizable
|
include Globalizable
|
||||||
|
|
||||||
belongs_to :process, class_name: "Legislation::Process", foreign_key: "legislation_process_id"
|
belongs_to :process, class_name: "Legislation::Process", foreign_key: "legislation_process_id"
|
||||||
@@ -20,23 +18,16 @@ class Legislation::DraftVersion < ApplicationRecord
|
|||||||
|
|
||||||
scope :published, -> { where(status: "published").order("id DESC") }
|
scope :published, -> { where(status: "published").order("id DESC") }
|
||||||
|
|
||||||
before_save :render_html
|
def body_html
|
||||||
|
|
||||||
def render_html
|
|
||||||
renderer = Redcarpet::Render::HTML.new(with_toc_data: true)
|
renderer = Redcarpet::Render::HTML.new(with_toc_data: true)
|
||||||
toc_renderer = Redcarpet::Render::HTML_TOC.new(with_toc_data: true)
|
|
||||||
|
|
||||||
if body_changed?
|
Redcarpet::Markdown.new(renderer).render(body)
|
||||||
self.body_html = Redcarpet::Markdown.new(renderer).render(body)
|
end
|
||||||
self.toc_html = Redcarpet::Markdown.new(toc_renderer).render(body)
|
|
||||||
end
|
|
||||||
|
|
||||||
translations.each do |translation|
|
def toc_html
|
||||||
if translation.body_changed?
|
renderer = Redcarpet::Render::HTML_TOC.new(with_toc_data: true)
|
||||||
translation.body_html = Redcarpet::Markdown.new(renderer).render(translation.body)
|
|
||||||
translation.toc_html = Redcarpet::Markdown.new(toc_renderer).render(translation.body)
|
Redcarpet::Markdown.new(renderer).render(body)
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def display_title
|
def display_title
|
||||||
|
|||||||
@@ -19,10 +19,6 @@ class Poll::Question::Answer < ApplicationRecord
|
|||||||
|
|
||||||
scope :visibles, -> { where(hidden: false) }
|
scope :visibles, -> { where(hidden: false) }
|
||||||
|
|
||||||
def description
|
|
||||||
self[:description]&.html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.order_answers(ordered_array)
|
def self.order_answers(ordered_array)
|
||||||
ordered_array.each_with_index do |answer_id, order|
|
ordered_array.each_with_index do |answer_id, order|
|
||||||
find(answer_id).update_attribute(:given_order, (order + 1))
|
find(answer_id).update_attribute(:given_order, (order + 1))
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html @debate.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(@debate.description) %>
|
||||||
|
|
||||||
<h3><%= t("votes.supports") %></h3>
|
<h3><%= t("votes.supports") %></h3>
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="moderation-description">
|
<div class="moderation-description">
|
||||||
<%= investment.description %>
|
<%= wysiwyg(investment.description) %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-top">
|
<td class="align-top">
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="moderation-description">
|
<div class="moderation-description">
|
||||||
<%= debate.description %>
|
<%= wysiwyg(debate.description) %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="align-top">
|
<td class="align-top">
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<div class="moderation-description">
|
<div class="moderation-description">
|
||||||
<p><small><%= proposal.summary %></small></p>
|
<p><small><%= proposal.summary %></small></p>
|
||||||
<%= proposal.description %>
|
<%= wysiwyg(proposal.description) %>
|
||||||
<% if proposal.video_url.present? %>
|
<% if proposal.video_url.present? %>
|
||||||
<p><%= sanitize_and_auto_link proposal.video_url %></p>
|
<p><%= sanitize_and_auto_link proposal.video_url %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= @answer.title %></td>
|
<td><%= @answer.title %></td>
|
||||||
<td><%= @answer.description %></td>
|
<td><%= wysiwyg(@answer.description) %></td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
(<%= @answer.images.count %>)<br>
|
(<%= @answer.images.count %>)<br>
|
||||||
<%= link_to t("admin.answers.show.images_list"), admin_answer_images_path(@answer) %>
|
<%= link_to t("admin.answers.show.images_list"), admin_answer_images_path(@answer) %>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@
|
|||||||
<% @question.question_answers.each do |answer| %>
|
<% @question.question_answers.each do |answer| %>
|
||||||
<tr id="<%= dom_id(answer) %>" class="poll_question_answer" data-answer-id="<%= answer.id %>">
|
<tr id="<%= dom_id(answer) %>" class="poll_question_answer" data-answer-id="<%= answer.id %>">
|
||||||
<td class="align-top"><%= link_to answer.title, admin_answer_path(answer) %></td>
|
<td class="align-top"><%= link_to answer.title, admin_answer_path(answer) %></td>
|
||||||
<td class="align-top break"><%= answer.description %></td>
|
<td class="align-top break"><%= wysiwyg(answer.description) %></td>
|
||||||
<td class="align-top text-center">
|
<td class="align-top text-center">
|
||||||
(<%= answer.images.count %>)
|
(<%= answer.images.count %>)
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
-
|
-
|
||||||
<%= l(phase.ends_at.to_date - 1.day, format: :long) if phase.ends_at.present? %>
|
<%= l(phase.ends_at.to_date - 1.day, format: :long) if phase.ends_at.present? %>
|
||||||
</span>
|
</span>
|
||||||
<p><%= auto_link_already_sanitized_html(WYSIWYGSanitizer.new.sanitize(phase.summary)) %></p>
|
<p><%= auto_link_already_sanitized_html(wysiwyg(phase.summary)) %></p>
|
||||||
</li>
|
</li>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<h1><%= current_budget.name %></h1>
|
<h1><%= current_budget.name %></h1>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<%= auto_link_already_sanitized_html(current_budget.description) %>
|
<%= auto_link_already_sanitized_html wysiwyg(current_budget.description) %>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
<%= link_to t("budgets.index.section_header.help"), "#section_help" %>
|
<%= link_to t("budgets.index.section_header.help"), "#section_help" %>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<%= investment.heading.name %>
|
<%= investment.heading.name %>
|
||||||
</p>
|
</p>
|
||||||
<div class="investment-project-description">
|
<div class="investment-project-description">
|
||||||
<%= investment.description %>
|
<%= wysiwyg(investment.description) %>
|
||||||
<div class="truncate"></div>
|
<div class="truncate"></div>
|
||||||
</div>
|
</div>
|
||||||
<%= render "shared/tags", taggable: investment, limit: 5 %>
|
<%= render "shared/tags", taggable: investment, limit: 5 %>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<%= sanitize(t("budgets.investments.show.code", code: investment.id)) %>
|
<%= sanitize(t("budgets.investments.show.code", code: investment.id)) %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html investment.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(investment.description) %>
|
||||||
|
|
||||||
<% if feature?(:map) && map_location_available?(@investment.map_location) %>
|
<% if feature?(:map) && map_location_available?(@investment.map_location) %>
|
||||||
<div class="margin">
|
<div class="margin">
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
<h1><%= @budget.name %></h1>
|
<h1><%= @budget.name %></h1>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html(@budget.description) %>
|
<%= auto_link_already_sanitized_html wysiwyg(@budget.description) %>
|
||||||
</div>
|
</div>
|
||||||
<div class="small-12 medium-3 column info padding" data-equalizer-watch>
|
<div class="small-12 medium-3 column info padding" data-equalizer-watch>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -38,10 +38,10 @@
|
|||||||
<small><%= t("dashboard.recommended_actions.show_description") %></small>
|
<small><%= t("dashboard.recommended_actions.show_description") %></small>
|
||||||
</a>
|
</a>
|
||||||
<div id="proposed_action_description_<%= dom_id(proposed_action) %>" class="hide" data-toggler=".hide">
|
<div id="proposed_action_description_<%= dom_id(proposed_action) %>" class="hide" data-toggler=".hide">
|
||||||
<%= WYSIWYGSanitizer.new.sanitize(proposed_action.description) %>
|
<%= wysiwyg(proposed_action.description) %>
|
||||||
</div>
|
</div>
|
||||||
<% else %>
|
<% else %>
|
||||||
<%= WYSIWYGSanitizer.new.sanitize(proposed_action.description) %>
|
<%= wysiwyg(proposed_action.description) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<div class="row expanded">
|
<div class="row expanded">
|
||||||
<div class="small-12 medium-8 column">
|
<div class="small-12 medium-8 column">
|
||||||
<%= WYSIWYGSanitizer.new.sanitize(dashboard_action.description) %>
|
<%= wysiwyg(dashboard_action.description) %>
|
||||||
<%= render "dashboard/form" %>
|
<%= render "dashboard/form" %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><%= first_proposed_action.title %></li>
|
<li><%= first_proposed_action.title %></li>
|
||||||
<% if first_proposed_action.description.present? %>
|
<% if first_proposed_action.description.present? %>
|
||||||
<p><%= WYSIWYGSanitizer.new.sanitize(first_proposed_action.description) %></p>
|
<p><%= wysiwyg(first_proposed_action.description) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><%= first_proposed_action.title %></li>
|
<li><%= first_proposed_action.title %></li>
|
||||||
<% if first_proposed_action.description.present? %>
|
<% if first_proposed_action.description.present? %>
|
||||||
<p><%= WYSIWYGSanitizer.new.sanitize(first_proposed_action.description) %></p>
|
<p><%= wysiwyg(first_proposed_action.description) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
|
|
||||||
</p>
|
</p>
|
||||||
<div class="debate-description">
|
<div class="debate-description">
|
||||||
<%= debate.description %>
|
<%= wysiwyg(debate.description) %>
|
||||||
<div class="truncate"></div>
|
<div class="truncate"></div>
|
||||||
</div>
|
</div>
|
||||||
<%= render "shared/tags", taggable: debate, limit: 5 %>
|
<%= render "shared/tags", taggable: debate, limit: 5 %>
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html @debate.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(@debate.description) %>
|
||||||
|
|
||||||
<%= render "shared/tags", taggable: @debate %>
|
<%= render "shared/tags", taggable: @debate %>
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
data-legislation-annotatable-base-url="<%= legislation_process_draft_version_path(@process, @draft_version) %>"
|
data-legislation-annotatable-base-url="<%= legislation_process_draft_version_path(@process, @draft_version) %>"
|
||||||
data-legislation-open-phase="<%= @process.allegations_phase.open? %>">
|
data-legislation-open-phase="<%= @process.allegations_phase.open? %>">
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= sanitize(@draft_version.body_html) %>
|
<%= sanitize(@draft_version.body_html, { attributes: ["id"] }) %>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="small-12 column">
|
<div class="small-12 column">
|
||||||
<%= WYSIWYGSanitizer.new.sanitize(@process.milestones_summary) %>
|
<%= wysiwyg(@process.milestones_summary) %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html @proposal.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(@proposal.description) %>
|
||||||
|
|
||||||
<% if @proposal.video_url.present? %>
|
<% if @proposal.video_url.present? %>
|
||||||
<div class="video-link">
|
<div class="video-link">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<td style="padding-bottom: 20px; padding-left: 10px;">
|
<td style="padding-bottom: 20px; padding-left: 10px;">
|
||||||
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;line-height: 24px;">
|
<p style="font-family: 'Open Sans','Helvetica Neue',arial,sans-serif;font-size: 14px;line-height: 24px;">
|
||||||
<%= auto_link_already_sanitized_html WYSIWYGSanitizer.new.sanitize(@newsletter.body) %>
|
<%= auto_link_already_sanitized_html wysiwyg(@newsletter.body) %>
|
||||||
</p>
|
</p>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
<%= investment.author.username %>
|
<%= investment.author.username %>
|
||||||
<br>
|
<br>
|
||||||
<div class="moderation-description">
|
<div class="moderation-description">
|
||||||
<%= investment.description %>
|
<%= wysiwyg(investment.description) %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<%= debate.author.username %>
|
<%= debate.author.username %>
|
||||||
<br>
|
<br>
|
||||||
<div class="moderation-description">
|
<div class="moderation-description">
|
||||||
<%= debate.description %>
|
<%= wysiwyg(debate.description) %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
<%= proposal.author.username %>
|
<%= proposal.author.username %>
|
||||||
<br>
|
<br>
|
||||||
<div class="moderation-description">
|
<div class="moderation-description">
|
||||||
<%= proposal.description %>
|
<%= wysiwyg(proposal.description) %>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td class="text-center">
|
<td class="text-center">
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<div class="small-12 column">
|
<div class="small-12 column">
|
||||||
<% if show_polls_description? %>
|
<% if show_polls_description? %>
|
||||||
<div class="polls-description">
|
<div class="polls-description">
|
||||||
<%= auto_link_already_sanitized_html WYSIWYGSanitizer.new.sanitize(@active_poll.description) %>
|
<%= auto_link_already_sanitized_html wysiwyg(@active_poll.description) %>
|
||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
<div id="answer_description_<%= answer.id %>"
|
<div id="answer_description_<%= answer.id %>"
|
||||||
class="answer-description short answer-left-divider" data-toggler="short">
|
class="answer-description short answer-left-divider" data-toggler="short">
|
||||||
<% if answer.description.present? %>
|
<% if answer.description.present? %>
|
||||||
<%= answer.description %>
|
<%= wysiwyg(answer.description) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if answer.images.any? %>
|
<% if answer.images.any? %>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html @proposal.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(@proposal.description) %>
|
||||||
|
|
||||||
<% if feature?(:map) && map_location_available?(@proposal.map_location) %>
|
<% if feature?(:map) && map_location_available?(@proposal.map_location) %>
|
||||||
<div class="margin">
|
<div class="margin">
|
||||||
|
|||||||
@@ -7,6 +7,6 @@
|
|||||||
|
|
||||||
<h1><%= @investment.title %></h1>
|
<h1><%= @investment.title %></h1>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html @investment.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(@investment.description) %>
|
||||||
|
|
||||||
<%= render "tracking/milestones/milestones", milestoneable: @investment %>
|
<%= render "tracking/milestones/milestones", milestoneable: @investment %>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<h2><%= t("tracking.budget_investments.show.title") %> <%= @investment.id %> </h2>
|
<h2><%= t("tracking.budget_investments.show.title") %> <%= @investment.id %> </h2>
|
||||||
<h1><%= @investment.title %></h1>
|
<h1><%= @investment.title %></h1>
|
||||||
|
|
||||||
<%= auto_link_already_sanitized_html @investment.description %>
|
<%= auto_link_already_sanitized_html wysiwyg(@investment.description) %>
|
||||||
|
|
||||||
<% if @investment.external_url.present? %>
|
<% if @investment.external_url.present? %>
|
||||||
<p><%= sanitize_and_auto_link @investment.external_url %></p>
|
<p><%= sanitize_and_auto_link @investment.external_url %></p>
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
<%= link_to recommended_path(recommended) do %>
|
<%= link_to recommended_path(recommended) do %>
|
||||||
<h4 class="truncate-horizontal-text"><%= recommended.title %></h4>
|
<h4 class="truncate-horizontal-text"><%= recommended.title %></h4>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= recommended.description %>
|
<%= wysiwyg(recommended.description) %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -20,12 +20,14 @@ class AddCollaborativeLegislationTranslations < ActiveRecord::Migration[4.2]
|
|||||||
{
|
{
|
||||||
title: :string,
|
title: :string,
|
||||||
changelog: :text,
|
changelog: :text,
|
||||||
body: :text,
|
body: :text
|
||||||
body_html: :text,
|
|
||||||
toc_html: :text
|
|
||||||
},
|
},
|
||||||
{ migrate_data: true }
|
{ migrate_data: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_column :legislation_draft_version_translations, :body_html, :text
|
||||||
|
add_column :legislation_draft_version_translations, :toc_html, :text
|
||||||
|
|
||||||
Legislation::QuestionOption.create_translation_table!(
|
Legislation::QuestionOption.create_translation_table!(
|
||||||
{ value: :string },
|
{ value: :string },
|
||||||
{ migrate_data: true }
|
{ migrate_data: true }
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
class RemoveHtmlFieldsFormLegislationDraftVersion < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
remove_column :legislation_draft_versions, :body_html
|
||||||
|
remove_column :legislation_draft_version_translations, :body_html
|
||||||
|
remove_column :legislation_draft_versions, :toc_html
|
||||||
|
remove_column :legislation_draft_version_translations, :toc_html
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -759,8 +759,6 @@ ActiveRecord::Schema.define(version: 20191020153455) do
|
|||||||
t.string "title"
|
t.string "title"
|
||||||
t.text "changelog"
|
t.text "changelog"
|
||||||
t.text "body"
|
t.text "body"
|
||||||
t.text "body_html"
|
|
||||||
t.text "toc_html"
|
|
||||||
t.datetime "hidden_at"
|
t.datetime "hidden_at"
|
||||||
t.index ["hidden_at"], name: "index_legislation_draft_version_translations_on_hidden_at", using: :btree
|
t.index ["hidden_at"], name: "index_legislation_draft_version_translations_on_hidden_at", using: :btree
|
||||||
t.index ["legislation_draft_version_id"], name: "index_900e5ba94457606e69e89193db426e8ddff809bc", using: :btree
|
t.index ["legislation_draft_version_id"], name: "index_900e5ba94457606e69e89193db426e8ddff809bc", using: :btree
|
||||||
@@ -777,8 +775,6 @@ ActiveRecord::Schema.define(version: 20191020153455) do
|
|||||||
t.datetime "hidden_at"
|
t.datetime "hidden_at"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.text "body_html"
|
|
||||||
t.text "toc_html"
|
|
||||||
t.index ["hidden_at"], name: "index_legislation_draft_versions_on_hidden_at", using: :btree
|
t.index ["hidden_at"], name: "index_legislation_draft_versions_on_hidden_at", using: :btree
|
||||||
t.index ["legislation_process_id"], name: "index_legislation_draft_versions_on_legislation_process_id", using: :btree
|
t.index ["legislation_process_id"], name: "index_legislation_draft_versions_on_legislation_process_id", using: :btree
|
||||||
t.index ["status"], name: "index_legislation_draft_versions_on_status", using: :btree
|
t.index ["status"], name: "index_legislation_draft_versions_on_status", using: :btree
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class ConsulFormBuilder < FoundationRailsHelper::FormBuilder
|
|||||||
|
|
||||||
def check_box(attribute, options = {})
|
def check_box(attribute, options = {})
|
||||||
if options[:label] != false
|
if options[:label] != false
|
||||||
label = content_tag(:span, sanitize(label_text(object, attribute, options[:label]), class: "checkbox"))
|
label = content_tag(:span, sanitize(label_text(object, attribute, options[:label])), class: "checkbox")
|
||||||
|
|
||||||
super(attribute, options.merge(label: label, label_options: label_options_for(options)))
|
super(attribute, options.merge(label: label, label_options: label_options_for(options)))
|
||||||
else
|
else
|
||||||
@@ -76,7 +76,7 @@ class ConsulFormBuilder < FoundationRailsHelper::FormBuilder
|
|||||||
|
|
||||||
def help_text_id(attribute, options)
|
def help_text_id(attribute, options)
|
||||||
if options[:hint]
|
if options[:hint]
|
||||||
"#{custom_label(attribute, nil, nil).match(/for=\"(.+)\"/)[1]}-help-text"
|
"#{custom_label(attribute, nil, nil).match(/for="([^"]+)"/)[1]}-help-text"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -121,6 +121,31 @@ describe "Cross-Site Scripting protection", :js do
|
|||||||
expect(page.text).not_to be_empty
|
expect(page.text).not_to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "proposal description" do
|
||||||
|
proposal = create(:proposal, description: attack_code)
|
||||||
|
|
||||||
|
visit proposal_path(proposal)
|
||||||
|
|
||||||
|
expect(page.text).not_to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "investment description" do
|
||||||
|
investment = create(:budget_investment, description: attack_code)
|
||||||
|
|
||||||
|
visit budget_investment_path(investment.budget, investment)
|
||||||
|
|
||||||
|
expect(page.text).not_to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario "budget phase description" do
|
||||||
|
budget = create(:budget)
|
||||||
|
budget.current_phase.update(description: attack_code)
|
||||||
|
|
||||||
|
visit budget_path(budget)
|
||||||
|
|
||||||
|
expect(page.text).not_to be_empty
|
||||||
|
end
|
||||||
|
|
||||||
scenario "markdown conversion" do
|
scenario "markdown conversion" do
|
||||||
process = create(:legislation_process, description: attack_code)
|
process = create(:legislation_process, description: attack_code)
|
||||||
|
|
||||||
@@ -128,4 +153,13 @@ describe "Cross-Site Scripting protection", :js do
|
|||||||
|
|
||||||
expect(page.text).not_to be_empty
|
expect(page.text).not_to be_empty
|
||||||
end
|
end
|
||||||
|
|
||||||
|
scenario "legislation version body filters script tags but not header IDs" do
|
||||||
|
version = create(:legislation_draft_version, :published, body: "# Title 1\n#{attack_code}")
|
||||||
|
|
||||||
|
visit legislation_process_draft_version_path(version.process, version)
|
||||||
|
|
||||||
|
expect(page.text).not_to be_empty
|
||||||
|
expect(page).to have_css "h1#title-1", text: "Title 1"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -205,12 +205,4 @@ describe Budget::Phase do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "#sanitize_description" do
|
|
||||||
it "removes not allowed html entities from the description" do
|
|
||||||
expect do
|
|
||||||
first_phase.update_attributes(description: '<p><a href="/"><b>a</b></a></p> <script>javascript</script>')
|
|
||||||
end.to change { first_phase.description }.to('<p><a href="/">a</a></p> javascript')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ describe Budget do
|
|||||||
Budget::Phase::PHASE_KINDS.each do |phase_kind|
|
Budget::Phase::PHASE_KINDS.each do |phase_kind|
|
||||||
budget.phase = phase_kind
|
budget.phase = phase_kind
|
||||||
expect(budget.description).to eq(budget.send("description_#{phase_kind}"))
|
expect(budget.description).to eq(budget.send("description_#{phase_kind}"))
|
||||||
expect(budget.description).to be_html_safe
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ describe Legislation::DraftVersion do
|
|||||||
expect(legislation_draft_version).to be_valid
|
expect(legislation_draft_version).to be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders and saves the html from the markdown body field" do
|
it "renders the html from the markdown body field" do
|
||||||
legislation_draft_version.body = body_markdown
|
legislation_draft_version.body = body_markdown
|
||||||
|
|
||||||
legislation_draft_version.save!
|
legislation_draft_version.save!
|
||||||
@@ -19,16 +19,6 @@ describe Legislation::DraftVersion do
|
|||||||
expect(legislation_draft_version.toc_html).to eq(toc_html)
|
expect(legislation_draft_version.toc_html).to eq(toc_html)
|
||||||
end
|
end
|
||||||
|
|
||||||
it "renders and saves the html from the markdown body field with alternative translation" do
|
|
||||||
legislation_draft_version.title_fr = "Français"
|
|
||||||
legislation_draft_version.body_fr = body_markdown
|
|
||||||
|
|
||||||
legislation_draft_version.save!
|
|
||||||
|
|
||||||
expect(legislation_draft_version.body_html_fr).to eq(body_html)
|
|
||||||
expect(legislation_draft_version.toc_html_fr).to eq(toc_html)
|
|
||||||
end
|
|
||||||
|
|
||||||
def body_markdown
|
def body_markdown
|
||||||
<<-BODY_MARKDOWN
|
<<-BODY_MARKDOWN
|
||||||
# Title 1
|
# Title 1
|
||||||
|
|||||||
@@ -1,38 +1,6 @@
|
|||||||
shared_examples "sanitizable" do
|
shared_examples "sanitizable" do
|
||||||
let(:sanitizable) { build(model_name(described_class)) }
|
let(:sanitizable) { build(model_name(described_class)) }
|
||||||
|
|
||||||
it "is sanitized" do
|
|
||||||
sanitizable.description = "<script>alert('danger');</script>"
|
|
||||||
|
|
||||||
sanitizable.valid?
|
|
||||||
|
|
||||||
expect(sanitizable.description).to eq("alert('danger');")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is html_safe" do
|
|
||||||
sanitizable.description = "<script>alert('danger');</script>"
|
|
||||||
|
|
||||||
sanitizable.valid?
|
|
||||||
|
|
||||||
expect(sanitizable.description).to be_html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is sanitized using globalize accessors" do
|
|
||||||
sanitizable.description_en = "<script>alert('danger');</script>"
|
|
||||||
|
|
||||||
sanitizable.valid?
|
|
||||||
|
|
||||||
expect(sanitizable.description_en).to eq("alert('danger');")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "is html_safe using globalize accessors" do
|
|
||||||
sanitizable.description_en = "<script>alert('danger');</script>"
|
|
||||||
|
|
||||||
sanitizable.valid?
|
|
||||||
|
|
||||||
expect(sanitizable.description_en).to be_html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#tag_list" do
|
describe "#tag_list" do
|
||||||
before do
|
before do
|
||||||
unless described_class.included_modules.include?(Taggable)
|
unless described_class.included_modules.include?(Taggable)
|
||||||
|
|||||||
Reference in New Issue
Block a user