Commit 13e6bd4af21120abc4edced4f5a4af8d629ad217

Authored by Victor Costa
2 parents 45a508d7 9fb3ad5a
Exists in staging and in 1 other branch production

Merge branch 'master' into staging

Conflicts:
	.travis.yml
	app/controllers/my_profile/tasks_controller.rb
	app/helpers/application_helper.rb
	app/views/profile_editor/_pending_tasks.html.erb
	app/views/tasks/processed.html.erb
	test/functional/tasks_controller_test.rb
Showing 292 changed files with 1077 additions and 1016 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 292 files displayed.

.gitlab-ci.yml
... ... @@ -30,14 +30,47 @@ integration:
30 30 script: bundle exec rake test:integration
31 31 stage: all-tests
32 32  
33   -cucumber:
34   - script: bundle exec rake cucumber
  33 +cucumber-1:
  34 + script: SLICE=1/2 bundle exec rake cucumber
  35 + stage: all-tests
  36 +cucumber-2:
  37 + script: SLICE=2/2 bundle exec rake cucumber
35 38 stage: all-tests
36 39  
37   -selenium:
38   - script: bundle exec rake selenium
  40 +selenium-1:
  41 + script: SLICE=1/6 bundle exec rake selenium
  42 + stage: all-tests
  43 +selenium-2:
  44 + script: SLICE=2/6 bundle exec rake selenium
  45 + stage: all-tests
  46 +selenium-3:
  47 + script: SLICE=3/6 bundle exec rake selenium
  48 + stage: all-tests
  49 +selenium-4:
  50 + script: SLICE=4/6 bundle exec rake selenium
  51 + stage: all-tests
  52 +selenium-5:
  53 + script: SLICE=5/6 bundle exec rake selenium
  54 + stage: all-tests
  55 +selenium-6:
  56 + script: SLICE=6/6 bundle exec rake selenium
39 57 stage: all-tests
40 58  
41   -plugins:
42   - script: bundle exec rake test:noosfero_plugins
  59 +# NOOSFERO_BUNDLE_OPTS=install makes migrations fails
  60 +# probably because of rubygems-integration
  61 +plugins-1:
  62 + script: SLICE=1/5 bundle exec rake test:noosfero_plugins
43 63 stage: all-tests
  64 +plugins-2:
  65 + script: SLICE=2/5 bundle exec rake test:noosfero_plugins
  66 + stage: all-tests
  67 +plugins-3:
  68 + script: SLICE=3/5 bundle exec rake test:noosfero_plugins
  69 + stage: all-tests
  70 +plugins-4:
  71 + script: SLICE=4/5 bundle exec rake test:noosfero_plugins
  72 + stage: all-tests
  73 +plugins-5:
  74 + script: SLICE=5/5 bundle exec rake test:noosfero_plugins
  75 + stage: all-tests
  76 +
... ...
.travis.yml
... ... @@ -61,11 +61,11 @@ env:
61 61 - SLICE=2/4 TASK=selenium
62 62 - SLICE=3/4 TASK=selenium
63 63 - SLICE=4/4 TASK=selenium
64   - - SLICE=1/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install
65   - - SLICE=2/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install
66   - - SLICE=3/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install
67   - - SLICE=4/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install
68   - - SLICE=5/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install
  64 + - SLICE=1/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install
  65 + - SLICE=2/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install
  66 + - SLICE=3/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install
  67 + - SLICE=4/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install
  68 + - SLICE=5/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install
69 69  
70 70 script:
71 71 - ./script/ci
... ...
README.rails.md
... ... @@ -99,7 +99,7 @@ Description of contents
99 99 Holds controllers that should be named like weblog_controller.rb for automated URL mapping. All controllers should descend from `ActionController::Base`.
100 100  
101 101 * `app/models`
102   - Holds models that should be named like post.rb. Most models will descend from `ActiveRecord::Base`.
  102 + Holds models that should be named like post.rb. Most models will descend from `ApplicationRecord`.
103 103  
104 104 * `app/views`
105 105 Holds the template files for the view that should be named like `weblog/index.rhtml` for the `WeblogController#index` action. All views use eRuby syntax. This directory can also be used to keep stylesheets, images, and so on that can be symlinked to public.
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -108,7 +108,7 @@ class CmsController < MyProfileController
108 108 end
109 109  
110 110 def new
111   - # FIXME this method should share some logic wirh edit !!!
  111 + # FIXME this method should share some logic with edit !!!
112 112  
113 113 @success_back_to = params[:success_back_to]
114 114 # user must choose an article type first
... ... @@ -365,7 +365,7 @@ class CmsController < MyProfileController
365 365 def search
366 366 query = params[:q]
367 367 results = find_by_contents(:uploaded_files, profile, profile.files.published, query)[:results]
368   - render :text => article_list_to_json(results), :content_type => 'application/json'
  368 + render :text => article_list_to_json(results).html_safe, :content_type => 'application/json'
369 369 end
370 370  
371 371 def search_article_privacy_exceptions
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -32,6 +32,7 @@ class ProfileEditorController < MyProfileController
32 32 Image.transaction do
33 33 begin
34 34 @plugins.dispatch(:profile_editor_transaction_extras)
  35 + # TODO: This is unsafe! Add sanitizer
35 36 @profile_data.update!(params[:profile_data])
36 37 redirect_to :action => 'index', :profile => profile.identifier
37 38 rescue Exception => ex
... ...
app/controllers/my_profile/tasks_controller.rb
... ... @@ -162,34 +162,25 @@ class TasksController < MyProfileController
162 162  
163 163 protected
164 164  
165   - def filter_by_closed_date(filter, tasks)
166   - filter[:closed_from] = Date.parse(filter[:closed_from]) unless filter[:closed_from].blank?
167   - filter[:closed_until] = Date.parse(filter[:closed_until]) unless filter[:closed_until].blank?
168   -
169   - tasks = tasks.where('tasks.end_date >= ?', filter[:closed_from].beginning_of_day) unless filter[:closed_from].blank?
170   - tasks = tasks.where('tasks.end_date <= ?', filter[:closed_until].end_of_day) unless filter[:closed_until].blank?
171   - tasks
172   - end
  165 + def filter_tasks(filter, tasks)
  166 + tasks = tasks.eager_load(:requestor, :closed_by)
  167 + tasks = tasks.of(filter[:type].presence)
  168 + tasks = tasks.where(:status => filter[:status]) unless filter[:status].blank?
173 169  
174   - def filter_by_creation_date(filter, tasks)
175 170 filter[:created_from] = Date.parse(filter[:created_from]) unless filter[:created_from].blank?
176 171 filter[:created_until] = Date.parse(filter[:created_until]) unless filter[:created_until].blank?
  172 + filter[:closed_from] = Date.parse(filter[:closed_from]) unless filter[:closed_from].blank?
  173 + filter[:closed_until] = Date.parse(filter[:closed_until]) unless filter[:closed_until].blank?
177 174  
178   - tasks = tasks.where('tasks.created_at >= ?', filter[:created_from].beginning_of_day) unless filter[:created_from].blank?
179   - tasks = tasks.where('tasks.created_at <= ?', filter[:created_until].end_of_day) unless filter[:created_until].blank?
180   - tasks
181   - end
  175 + tasks = tasks.from_creation_date filter[:created_from] unless filter[:created_from].blank?
  176 + tasks = tasks.until_creation_date filter[:created_until] unless filter[:created_until].blank?
182 177  
183   - def filter_tasks(filter, tasks)
184   - tasks = tasks.eager_load(:requestor, :closed_by)
185   - tasks = tasks.of(filter[:type].presence)
186   - tasks = tasks.where(:status => filter[:status]) unless filter[:status].blank?
187   - tasks = filter_by_creation_date(filter, tasks)
188   - tasks = filter_by_closed_date(filter, tasks)
  178 + tasks = tasks.from_closed_date filter[:closed_from] unless filter[:closed_from].blank?
  179 + tasks = tasks.until_closed_date filter[:closed_until] unless filter[:closed_until].blank?
189 180  
190   - tasks = tasks.like('profiles.name', filter[:requestor]) unless filter[:requestor].blank?
191   - tasks = tasks.like('closed_bies_tasks.name', filter[:closed_by]) unless filter[:closed_by].blank?
192   - tasks = tasks.like('tasks.data', filter[:text]) unless filter[:text].blank?
  181 + tasks = tasks.where('profiles.name LIKE ?', filter[:requestor]) unless filter[:requestor].blank?
  182 + tasks = tasks.where('closed_bies_tasks.name LIKE ?', filter[:closed_by]) unless filter[:closed_by].blank?
  183 + tasks = tasks.where('tasks.data LIKE ?', "%#{filter[:text]}%") unless filter[:text].blank?
193 184 tasks
194 185 end
195 186  
... ...
app/helpers/action_tracker_helper.rb
... ... @@ -5,22 +5,22 @@ module ActionTrackerHelper
5 5 end
6 6  
7 7 def new_friendship_description ta
8   - n_('has made 1 new friend:<br />%{name}', 'has made %{num} new friends:<br />%{name}', ta.get_friend_name.size) % {
  8 + n_('has made 1 new friend:<br />%{name}', 'has made %{num} new friends:<br />%{name}', ta.get_friend_name.size).html_safe % {
9 9 num: ta.get_friend_name.size,
10   - name: ta.collect_group_with_index(:friend_name) do |n,i|
  10 + name: safe_join(ta.collect_group_with_index(:friend_name) do |n,i|
11 11 link_to image_tag(ta.get_friend_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")),
12 12 ta.get_friend_url[i], title: n
13   - end.join
  13 + end)
14 14 }
15 15 end
16 16  
17 17 def join_community_description ta
18   - n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size) % {
  18 + n_('has joined 1 community:<br />%{name}'.html_safe, 'has joined %{num} communities:<br />%{name}'.html_safe, ta.get_resource_name.size) % {
19 19 num: ta.get_resource_name.size,
20 20 name: ta.collect_group_with_index(:resource_name) do |n,i|
21   - link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")),
  21 + link = link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")),
22 22 ta.get_resource_url[i], title: n
23   - end.join
  23 + end.join.html_safe
24 24 }
25 25 end
26 26  
... ...
app/helpers/application_helper.rb
... ... @@ -101,7 +101,6 @@ module ApplicationHelper
101 101 #
102 102 # TODO: implement correcly the 'Help' button click
103 103 def help(content = nil, link_name = nil, options = {}, &block)
104   -
105 104 link_name ||= _('Help')
106 105  
107 106 @help_message_id ||= 1
... ... @@ -124,7 +123,7 @@ module ApplicationHelper
124 123 button = link_to_function(content_tag('span', link_name), "Element.show('#{help_id}')", options )
125 124 close_button = content_tag("div", link_to_function(_("Close"), "Element.hide('#{help_id}')", :class => 'close_help_button'))
126 125  
127   - text = content_tag('div', button + content_tag('div', content_tag('div', content) + close_button, :class => 'help_message', :id => help_id, :style => 'display: none;'), :class => 'help_box')
  126 + text = content_tag('div', button + content_tag('div', content_tag('div', content.html_safe) + close_button, :class => 'help_message', :id => help_id, :style => 'display: none;'), :class => 'help_box')
128 127  
129 128 unless block.nil?
130 129 concat(text)
... ... @@ -364,8 +363,8 @@ module ApplicationHelper
364 363 def popover_menu(title,menu_title,links,html_options={})
365 364 html_options[:class] = "" unless html_options[:class]
366 365 html_options[:class] << " menu-submenu-trigger"
367   - html_options[:onclick] = "toggleSubmenu(this, '#{menu_title}', #{CGI::escapeHTML(links.to_json)}); return false"
368 366  
  367 + html_options[:onclick] = "toggleSubmenu(this, '#{menu_title}', #{CGI::escapeHTML(links.to_json)}); return false".html_safe
369 368 link_to(content_tag(:span, title), '#', html_options)
370 369 end
371 370  
... ... @@ -475,9 +474,9 @@ module ApplicationHelper
475 474 map(&:role)
476 475 names = []
477 476 roles.each do |role|
478   - names << content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}")
  477 + names << content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}").html_safe
479 478 end
480   - names.join(', ')
  479 + safe_join(names, ', ')
481 480 end
482 481  
483 482 def role_color(role, env_id)
... ... @@ -913,7 +912,8 @@ module ApplicationHelper
913 912 end
914 913  
915 914 def admin_link
916   - user.is_admin?(environment) ? link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') : ''
  915 + admin_icon = '<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>'
  916 + user.is_admin?(environment) ? link_to(admin_icon.html_safe, environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') : ''
917 917 end
918 918  
919 919 def usermenu_logged_in
... ... @@ -922,23 +922,39 @@ module ApplicationHelper
922 922 if count > 0
923 923 pending_tasks_count = link_to("<i class=\"icon-menu-tasks\"></i><span class=\"task-count\">#{count}</span>", user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
924 924 end
  925 + user_identifier = "<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>"
  926 + welcome_link = link_to(user_identifier.html_safe, user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage'))
  927 + welcome_span = _("<span class='welcome'>Welcome,</span> %s") % welcome_link.html_safe
  928 + ctrl_panel_icon = '<i class="icon-menu-ctrl-panel"></i>'
  929 + ctrl_panel_section = '<strong>' + ctrl_panel_icon + _('Control panel') + '</strong>'
  930 + ctrl_panel_link = link_to(ctrl_panel_section.html_safe, user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content"))
  931 + logout_icon = '<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>'
  932 + logout_link = link_to(logout_icon.html_safe, { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
  933 + join_result = safe_join(
  934 + [welcome_span.html_safe, render_environment_features(:usermenu).html_safe, admin_link.html_safe,
  935 + manage_enterprises.html_safe, manage_communities.html_safe, ctrl_panel_link.html_safe,
  936 + pending_tasks_count.html_safe, logout_link.html_safe], "")
  937 + join_result
  938 + end
925 939  
926   - (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.url, :id => "homepage-link", :title => _('Go to your homepage'))) +
927   - render_environment_features(:usermenu) +
928   - admin_link +
929   - manage_enterprises +
930   - manage_communities +
931   - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content")) +
932   - pending_tasks_count +
933   - link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
  940 + def usermenu_notlogged_in
  941 + login_str = '<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>'
  942 + ret = _("<span class='login'>%s</span>") % modal_inline_link_to(login_str.html_safe, login_url, '#inlineLoginBox', :id => 'link_login')
  943 + return ret.html_safe
934 944 end
935 945  
  946 + def usermenu_signup
  947 + signup_str = '<strong>' + _('Sign up') + '</strong>'
  948 + ret = _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to(signup_str.html_safe, :controller => 'account', :action => 'signup')
  949 + return ret.html_safe
  950 +
  951 + end
936 952 def limited_text_area(object_name, method, limit, text_area_id, options = {})
937   - content_tag(:div, [
  953 + content_tag(:div, safe_join([
938 954 text_area(object_name, method, { :id => text_area_id, :onkeyup => "limited_text_area('#{text_area_id}', #{limit})" }.merge(options)),
939 955 content_tag(:p, content_tag(:span, limit) + ' ' + _(' characters left'), :id => text_area_id + '_left'),
940 956 content_tag(:p, _('Limit of characters reached'), :id => text_area_id + '_limit', :style => 'display: none')
941   - ].join, :class => 'limited-text-area')
  957 + ]), :class => 'limited-text-area')
942 958 end
943 959  
944 960 def expandable_text_area(object_name, method, text_area_id, options = {})
... ... @@ -1034,8 +1050,8 @@ module ApplicationHelper
1034 1050 end
1035 1051  
1036 1052 def render_tabs(tabs)
1037   - titles = tabs.inject(''){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') }
1038   - contents = tabs.inject(''){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) }
  1053 + titles = tabs.inject(''.html_safe){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') }
  1054 + contents = tabs.inject(''.html_safe){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) }
1039 1055  
1040 1056 content_tag(:div, content_tag(:ul, titles) + raw(contents), :class => 'ui-tabs')
1041 1057 end
... ... @@ -1053,7 +1069,7 @@ module ApplicationHelper
1053 1069 def expirable_link_to(expired, content, url, options = {})
1054 1070 if expired
1055 1071 options[:class] = (options[:class] || '') + ' disabled'
1056   - content_tag('a', '&nbsp;'+content_tag('span', content), options)
  1072 + content_tag('a', '&nbsp;'.html_safe+content_tag('span', content), options)
1057 1073 else
1058 1074 if options[:modal]
1059 1075 options.delete(:modal)
... ... @@ -1082,29 +1098,18 @@ module ApplicationHelper
1082 1098 def template_options(kind, field_name)
1083 1099 templates = environment.send(kind).templates
1084 1100 return '' if templates.count == 0
1085   - if templates.count == 1
1086   - if templates.first.custom_fields == {}
1087   - return hidden_field_tag("#{field_name}[template_id]", templates.first.id)
1088   - else
1089   - custom_fields = ""
1090   - templates.first.custom_fields.each { |field, value|
1091   - custom_fields += content_tag('div', content_tag('label', value[:title].capitalize, :class => 'formlabel') +
1092   - content_tag('div', text_field_tag( "profile_data[custom_fields][#{field}][title]", ''), :class => 'formfield type-text'), :class => "formfieldline" ) if value[:signup] == 'on'
1093   - }
1094   - content_tag('div', custom_fields)
1095   - end
1096   - else
1097   - radios = templates.map do |template|
1098   - content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template), :onchange => 'show_fields_for_template(this);'))
1099   - end.join("\n")
1100   -
1101   - content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') +
1102   - content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') +
1103   - content_tag('ul', radios, :style => 'list-style: none; padding-left: 20px; margin-top: 0.5em;'),
1104   - :id => 'template-options',
1105   - :style => 'margin-top: 1em'
1106   - )
1107   - end
  1101 + return hidden_field_tag("#{field_name}[template_id]", templates.first.id) if templates.count == 1
  1102 +
  1103 + radios = templates.map do |template|
  1104 + content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template)))
  1105 + end.join("\n").html_safe
  1106 +
  1107 + content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') +
  1108 + content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') +
  1109 + content_tag('ul', radios, :style => 'list-style: none; padding-left: 20px; margin-top: 0.5em;'),
  1110 + :id => 'template-options',
  1111 + :style => 'margin-top: 1em'
  1112 + )
1108 1113 end
1109 1114  
1110 1115 def expirable_content_reference(content, action, text, url, options = {})
... ... @@ -1137,7 +1142,7 @@ module ApplicationHelper
1137 1142 content_tag(:div, :class => 'errorExplanation', :id => 'errorExplanation') do
1138 1143 content_tag(:h2, _('Errors while saving')) +
1139 1144 content_tag(:ul) do
1140   - errors.map { |err| content_tag(:li, err) }.join
  1145 + safe_join(errors.map { |err| content_tag(:li, err) })
1141 1146 end
1142 1147 end
1143 1148 end
... ... @@ -1247,6 +1252,7 @@ module ApplicationHelper
1247 1252 :href=>"#",
1248 1253 :title=>_("Exit full screen mode")
1249 1254 })
  1255 + content.html_safe
1250 1256 end
1251 1257  
1252 1258 end
... ...
app/helpers/block_helper.rb
... ... @@ -3,13 +3,13 @@ module BlockHelper
3 3 def block_title(title, subtitle=nil)
4 4 block_header = block_heading title
5 5 block_header += block_heading(subtitle, 'h4') if subtitle
6   - content_tag 'div', block_header, :class => 'block-header'
  6 + content_tag('div', block_header, :class => 'block-header').html_safe
7 7 end
8 8  
9 9 def block_heading(title, heading='h3')
10 10 tag_class = 'block-' + (heading == 'h3' ? 'title' : 'subtitle')
11 11 tag_class += ' empty' if title.empty?
12   - content_tag heading, content_tag('span', h(title)), :class => tag_class
  12 + content_tag heading, content_tag('span', h(title)), :class => tag_class.html_safe
13 13 end
14 14  
15 15 def highlights_block_config_image_fields(block, image={}, row_number=nil)
... ...
app/helpers/blog_helper.rb
... ... @@ -41,12 +41,12 @@ module BlogHelper
41 41 css_add << position
42 42 content << (content_tag 'div', id: "post-#{art.id}", class: css_add do
43 43 content_tag 'div', class: position + '-inner blog-post-inner' do
44   - display_post(art, conf[:format]).html_safe +
45   - '<br style="clear:both"/>'.html_safe
  44 + display_post(art, conf[:format]) +
  45 + '<br style="clear:both"/>'
46 46 end
47   - end)
  47 + end).html_safe
48 48 }
49   - content.join("\n<hr class='sep-posts'/>\n") + (pagination or '')
  49 + safe_join(content, "\n<hr class='sep-posts'/>\n") + (pagination or '').html_safe
50 50 end
51 51  
52 52 def display_post(article, format = 'full')
... ... @@ -61,7 +61,8 @@ module BlogHelper
61 61 else
62 62 '<div class="post-pic" style="background-image:url('+img+')"></div>'
63 63 end
64   - end.to_s + title + html
  64 + end.to_s.html_safe +
  65 + title.html_safe + html
65 66 end
66 67  
67 68 def display_compact_format(article)
... ...
app/helpers/box_organizer_helper.rb
... ... @@ -38,7 +38,7 @@ module BoxOrganizerHelper
38 38 content_tag(:ul,
39 39 images_path.map do |preview|
40 40 content_tag(:li, image_tag(preview, height: '240', alt: ''))
41   - end.join("\n")
  41 + end.join("\n").html_safe
42 42 )
43 43 end
44 44  
... ...
app/helpers/boxes_helper.rb
... ... @@ -44,7 +44,7 @@ module BoxesHelper
44 44  
45 45 def display_boxes(holder, main_content)
46 46 boxes = holder.boxes.with_position.first(boxes_limit(holder))
47   - content = boxes.reverse.map { |item| display_box(item, main_content) }.join("\n")
  47 + content = safe_join(boxes.reverse.map { |item| display_box(item, main_content) }, "\n")
48 48 content = main_content if (content.blank?)
49 49  
50 50 content_tag('div', content, :class => 'boxes', :id => 'boxes' )
... ... @@ -54,7 +54,7 @@ module BoxesHelper
54 54 if holder.respond_to?(element)
55 55 content_tag('div', holder.send(element), options)
56 56 else
57   - ''
  57 + ''.html_safe
58 58 end
59 59 end
60 60  
... ... @@ -70,9 +70,10 @@ module BoxesHelper
70 70  
71 71 def display_box_content(box, main_content)
72 72 context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params, :user => user, :controller => controller }
73   - box_decorator.select_blocks(box, box.blocks.includes(:box), context).map do |item|
  73 + blocks = box_decorator.select_blocks(box, box.blocks.includes(:box), context).map do |item|
74 74 display_block item, main_content
75   - end.join("\n") + box_decorator.block_target(box)
  75 + end
  76 + safe_join(blocks, "\n") + box_decorator.block_target(box)
76 77 end
77 78  
78 79 def select_blocks box, arr, context
... ... @@ -136,17 +137,18 @@ module BoxesHelper
136 137  
137 138 result = filter_html(result, block)
138 139  
139   - content_tag('div',
140   - box_decorator.block_target(block.box, block) +
141   - content_tag('div',
142   - content_tag('div',
143   - content_tag('div',
144   - result + footer_content + box_decorator.block_edit_buttons(block),
145   - :class => 'block-inner-2'),
146   - :class => 'block-inner-1'),
147   - options),
148   - :class => 'block-outer') +
149   - box_decorator.block_handle(block)
  140 + join_result = safe_join([result, footer_content, box_decorator.block_edit_buttons(block)])
  141 + content_tag_inner_1 = content_tag('div', join_result, :class => 'block-inner-2')
  142 +
  143 + content_tag_inner_2 = content_tag('div', content_tag_inner_1, :class => 'block-inner-1')
  144 + content_tag_inner_3 = content_tag('div', content_tag_inner_2, options)
  145 + content_tag_inner_4 = box_decorator.block_target(block.box, block) + content_tag_inner_3
  146 + c = content_tag('div', content_tag_inner_4, :class => 'block-outer')
  147 + box_decorator_result = box_decorator.block_handle(block)
  148 + result_final = safe_join([c, box_decorator_result], "")
  149 +
  150 +
  151 + return result_final
150 152 end
151 153  
152 154 def wrap_main_content(content)
... ... @@ -156,17 +158,17 @@ module BoxesHelper
156 158 def extract_block_content(content)
157 159 case content
158 160 when Hash
159   - content_tag('iframe', '', :src => url_for(content))
  161 + content_tag('iframe', ''.html_safe, :src => url_for(content))
160 162 when String
161 163 if content.split("\n").size == 1 and content =~ /^https?:\/\//
162   - content_tag('iframe', '', :src => content)
  164 + content_tag('iframe', ''.html_safe, :src => content)
163 165 else
164 166 content
165 167 end
166 168 when Proc
167 169 self.instance_eval(&content)
168 170 when NilClass
169   - ''
  171 + ''.html_safe
170 172 else
171 173 raise "Unsupported content for block (#{content.class})"
172 174 end
... ... @@ -175,14 +177,14 @@ module BoxesHelper
175 177 module DontMoveBlocks
176 178 # does nothing
177 179 def self.block_target(box, block = nil)
178   - ''
  180 + ''.html_safe
179 181 end
180 182 # does nothing
181 183 def self.block_handle(block)
182   - ''
  184 + ''.html_safe
183 185 end
184 186 def self.block_edit_buttons(block)
185   - ''
  187 + ''.html_safe
186 188 end
187 189 def self.select_blocks box, arr, context
188 190 arr = arr.select{ |block| block.visible? context }
... ... @@ -229,9 +231,9 @@ module BoxesHelper
229 231 # makes the given block draggable so it can be moved away.
230 232 def block_handle(block)
231 233 return "" unless movable?(block)
232   - icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>"
  234 + icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>".html_safe
233 235 block_draggable("block-#{block.id}",
234   - :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}")
  236 + :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}".html_safe)
235 237 end
236 238  
237 239 def block_draggable(element_id, options={})
... ... @@ -302,7 +304,7 @@ module BoxesHelper
302 304 buttons << modal_inline_icon(:embed, _('Embed code'), {}, "#embed-code-box-#{block.id}") << html
303 305 end
304 306  
305   - content_tag('div', buttons.join("\n") + tag('br', :style => 'clear: left'), :class => 'button-bar')
  307 + content_tag('div', buttons.join("\n").html_safe + tag('br', :style => 'clear: left'), :class => 'button-bar')
306 308 end
307 309  
308 310 def current_blocks
... ...
app/helpers/buttons_helper.rb
... ... @@ -15,9 +15,9 @@ module ButtonsHelper
15 15 end
16 16 the_title = html_options[:title] || label
17 17 if html_options[:disabled]
18   - content_tag('a', '&nbsp;'+content_tag('span', label), html_options.merge(:class => the_class, :title => the_title))
  18 + content_tag('a', '&nbsp;'.html_safe+content_tag('span', label), html_options.merge(:class => the_class, :title => the_title))
19 19 else
20   - link_to('&nbsp;'+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title))
  20 + link_to('&nbsp;'.html_safe+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title))
21 21 end
22 22 end
23 23  
... ...
app/helpers/catalog_helper.rb
... ... @@ -19,18 +19,18 @@ module CatalogHelper
19 19 ancestors = category.ancestors.map { |c| link_to(c.name, {:controller => :catalog, :action => 'index', :level => c.id}) }.reverse
20 20 current_level = content_tag('strong', category.name)
21 21 all_items = [start] + ancestors + [current_level]
22   - content_tag('div', all_items.join(' &rarr; '), :id => 'breadcrumb')
  22 + content_tag('div', safe_join(all_items, ' &rarr; '), :id => 'breadcrumb')
23 23 end
24 24  
25 25 def category_link(category)
26 26 count = profile.products.from_category(category).count
27 27 name = truncate(category.name, :length => 22 - count.to_s.size)
28 28 link = link_to(name, {:controller => 'catalog', :action => 'index', :level => category.id}, :title => category.name)
29   - content_tag('div', "#{link} <span class=\"count\">#{count}</span>") if count > 0
  29 + content_tag('div', "#{link} <span class=\"count\">#{count}</span>".html_safe) if count > 0
30 30 end
31 31  
32 32 def category_with_sub_list(category)
33   - content_tag 'li', "#{category_link(category)}\n#{sub_category_list(category)}"
  33 + content_tag 'li', "#{category_link(category)}\n#{sub_category_list(category)}".html_safe
34 34 end
35 35  
36 36 def sub_category_list(category)
... ... @@ -39,7 +39,7 @@ module CatalogHelper
39 39 cat_link = category_link sub_category
40 40 sub_categories << content_tag('li', cat_link) unless cat_link.nil?
41 41 end
42   - content_tag('ul', sub_categories.join) if sub_categories.size > 0
  42 + content_tag('ul', sub_categories.join.html_safe) if sub_categories.size > 0
43 43 end
44 44  
45 45 end
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -7,7 +7,8 @@ module ContentViewerHelper
7 7 def display_number_of_comments(n)
8 8 base_str = "<span class='comment-count hide'>#{n}</span>"
9 9 amount_str = n == 0 ? _('no comments yet') : (n == 1 ? _('One comment') : _('%s comments') % n)
10   - base_str + "<span class='comment-count-write-out'>#{amount_str}</span>"
  10 + base_str += "<span class='comment-count-write-out'>#{amount_str}</span>"
  11 + base_str.html_safe
11 12 end
12 13  
13 14 def number_of_comments(article)
... ... @@ -19,11 +20,11 @@ module ContentViewerHelper
19 20 title = content_tag('h1', h(title), :class => 'title')
20 21 if article.belongs_to_blog? || article.belongs_to_forum?
21 22 unless args[:no_link]
22   - title = content_tag('h1', link_to(article.name, article.url), :class => 'title')
  23 + title = content_tag('h1', link_to(article.name, url_for(article.url)), :class => 'title')
23 24 end
24 25 comments = ''
25 26 unless args[:no_comments] || !article.accept_comments
26   - comments = (" - %s") % link_to_comments(article)
  27 + comments = (" - %s").html_safe % link_to_comments(article)
27 28 end
28 29 date_format = show_with_right_format_date article
29 30 title << content_tag('span',
... ...
app/helpers/display_helper.rb
... ... @@ -53,18 +53,19 @@ module DisplayHelper
53 53 end
54 54  
55 55 def txt2html(txt)
56   - txt.strip.
  56 + ret = txt.strip.
57 57 gsub( /\s*\n\s*\n\s*/, "\r<p/>\r" ).
58 58 gsub( /\s*\n\s*/, "\n<br/>\n" ).
59 59 gsub( /\r/, "\n" ).
60 60 gsub( /(^|\s)(www\.[^\s]+|https?:\/\/[^\s]+)/ ) do
61 61 pre_char, href = $1, $2
62 62 href = 'http://'+href if ! href.match /^https?:/
63   - content = href.gsub(/^https?:\/\//, '').scan(/.{1,4}/).join('&#x200B;')
  63 + content = safe_join(href.gsub(/^https?:\/\//, '').scan(/.{1,4}/), '&#x200B;'.html_safe)
64 64 pre_char +
65 65 content_tag(:a, content, :href => href, :target => '_blank',
66   - :rel => 'nofolow', :onclick => "return confirm('%s')" %
  66 + :rel => 'nofolow', :onclick => "return confirm('%s')".html_safe %
67 67 _('Are you sure you want to visit this web site?'))
68 68 end
  69 + ret.html_safe
69 70 end
70 71 end
... ...
app/helpers/events_helper.rb
1 1 module EventsHelper
2 2  
3 3 include DatesHelper
  4 + include ActionView::Helpers::OutputSafetyHelper
  5 +
4 6 def list_events(date, events)
5 7 title = _('Events for %s') % show_date_month(date)
  8 + user_events = events.select { |item| item.display_to?(user) }
  9 + events_for_month = safe_join(user_events.map {|item| display_event_in_listing(item)}, '')
6 10 content_tag('h2', title) +
7 11 content_tag('div',
8 12 (events.any? ?
9   - content_tag('table', events.select { |item| item.display_to?(user) }.map {|item| display_event_in_listing(item)}.join('')) :
10   - content_tag('em', _('No events for this month'), :class => 'no-events')
  13 + content_tag('table', events_for_month) :
  14 + content_tag('em', _('No events for this month'), :class => 'no-events')
11 15 ), :id => 'agenda-items'
12 16 )
13 17 end
... ...
app/helpers/forms_helper.rb
... ... @@ -101,7 +101,7 @@ module FormsHelper
101 101  
102 102 def required_fields_message
103 103 content_tag('p', content_tag('span',
104   - _("The <label class='pseudoformlabel'>highlighted</label> fields are mandatory."),
  104 + _("The <label class='pseudoformlabel'>highlighted</label> fields are mandatory.").html_safe,
105 105 :class => 'required-field'
106 106 ))
107 107 end
... ... @@ -112,10 +112,11 @@ module FormsHelper
112 112 options_for_select = container.inject([]) do |options, element|
113 113 text, value = option_text_and_value(element)
114 114 selected_attribute = ' selected="selected"' if option_value_selected?(value, selected)
115   - options << %(<option title="#{html_escape(text.to_s)}" value="#{html_escape(value.to_s)}"#{selected_attribute}>#{html_escape(text.to_s)}</option>)
  115 + opt = %(<option title="#{html_escape(text.to_s)}" value="#{html_escape(value.to_s)}"#{selected_attribute}>#{html_escape(text.to_s)}</option>)
  116 + options << opt.html_safe
116 117 end
117 118  
118   - options_for_select.join("\n")
  119 + safe_join(options_for_select, "\n")
119 120 end
120 121  
121 122 def balanced_table(items, per_row=3)
... ... @@ -248,8 +249,8 @@ module FormsHelper
248 249 def date_range_field(from_name, to_name, from_value, to_value, datepicker_options = {}, html_options = {})
249 250 from_id = html_options[:from_id] || 'datepicker-from-date'
250 251 to_id = html_options[:to_id] || 'datepicker-to-date'
251   - return _('From') +' '+ date_field(from_name, from_value, datepicker_options, html_options.merge({:id => from_id})) +
252   - ' ' + _('until') +' '+ date_field(to_name, to_value, datepicker_options, html_options.merge({:id => to_id}))
  252 + return (_('From') +' '+ date_field(from_name, from_value, datepicker_options, html_options.merge({:id => from_id})) +
  253 + ' ' + _('until') +' '+ date_field(to_name, to_value, datepicker_options, html_options.merge({:id => to_id}))).html_safe
253 254 end
254 255  
255 256 def select_folder(label_text, field_id, collection, default_value=nil, html_options = {}, js_options = {})
... ...
app/helpers/forum_helper.rb
... ... @@ -35,7 +35,7 @@ module ForumHelper
35 35 :id => "post-#{art.id}"
36 36 )
37 37 }
38   - content_tag('table', content.join) + (pagination or '')
  38 + content_tag('table', safe_join(content, "")) + (pagination or '').html_safe
39 39 end
40 40  
41 41 def last_topic_update(article)
... ...
app/helpers/language_helper.rb
... ... @@ -40,7 +40,7 @@ module LanguageHelper
40 40 else
41 41 link_to(name, params.merge(:lang => code), :rel => 'nofollow')
42 42 end
43   - end.join(separator)
  43 + end.join(separator).html_safe
44 44 content_tag('div', languages, :id => 'language-chooser', :help => _('The language you choose here is the language used for options, buttons, etc. It does not affect the language of the content created by other users.'))
45 45 end
46 46 end
... ...
app/helpers/layout_helper.rb
... ... @@ -40,7 +40,8 @@ module LayoutHelper
40 40  
41 41 output += templete_javascript_ng.to_s
42 42  
43   - output
  43 + # This output should be safe!
  44 + output.html_safe
44 45 end
45 46  
46 47 def noosfero_stylesheets
... ... @@ -64,7 +65,9 @@ module LayoutHelper
64 65 output << stylesheet_link_tag(global_css_pub)
65 66 end
66 67 output << stylesheet_link_tag(theme_stylesheet_path)
67   - output.join "\n"
  68 +
  69 + # This output should be safe!
  70 + output.join("\n").html_safe
68 71 end
69 72  
70 73 def noosfero_layout_features
... ...
app/helpers/manage_products_helper.rb
... ... @@ -38,10 +38,11 @@ module ManageProductsHelper
38 38 end
39 39  
40 40 def options_for_select_categories(categories, selected = nil)
41   - categories.sort_by{|cat| cat.name.transliterate}.map do |category|
42   - selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '')
43   - "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{category.name + (category.leaf? ? '': ' &raquo;')}</option>"
44   - end.join("\n")
  41 + safe_join(categories.sort_by{ |cat|
  42 + cat.name.transliterate}.map do |category|
  43 + selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '')
  44 + "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{category.name + (category.leaf? ? '': ' &raquo;')}</option>".html_safe
  45 + end, "\n")
45 46 end
46 47  
47 48 def build_selects_for_ancestors(ancestors, current_category)
... ... @@ -76,10 +77,13 @@ module ManageProductsHelper
76 77  
77 78 def categories_container(categories_selection_html, hierarchy_html = '')
78 79 content_tag 'div',
79   - render('categories_autocomplete') +
80   - hidden_field_tag('selected_category_id') +
81   - content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
82   - content_tag('div', categories_selection_html, :id => 'categories_container_wrapper'),
  80 + safe_join(
  81 + [
  82 + render('categories_autocomplete'),
  83 + hidden_field_tag('selected_category_id'),
  84 + content_tag('div', hierarchy_html, :id => 'hierarchy_navigation'),
  85 + content_tag('div', categories_selection_html, :id => 'categories_container_wrapper')
  86 + ], ''),
83 87 :id => 'categories-container'
84 88 end
85 89  
... ...
app/helpers/profile_editor_helper.rb
... ... @@ -129,7 +129,11 @@ module ProfileEditorHelper
129 129 else
130 130 domains = environment.domains
131 131 end
132   - labelled_form_field(_('Preferred domain name:'), select(object, :preferred_domain_id, domains.map {|item| [item.name, item.id]}, :prompt => '&lt;' + _('Select domain') + '&gt;'))
  132 + select_domain_prompt = '&lt;'.html_safe + _('Select domain').html_safe + '&gt;'.html_safe
  133 + select_field = select(object, :preferred_domain_id, domains.map {
  134 + |item| [item.name, item.id]}, :prompt => select_domain_prompt.html_safe)
  135 +
  136 + labelled_form_field(_('Preferred domain name:'), select_field)
133 137 end
134 138  
135 139 def control_panel(&block)
... ...
app/helpers/profile_image_helper.rb
... ... @@ -131,7 +131,7 @@ module ProfileImageHelper
131 131 links = links_for_balloon(profile)
132 132 content_tag('div', content_tag(tag,
133 133 (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ?
134   - popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") +
  134 + popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "").html_safe +
135 135 link_to(
136 136 content_tag( 'span', profile_image( profile, size ), :class => img_class ) +
137 137 content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) +
... ... @@ -139,7 +139,7 @@ module ProfileImageHelper
139 139 profile.url,
140 140 :class => 'profile_link url',
141 141 :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name,
142   - :title => profile.name ),
  142 + :title => profile.name ).html_safe,
143 143 :class => 'vcard'), :class => 'common-profile-list-block')
144 144 end
145 145 end
... ...
app/helpers/search_helper.rb
... ... @@ -124,10 +124,10 @@ module SearchHelper
124 124 def filters(asset)
125 125 return if !asset
126 126 klass = asset_class(asset)
127   - content_tag('div', klass::SEARCH_FILTERS.map do |name, options|
  127 + content_tag('div', safe_join(klass::SEARCH_FILTERS.map do |name, options|
128 128 default = klass.respond_to?("default_search_#{name}") ? klass.send("default_search_#{name}".to_s) : nil
129 129 select_filter(name, options, default)
130   - end.join("\n"), :id => 'search-filters')
  130 + end, "\n"), :id => 'search-filters')
131 131 end
132 132  
133 133 def assets_menu(selected)
... ... @@ -137,11 +137,11 @@ module SearchHelper
137 137 # menu.
138 138 assets.delete(:events)
139 139 content_tag('ul',
140   - assets.map do |asset|
  140 + safe_join(assets.map do |asset|
141 141 options = {}
142 142 options.merge!(:class => 'selected') if selected.to_s == asset.to_s
143 143 content_tag('li', asset_link(asset), options)
144   - end.join("\n"),
  144 + end, "\n"),
145 145 :id => 'assets-menu')
146 146 end
147 147  
... ...
app/helpers/tags_helper.rb
... ... @@ -58,7 +58,7 @@ module TagsHelper
58 58  
59 59 if options[:show_count]
60 60 display_count = options[:show_count] ? "<small><sup>(#{count})</sup></small>" : ""
61   - link_to tag + display_count, destination, :style => style
  61 + link_to (tag + display_count).html_safe, destination, :style => style
62 62 else
63 63 link_to h(tag) , destination, :style => style,
64 64 :title => n_( 'one item', '%d items', count ) % count
... ...
app/helpers/tinymce_helper.rb
... ... @@ -7,7 +7,7 @@ module TinymceHelper
7 7 output += javascript_include_tag 'tinymce/js/tinymce/jquery.tinymce.min.js'
8 8 output += javascript_include_tag 'tinymce.js'
9 9 output += include_macro_js_files.to_s
10   - output
  10 + output.html_safe
11 11 end
12 12  
13 13 def tinymce_init_js options = {}
... ... @@ -37,7 +37,7 @@ module TinymceHelper
37 37 #cleanup non tinymce options
38 38 options = options.except :mode
39 39  
40   - "noosfero.tinymce.init(#{options.to_json})"
  40 + "noosfero.tinymce.init(#{options.to_json})".html_safe
41 41 end
42 42  
43 43 def menubar mode
... ...
app/mailers/mailing.rb
1 1 require_dependency 'mailing_job'
2 2  
3   -class Mailing < ActiveRecord::Base
  3 +class Mailing < ApplicationRecord
4 4  
5 5 acts_as_having_settings :field => :data
6 6  
... ...
app/models/abuse_report.rb
1   -class AbuseReport < ActiveRecord::Base
  1 +class AbuseReport < ApplicationRecord
2 2  
3 3 attr_accessible :content, :reason
4 4  
... ...
app/models/action_tracker_notification.rb
1   -class ActionTrackerNotification < ActiveRecord::Base
  1 +class ActionTrackerNotification < ApplicationRecord
2 2  
3 3 belongs_to :profile
4 4 belongs_to :action_tracker, :class_name => 'ActionTracker::Record', :foreign_key => 'action_tracker_id'
... ...
app/models/application_record.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +class ApplicationRecord < ActiveRecord::Base
  2 +
  3 + self.abstract_class = true
  4 +
  5 + def self.postgresql?
  6 + self.connection.adapter_name == 'PostgreSQL'
  7 + end
  8 +
  9 + # an ActionView instance for rendering views on models
  10 + def self.action_view
  11 + @action_view ||= begin
  12 + view_paths = ::ActionController::Base.view_paths
  13 + action_view = ::ActionView::Base.new view_paths
  14 + # for using Noosfero helpers inside render calls
  15 + action_view.extend ::ApplicationHelper
  16 + action_view
  17 + end
  18 + end
  19 +
  20 + # default value needed for the above ActionView
  21 + def to_partial_path
  22 + self.class.name.underscore
  23 + end
  24 +
  25 + alias :meta_cache_key :cache_key
  26 + def cache_key
  27 + key = [Noosfero::VERSION, meta_cache_key]
  28 + key.unshift(ApplicationRecord.connection.schema_search_path) if ApplicationRecord.postgresql?
  29 + key.join('/')
  30 + end
  31 +
  32 + def self.like_search(query, options={})
  33 + if defined?(self::SEARCHABLE_FIELDS) || options[:fields].present?
  34 + fields_per_table = {}
  35 + fields_per_table[table_name] = (options[:fields].present? ? options[:fields] : self::SEARCHABLE_FIELDS.keys.map(&:to_s)) & column_names
  36 +
  37 + if options[:joins].present?
  38 + join_asset = options[:joins].to_s.classify.constantize
  39 + if defined?(join_asset::SEARCHABLE_FIELDS) || options[:fields].present?
  40 + fields_per_table[join_asset.table_name] = (options[:fields].present? ? options[:fields] : join_asset::SEARCHABLE_FIELDS.keys.map(&:to_s)) & join_asset.column_names
  41 + end
  42 + end
  43 +
  44 + query = query.downcase.strip
  45 + fields_per_table.delete_if { |table,fields| fields.blank? }
  46 + conditions = fields_per_table.map do |table,fields|
  47 + fields.map do |field|
  48 + "lower(#{table}.#{field}) LIKE '%#{query}%'"
  49 + end.join(' OR ')
  50 + end.join(' OR ')
  51 +
  52 + if options[:joins].present?
  53 + joins(options[:joins]).where(conditions)
  54 + else
  55 + where(conditions)
  56 + end
  57 +
  58 + else
  59 + raise "No searchable fields defined for #{self.name}"
  60 + end
  61 + end
  62 +
  63 +end
  64 +
... ...
app/models/approve_article.rb
... ... @@ -86,7 +86,7 @@ class ApproveArticle &lt; Task
86 86  
87 87 def information
88 88 if article
89   - {:message => _('%{requestor} wants to publish the article: %{linked_subject}.')}
  89 + {:message => _('%{requestor} wants to publish the article: %{linked_subject}.').html_safe}
90 90 else
91 91 {:message => _("The article was removed.")}
92 92 end
... ...
app/models/article.rb
1 1  
2   -class Article < ActiveRecord::Base
  2 +class Article < ApplicationRecord
3 3  
4 4 include SanitizeHelper
5 5  
... ...
app/models/article_categorization.rb
1   -class ArticleCategorization < ActiveRecord::Base
  1 +class ArticleCategorization < ApplicationRecord
2 2 self.table_name = :articles_categories
3 3  
4 4 belongs_to :article
... ...
app/models/article_follower.rb
1   -class ArticleFollower < ActiveRecord::Base
  1 +class ArticleFollower < ApplicationRecord
2 2  
3 3 attr_accessible :article_id, :person_id, :since
4 4 belongs_to :article, :counter_cache => :followers_count
... ...
app/models/block.rb
1   -class Block < ActiveRecord::Base
  1 +class Block < ApplicationRecord
2 2  
3 3 attr_accessible :title, :subtitle, :display, :limit, :box_id, :posts_per_page,
4 4 :visualization_format, :language, :display_user,
... ...
app/models/box.rb
1   -class Box < ActiveRecord::Base
  1 +class Box < ApplicationRecord
2 2  
3 3 acts_as_list scope: -> box { where owner_id: box.owner_id, owner_type: box.owner_type }
4 4  
... ...
app/models/category.rb
1   -class Category < ActiveRecord::Base
  1 +class Category < ApplicationRecord
2 2  
3 3 attr_accessible :name, :parent_id, :display_color, :display_in_menu, :image_builder, :environment, :parent
4 4  
... ...
app/models/certifier.rb
1   -class Certifier < ActiveRecord::Base
  1 +class Certifier < ApplicationRecord
2 2  
3 3 attr_accessible :name, :environment
4 4  
... ...
app/models/chat_message.rb
1   -class ChatMessage < ActiveRecord::Base
  1 +class ChatMessage < ApplicationRecord
  2 +
2 3 attr_accessible :body, :from, :to
3 4  
4 5 belongs_to :to, :class_name => 'Profile'
... ...
app/models/comment.rb
1   -class Comment < ActiveRecord::Base
  1 +class Comment < ApplicationRecord
2 2  
3 3 SEARCHABLE_FIELDS = {
4 4 :title => {:label => _('Title'), :weight => 10},
... ...
app/models/contact_list.rb
1   -class ContactList < ActiveRecord::Base
  1 +class ContactList < ApplicationRecord
2 2  
3 3 serialize :list, Array
4 4  
... ...
app/models/create_community.rb
... ... @@ -60,9 +60,9 @@ class CreateCommunity &lt; Task
60 60  
61 61 def information
62 62 if description.blank?
63   - { :message => _('%{requestor} wants to create community %{subject} with no description.') }
  63 + { :message => _('%{requestor} wants to create community %{subject} with no description.').html_safe }
64 64 else
65   - { :message => _('%{requestor} wants to create community %{subject} with this description:<p><em>%{description}</em></p>'),
  65 + { :message => _('%{requestor} wants to create community %{subject} with this description:<p><em>%{description}</em></p>').html_safe,
66 66 :variables => {:description => description} }
67 67 end
68 68 end
... ...
app/models/create_enterprise.rb
... ... @@ -163,7 +163,7 @@ class CreateEnterprise &lt; Task
163 163 end
164 164  
165 165 def information
166   - {:message => _('%{requestor} wants to create enterprise %{subject}.')}
  166 + {:message => _('%{requestor} wants to create enterprise %{subject}.').html_safe}
167 167 end
168 168  
169 169 def task_created_message
... ...
app/models/custom_field.rb
1   -class CustomField < ActiveRecord::Base
  1 +class CustomField < ApplicationRecord
  2 +
2 3 attr_accessible :name, :default_value, :format, :extras, :customized_type, :active, :required, :signup, :environment, :moderation_task
3 4 serialize :customized_type
4 5 serialize :extras
... ...
app/models/custom_field_value.rb
1   -class CustomFieldValue < ActiveRecord::Base
  1 +class CustomFieldValue < ApplicationRecord
  2 +
2 3 belongs_to :custom_field
3 4 belongs_to :customized, :polymorphic => true
4 5 attr_accessible :value, :public, :customized, :custom_field, :customized_type
... ...
app/models/doc_item.rb
... ... @@ -17,7 +17,7 @@ class DocItem
17 17 else
18 18 match
19 19 end
20   - end
  20 + end.html_safe
21 21 end
22 22  
23 23 private
... ...
app/models/domain.rb
1 1 require 'noosfero/multi_tenancy'
2 2  
3   -class Domain < ActiveRecord::Base
  3 +class Domain < ApplicationRecord
4 4  
5 5 attr_accessible :name, :owner, :is_default
6 6  
... ...
app/models/email_template.rb
1   -class EmailTemplate < ActiveRecord::Base
  1 +class EmailTemplate < ApplicationRecord
2 2  
3 3 belongs_to :owner, :polymorphic => true
4 4  
... ...
app/models/environment.rb
1 1 # A Environment is like a website to be hosted in the platform. It may
2 2 # contain multiple Profile's and can be identified by several different
3 3 # domains.
4   -class Environment < ActiveRecord::Base
  4 +class Environment < ApplicationRecord
5 5  
6 6 attr_accessible :name, :is_default, :signup_welcome_text_subject,
7 7 :signup_welcome_text_body, :terms_of_use,
... ... @@ -731,7 +731,7 @@ class Environment &lt; ActiveRecord::Base
731 731 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
732 732 url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port)
733 733 url << Noosfero.root('')
734   - url
  734 + url.html_safe
735 735 end
736 736  
737 737 def to_s
... ...
app/models/external_feed.rb
1   -class ExternalFeed < ActiveRecord::Base
  1 +class ExternalFeed < ApplicationRecord
2 2  
3 3 belongs_to :blog
4 4 validates_presence_of :blog_id
... ...
app/models/favorite_enterprise_person.rb
1   -class FavoriteEnterprisePerson < ActiveRecord::Base
  1 +class FavoriteEnterprisePerson < ApplicationRecord
2 2  
3 3 attr_accessible :person, :enterprise
4 4  
... ...
app/models/friendship.rb
1   -class Friendship < ActiveRecord::Base
  1 +class Friendship < ApplicationRecord
2 2 track_actions :new_friendship, :after_create, :keep_params => ["friend.name", "friend.url", "friend.profile_custom_icon"], :custom_user => :person
3 3  
4 4 extend CacheCounterHelper
... ...
app/models/image.rb
1   -class Image < ActiveRecord::Base
  1 +class Image < ApplicationRecord
2 2  
3 3 attr_accessible :uploaded_data, :label, :remove_image
4 4 attr_accessor :remove_image
... ...
app/models/input.rb
1   -class Input < ActiveRecord::Base
  1 +class Input < ApplicationRecord
2 2  
3 3 attr_accessible :product, :product_id, :product_category, :product_category_id,
4 4 :amount_used, :unit_id, :price_per_unit, :relevant_to_price, :is_from_solidarity_economy
... ...
app/models/invite_friend.rb
... ... @@ -13,7 +13,7 @@ class InviteFriend &lt; Invitation
13 13 end
14 14  
15 15 def information
16   - {:message => _('%{requestor} wants to be your friend.')}
  16 + {:message => _('%{requestor} wants to be your friend.').html_safe}
17 17 end
18 18  
19 19 def accept_details
... ... @@ -25,7 +25,7 @@ class InviteFriend &lt; Invitation
25 25 end
26 26  
27 27 def target_notification_description
28   - _('%{requestor} wants to be your friend.') % {:requestor => requestor.name}
  28 + (_('%{requestor} wants to be your friend.') % {:requestor => requestor.name}).html_safe
29 29 end
30 30  
31 31 def permission
... ...
app/models/invite_member.rb
... ... @@ -25,7 +25,7 @@ class InviteMember &lt; Invitation
25 25 end
26 26  
27 27 def information
28   - {:message => _('%{requestor} invited you to join %{linked_subject}.')}
  28 + {:message => _('%{requestor} invited you to join %{linked_subject}.').html_safe}
29 29 end
30 30  
31 31 def url
... ... @@ -37,7 +37,7 @@ class InviteMember &lt; Invitation
37 37 end
38 38  
39 39 def target_notification_description
40   - _('%{requestor} invited you to join %{community}.') % {:requestor => requestor.name, :community => community.name}
  40 + (_('%{requestor} invited you to join %{community}.') % {:requestor => requestor.name, :community => community.name}).html_safe
41 41 end
42 42  
43 43 def target_notification_message
... ...
app/models/license.rb
1   -class License < ActiveRecord::Base
  1 +class License < ApplicationRecord
2 2  
3 3 attr_accessible :name, :url
4 4  
... ...
app/models/mailing_sent.rb
1   -class MailingSent < ActiveRecord::Base
  1 +class MailingSent < ApplicationRecord
  2 +
2 3 attr_accessible :person
3 4 belongs_to :mailing
4 5 belongs_to :person
... ...
app/models/national_region.rb
1   -class NationalRegion < ActiveRecord::Base
  1 +class NationalRegion < ApplicationRecord
2 2  
3 3 SEARCHABLE_FIELDS = {
4 4 :name => {:label => _('Name'), :weight => 1},
... ...
app/models/national_region_type.rb
1   -class NationalRegionType < ActiveRecord::Base
  1 +class NationalRegionType < ApplicationRecord
2 2 COUNTRY = 1
3 3 STATE = 2
4 4 CITY = 3
... ...
app/models/person.rb
... ... @@ -341,7 +341,7 @@ class Person &lt; Profile
341 341 environment ||= self.environment
342 342 role_assignments.includes([:role, :resource]).select { |ra| ra.resource == environment }.map{|ra|ra.role.permissions}.any? do |ps|
343 343 ps.any? do |p|
344   - ActiveRecord::Base::PERMISSIONS['Environment'].keys.include?(p)
  344 + ApplicationRecord::PERMISSIONS['Environment'].keys.include?(p)
345 345 end
346 346 end
347 347 end
... ...
app/models/price_detail.rb
1   -class PriceDetail < ActiveRecord::Base
  1 +class PriceDetail < ApplicationRecord
2 2  
3 3 attr_accessible :price, :production_cost_id
4 4  
... ...
app/models/product.rb
1   -class Product < ActiveRecord::Base
  1 +class Product < ApplicationRecord
2 2  
3 3 SEARCHABLE_FIELDS = {
4 4 :name => {:label => _('Name'), :weight => 10},
... ...
app/models/product_qualifier.rb
1   -class ProductQualifier < ActiveRecord::Base
  1 +class ProductQualifier < ApplicationRecord
2 2  
3 3 attr_accessible :qualifier, :product, :certifier
4 4  
... ...
app/models/production_cost.rb
1   -class ProductionCost < ActiveRecord::Base
  1 +class ProductionCost < ApplicationRecord
2 2  
3 3 attr_accessible :name, :owner
4 4  
... ...
app/models/profile.rb
1 1 # A Profile is the representation and web-presence of an individual or an
2 2 # organization. Every Profile is attached to its Environment of origin,
3 3 # which by default is the one returned by Environment:default.
4   -class Profile < ActiveRecord::Base
  4 +class Profile < ApplicationRecord
5 5  
6 6 attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time,
7 7 :redirection_after_login, :custom_url_redirection,
... ... @@ -675,7 +675,7 @@ class Profile &lt; ActiveRecord::Base
675 675 url << url_options[:host]
676 676 url << ':' << url_options[:port].to_s if url_options.key?(:port)
677 677 url << Noosfero.root('')
678   - url
  678 + url.html_safe
679 679 end
680 680  
681 681 private :generate_url, :url_options
... ...
app/models/profile_activity.rb
1   -class ProfileActivity < ActiveRecord::Base
  1 +class ProfileActivity < ApplicationRecord
2 2  
3 3 self.record_timestamps = false
4 4  
... ...
app/models/profile_categorization.rb
1   -class ProfileCategorization < ActiveRecord::Base
  1 +class ProfileCategorization < ApplicationRecord
2 2 self.table_name = :categories_profiles
3 3 belongs_to :profile
4 4 belongs_to :category
... ...
app/models/profile_suggestion.rb
1   -class ProfileSuggestion < ActiveRecord::Base
  1 +class ProfileSuggestion < ApplicationRecord
  2 +
2 3 belongs_to :person
3 4 belongs_to :suggestion, :class_name => 'Profile', :foreign_key => :suggestion_id
4 5  
... ...
app/models/qualifier.rb
1   -class Qualifier < ActiveRecord::Base
  1 +class Qualifier < ApplicationRecord
2 2  
3 3 attr_accessible :name, :environment
4 4  
... ...
app/models/qualifier_certifier.rb
1   -class QualifierCertifier < ActiveRecord::Base
  1 +class QualifierCertifier < ApplicationRecord
2 2 belongs_to :qualifier
3 3 belongs_to :certifier
4 4  
... ...
app/models/reported_image.rb
1   -class ReportedImage < ActiveRecord::Base
  1 +class ReportedImage < ApplicationRecord
2 2 belongs_to :abuse_report
3 3  
4 4 validates_presence_of :abuse_report
... ...
app/models/scrap.rb
1   -class Scrap < ActiveRecord::Base
  1 +class Scrap < ApplicationRecord
2 2  
3 3 include SanitizeHelper
4 4  
... ...
app/models/search_term.rb
1   -class SearchTerm < ActiveRecord::Base
  1 +class SearchTerm < ApplicationRecord
2 2 validates_presence_of :term, :context
3 3 validates_uniqueness_of :term, :scope => [:context_id, :context_type, :asset]
4 4  
... ... @@ -25,7 +25,7 @@ class SearchTerm &lt; ActiveRecord::Base
25 25 # Therefore the score is 97. Them we sum every score to get the total score
26 26 # for a search term.
27 27 def self.occurrences_scores
28   - Hash[*ActiveRecord::Base.connection.execute(
  28 + Hash[*ApplicationRecord.connection.execute(
29 29 joins(:occurrences).
30 30 select("search_terms.id, sum(#{SearchTermOccurrence::EXPIRATION_TIME.to_i} - extract(epoch from (now() - search_term_occurrences.created_at))) as value").
31 31 where("search_term_occurrences.created_at > ?", DateTime.now - SearchTermOccurrence::EXPIRATION_TIME).
... ...
app/models/search_term_occurrence.rb
1   -class SearchTermOccurrence < ActiveRecord::Base
  1 +class SearchTermOccurrence < ApplicationRecord
2 2  
3 3 belongs_to :search_term
4 4 validates_presence_of :search_term
... ...
app/models/suggest_article.rb
... ... @@ -65,7 +65,7 @@ class SuggestArticle &lt; Task
65 65  
66 66 def information
67 67 variables = requestor.blank? ? {:requestor => sender} : {}
68   - { :message => _('%{requestor} suggested the publication of the article: %{subject}.'),
  68 + { :message => _('%{requestor} suggested the publication of the article: %{subject}.').html_safe,
69 69 :variables => variables }
70 70 end
71 71  
... ... @@ -78,7 +78,7 @@ class SuggestArticle &lt; Task
78 78 end
79 79  
80 80 def target_notification_description
81   - _('%{requestor} suggested the publication of the article: %{article}.') %
  81 + _('%{requestor} suggested the publication of the article: %{article}.').html_safe %
82 82 {:requestor => sender, :article => article_name}
83 83 end
84 84  
... ...
app/models/suggestion_connection.rb
1   -class SuggestionConnection < ActiveRecord::Base
  1 +class SuggestionConnection < ApplicationRecord
  2 +
2 3 attr_accessible :suggestion, :suggestion_id, :connection_type, :connection_id
3 4  
4 5 belongs_to :suggestion, :class_name => 'ProfileSuggestion', :foreign_key => 'suggestion_id'
... ...
app/models/task.rb
... ... @@ -9,7 +9,7 @@
9 9 # This class has a +data+ field of type <tt>text</tt>, where you can store any
10 10 # type of data (as serialized Ruby objects) you need for your subclass (which
11 11 # will need to declare <ttserialize</tt> itself).
12   -class Task < ActiveRecord::Base
  12 +class Task < ApplicationRecord
13 13  
14 14 acts_as_having_settings :field => :data
15 15 acts_as_ordered_taggable
... ... @@ -347,6 +347,21 @@ class Task &lt; ActiveRecord::Base
347 347 where [environment_condition, profile_condition].compact.join(' OR ')
348 348 }
349 349  
  350 + scope :from_closed_date, -> closed_from {
  351 + where('tasks.end_date >= ?', closed_from.beginning_of_day) unless closed_from.blank?
  352 + }
  353 +
  354 + scope :until_closed_date, -> closed_until {
  355 + where('tasks.end_date <= ?', closed_until.end_of_day) unless closed_until.blank?
  356 + }
  357 +
  358 + scope :from_creation_date, -> created_from {
  359 + where('tasks.created_at >= ?', created_from.beginning_of_day) unless created_from.blank?
  360 + }
  361 +
  362 + scope :until_creation_date, -> created_until {
  363 + where('tasks.created_at <= ?', created_until.end_of_day) unless created_until.blank?
  364 + }
350 365  
351 366 def self.pending_types_for(profile)
352 367 Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] }
... ...
app/models/thumbnail.rb
1   -class Thumbnail < ActiveRecord::Base
  1 +class Thumbnail < ApplicationRecord
2 2  
3 3 attr_accessible :uploaded_data
4 4 # mass assigned by attachment_fu
... ...
app/models/unit.rb
1   -class Unit < ActiveRecord::Base
  1 +class Unit < ApplicationRecord
2 2  
3 3 acts_as_list scope: -> unit { where environment_id: unit.environment_id }
4 4  
... ...
app/models/user.rb
... ... @@ -4,7 +4,7 @@ require &#39;securerandom&#39;
4 4  
5 5 # User models the system users, and is generated by the acts_as_authenticated
6 6 # Rails generator.
7   -class User < ActiveRecord::Base
  7 +class User < ApplicationRecord
8 8  
9 9 attr_accessible :login, :email, :password, :password_confirmation, :activated_at
10 10  
... ...
app/models/validation_info.rb
1   -class ValidationInfo < ActiveRecord::Base
  1 +class ValidationInfo < ApplicationRecord
2 2  
3 3 attr_accessible :validation_methodology, :restrictions, :organization
4 4  
... ...
app/views/account/_signup_form.html.erb
... ... @@ -107,7 +107,7 @@
107 107 <%= render :partial => 'profile_editor/person_form', :locals => {:f => f} %>
108 108 <% end %>
109 109  
110   - <%= @plugins.dispatch(:signup_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
  110 + <%= safe_join(@plugins.dispatch(:signup_extra_contents).collect { |content| instance_eval(&content) }, "") %>
111 111  
112 112 <% unless @terms_of_use.blank? %>
113 113 <div id='terms-of-use-box' class='formfieldline'>
... ...
app/views/account/activate_enterprise.html.erb
... ... @@ -14,7 +14,7 @@
14 14 <div id="enterprise-activation-create-user-form" style="display: none">
15 15 <h3><%= _('Personal signup form') %></h3>
16 16 <%= render :partial => 'signup_form', :locals => { :hidden_atention => true } %>
17   - <p><%= message = _('<b>Warning</b>: this form is for your personal information, not of your enterprise. So you will have a personal account that can manage your enterprise.') %></p>
  17 + <p><%= message = _('<b>Warning</b>: this form is for your personal information, not of your enterprise. So you will have a personal account that can manage your enterprise.').html_safe %></p>
18 18 </div>
19 19  
20 20 <div id="enterprise-activation-login-form" style="display: none">
... ...
app/views/account/invalid_change_password_code.html.erb
1 1 <h1><%= _("Invalid change password code") %></h1>
2 2  
3 3 <p>
4   -<%= _('The code you are using for password change is not valid. Please try to request password change using the <a href="%s">"I forgot my password"</a> functionality.') % url_for(:action => 'forgot_password') %>
  4 +<%= _('The code you are using for password change is not valid. Please try to request password change using the <a href="%s">"I forgot my password"</a> functionality.') % url_for(:action => 'forgot_password').html_safe %>
5 5 </p>
... ...
app/views/account/login.html.erb
... ... @@ -20,7 +20,7 @@
20 20 </label>
21 21 </div>
22 22  
23   - <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_exec(&content) }.join("") %>
  23 + <%= safe_join(@plugins.dispatch(:login_extra_contents).collect { |content| instance_exec(&content) }, "") %>
24 24  
25 25 <% button_bar do %>
26 26 <%= submit_button( 'login', _('Log in') )%>
... ...
app/views/account/login_block.html.erb
... ... @@ -15,7 +15,7 @@
15 15  
16 16 <%= f.password_field :password %>
17 17  
18   - <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
  18 + <%= safe_join(@plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }, "") %>
19 19  
20 20 <% button_bar do %>
21 21 <%= submit_button( 'login', _('Log in') )%>
... ...
app/views/account/new_password_ok.html.erb
... ... @@ -5,5 +5,5 @@
5 5 </p>
6 6  
7 7 <p>
8   -<%= _("You can <a href='%s'>login</a> now.") % url_for(:action => 'login') %>
  8 +<%= _("You can <a href='%s'>login</a> now.").html_safe % url_for(:action => 'login') %>
9 9 </p>
... ...
app/views/blocks/blog_archives.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <%= content_tag('li', content_tag('strong', "#{year.to_i} (#{count})")) %>
7 7 <ul class='<%= year.to_i %>-archive'>
8 8 <% block.blog.total_number_of_posts(:by_month, year).each do |month, count| %>
9   - <%= content_tag('li', link_to("#{month_name(month.to_i)} (#{count})", block.blog.url.merge(year: year.to_i, month: month.to_i))) %>
  9 + <%= content_tag('li', link_to("#{month_name(month.to_i)} (#{count})", url_for(block.blog.url.merge(year: year.to_i, month: month.to_i)).html_safe)) %>
10 10 <% end %>
11 11 </ul>
12 12 <% end %>
... ...
app/views/blocks/link_list.html.erb
... ... @@ -8,7 +8,7 @@
8 8 <%= block.sanitize_link(link_to(link[:name], block.expand_address(link[:address]),
9 9 :target => link[:target],
10 10 :class => (link[:icon] ? "icon-#{link[:icon]}" : ''),
11   - :title => link[:title])) %>
  11 + :title => link[:title])).html_safe %>
12 12 </li>
13 13 <% end %>
14 14 </ul>
... ...
app/views/blocks/login.html.erb
... ... @@ -3,7 +3,7 @@
3 3 <h2><%= _('Logged in as %s') % user.identifier %></h2>
4 4 <ul>
5 5 <li><%= _('User since %s/%s') % [user.created_at.month, user.created_at.year] %></li>
6   - <li><%= link_to _('Homepage'), user.public_profile_url %></li>
  6 + <li><%= link_to _('Homepage'), url_for(user.public_profile_url) %></li>
7 7 </ul>
8 8 <div class="user-actions">
9 9 <%= button(:'menu-logout', _('Logout'), :controller => 'account', :action => 'logout') %>
... ...
app/views/blocks/profile_list.html.erb
... ... @@ -10,8 +10,8 @@
10 10 <% if list.empty? %>
11 11 <div class='common-profile-list-block-none'><%= _('None') %></div>
12 12 <% else %>
13   - <ul><%= list %></ul>
  13 + <ul><%= list.html_safe %></ul>
14 14 <% end %>
15 15 </div>
16   -
  16 +
17 17 <br style='clear:both'/>
... ...
app/views/box_organizer/_article_block.html.erb
... ... @@ -9,7 +9,8 @@
9 9 first_text = articles[articles.find_index{|a| a.kind_of? TextArticle}||-1]
10 10 selected = @block.article || first_text
11 11 %>
12   - <%= select_tag(
  12 + <%=
  13 + select_tag(
13 14 'block[article_id]',
14 15 options_for_select_with_title(articles.map {|item| [item.path, item.id]}, selected.id),
15 16 :onchange => 'this.changedTo(this.value)'
... ...
app/views/catalog/index.html.erb
... ... @@ -35,7 +35,7 @@
35 35 <% else %>
36 36 <div class="no-image"><%= _('No image') %></div>
37 37 <% end %>
38   - <div class="catalog-item-extras"><%= extra_content.join("\n") %></div>
  38 + <div class="catalog-item-extras"><%= safe_join(extra_content, "\n") %></div>
39 39 </li>
40 40  
41 41 <li class="product-link"><%= link_to_product product %></li>
... ...
app/views/cms/_blog.html.erb
... ... @@ -35,7 +35,7 @@
35 35 <div id="article-formitem">
36 36 <%= labelled_form_field( _('Address'),
37 37 content_tag('code',
38   - url_for(@article.url).gsub(/#{@article.slug}$/, '') +
  38 + url_for(@article.url).gsub(/#{@article.slug}$/, '').html_safe +
39 39 text_field(:article, :slug, :onchange => "warn_value_change()", :size => 25)
40 40 ) +
41 41 content_tag('div',
... ...
app/views/cms/_textile_quick_reference.html.erb
... ... @@ -14,7 +14,7 @@
14 14 <p><%= _('Numbered lists:') %></p>
15 15 <pre># <%= _('first item') %>
16 16 # <%= _('second item') %></pre>
17   - <p><%= h(_('For code, use HTML tags <pre> and <code>, and indent the code inside them:')) %>
  17 + <p><%= h(_('For code, use HTML tags <pre> and <code>, and indent the code inside them:').html_safe) %>
18 18 </p>
19 19 <pre>
20 20 &lt;pre&gt;
... ... @@ -23,7 +23,7 @@
23 23 &lt;/code&gt;
24 24 &lt;/pre&gt;
25 25 </pre>
26   - <p><%= _('See also a more complete <a href="%s">Textile Reference</a>.') % 'http://redcloth.org/hobix.com/textile/' %></p>
  26 + <p><%= _('See also a more complete <a href="%s">Textile Reference</a>.').html_safe % 'http://redcloth.org/hobix.com/textile/' %></p>
27 27 </div>
28 28 </div>
29 29  
... ...
app/views/cms/edit.html.erb
... ... @@ -39,7 +39,7 @@
39 39  
40 40 <script>
41 41 jQuery('#article_tag_list').inputosaurus({
42   - autoCompleteSource: <%= "'/myprofile/#{profile.identifier}/cms/search_tags'," %>
  42 + autoCompleteSource: <%= "'/myprofile/#{profile.identifier}/cms/search_tags',".html_safe %>
43 43 activateFinalResult : true
44 44 })
45 45 </script>
... ...
app/views/cms/select_article_type.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <ul class="article-types">
6 6 <% for type in @article_types %>
7 7 <% action = type[:class].name == 'UploadedFile' ? {:action => 'upload_files'} : {:action => 'new', :type => type[:class].name} %>
8   - <%= content_tag('a', :href => url_for(action.merge(:parent_id => @parent_id, :back_to => @back_to))) do %>
  8 + <%= content_tag('a', :href => url_for(action.merge(:parent_id => @parent_id, :back_to => @back_to)).html_safe) do %>
9 9 <li class="<%= icon_for_new_article(type[:class]) %>" onmouseover="javascript: jQuery(this).addClass('mouseover')" onmouseout="jQuery(this).removeClass('mouseover')">
10 10 <strong><%= type[:short_description] %></strong>
11 11 <div class='description'><%= type[:description] %></div>
... ...
app/views/cms/upload_files.html.erb
... ... @@ -17,11 +17,11 @@
17 17 <h3><%= _("Select the files you want to upload (max size %s):") % UploadedFile.max_size.to_humanreadable %></h3>
18 18 <h4><%= _('Documents, Images, Videos, Audio') %></h4>
19 19  
20   -<h5><%= _('Uploading files to %s') % content_tag('code', @target) %></h5>
  20 +<h5><%= (_('Uploading files to %s') % content_tag('code', @target)).html_safe%></h5>
21 21  
22 22 <%= form_for('uploaded_file', :url => { :action => 'upload_files' }, :html => {:multipart => true}) do |f| %>
23 23  
24   - <%= @plugins.dispatch(:upload_files_extra_fields, params[:parent_id]).collect { |content| instance_exec(&content) }.join("") %>
  24 + <%= safe_join(@plugins.dispatch(:upload_files_extra_fields, params[:parent_id]).collect { |content| instance_exec(&content) }, "") %>
25 25  
26 26 <%= render :partial => 'upload_file_form', :locals => { :size => '45'} %>
27 27  
... ...