Compare View

switch
from
...
to
 
Commits (128)
Showing 341 changed files   Show diff stats

Too many changes.

To preserve performance only 100 of 341 files displayed.

app/api/app.rb
... ... @@ -54,6 +54,7 @@ module Api
54 54 mount V1::Blocks
55 55 mount V1::Profiles
56 56 mount V1::Activities
  57 + mount V1::Roles
57 58  
58 59 # hook point which allow plugins to add Grape::API extensions to Api::App
59 60 #finds for plugins which has api mount points classes defined (the class should extends Grape::API)
... ...
app/api/entities.rb
... ... @@ -111,6 +111,10 @@ module Api
111 111 hash[value.custom_field.name]=value.value
112 112 end
113 113  
  114 + profile.public_fields.each do |field|
  115 + hash[field] = profile.send(field.to_sym)
  116 + end
  117 +
114 118 private_values = profile.custom_field_values - profile.public_values
115 119 private_values.each do |value|
116 120 if Entities.can_display_profile_field?(profile,options)
... ... @@ -124,6 +128,7 @@ module Api
124 128 expose :type
125 129 expose :custom_header
126 130 expose :custom_footer
  131 + expose :layout_template
127 132 expose :permissions do |profile, options|
128 133 Entities.permissions_for_entity(profile, options[:current_person],
129 134 :allow_post_content?, :allow_edit?, :allow_destroy?)
... ... @@ -258,12 +263,28 @@ module Api
258 263 root 'tasks', 'task'
259 264 expose :id
260 265 expose :type
  266 + expose :requestor, using: Profile
  267 + expose :status
  268 + expose :created_at
  269 + expose :data
  270 + expose :accept_details
  271 + expose :reject_details
  272 + expose :accept_disabled?, as: :accept_disabled
  273 + expose :reject_disabled?, as: :reject_disabled
  274 + expose :target do |task, options|
  275 + type_map = {Profile => ::Profile, Environment => ::Environment}.find {|h| task.target.kind_of?(h.last)}
  276 + type_map.first.represent(task.target) unless type_map.nil?
  277 + end
261 278 end
262 279  
263 280 class Environment < Entity
264 281 expose :name
265 282 expose :id
266 283 expose :description
  284 + expose :layout_template
  285 + expose :signup_intro
  286 + expose :terms_of_use
  287 + expose :top_url, as: :host
267 288 expose :settings, if: lambda { |instance, options| options[:is_admin] }
268 289 end
269 290  
... ... @@ -281,5 +302,12 @@ module Api
281 302 type_map.first.represent(activity.target) unless type_map.nil?
282 303 end
283 304 end
  305 +
  306 + class Role < Entity
  307 + root 'roles', 'role'
  308 + expose :id
  309 + expose :name
  310 + expose :key
  311 + end
284 312 end
285 313 end
... ...
app/api/helpers.rb
... ... @@ -4,7 +4,7 @@ require &#39;tempfile&#39;
4 4 module Api
5 5 module Helpers
6 6 PRIVATE_TOKEN_PARAM = :private_token
7   - DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived]
  7 + ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived, :status]
8 8  
9 9 include SanitizeParams
10 10 include Noosfero::Plugin::HotSpot
... ... @@ -124,8 +124,8 @@ module Api
124 124 present_partial article, with: Entities::Article, params: params, current_person: current_person
125 125 end
126 126  
127   - def present_articles_for_asset(asset, method = 'articles')
128   - articles = find_articles(asset, method)
  127 + def present_articles_for_asset(asset, method_or_relation = 'articles')
  128 + articles = find_articles(asset, method_or_relation)
129 129 present_articles(articles)
130 130 end
131 131  
... ... @@ -133,8 +133,8 @@ module Api
133 133 present_partial paginate(articles), :with => Entities::Article, :params => params, current_person: current_person
134 134 end
135 135  
136   - def find_articles(asset, method = 'articles')
137   - articles = select_filtered_collection_of(asset, method, params)
  136 + def find_articles(asset, method_or_relation = 'articles')
  137 + articles = select_filtered_collection_of(asset, method_or_relation, params)
138 138 if current_person.present?
139 139 articles = articles.display_filter(current_person, nil)
140 140 else
... ... @@ -143,14 +143,17 @@ module Api
143 143 articles
144 144 end
145 145  
146   - def find_task(asset, id)
147   - task = asset.tasks.find(id)
  146 + def find_task(asset, method_or_relation, id)
  147 + task = is_a_relation?(method_or_relation) ? method_or_relation : asset.send(method_or_relation)
  148 + task = task.find_by_id(id)
  149 + not_found! if task.blank?
148 150 current_person.has_permission?(task.permission, asset) ? task : forbidden!
149 151 end
150 152  
151 153 def post_task(asset, params)
152 154 klass_type= params[:content_type].nil? ? 'Task' : params[:content_type]
153 155 return forbidden! unless klass_type.constantize <= Task
  156 + return forbidden! if !current_person.has_permission?(:perform_task, asset)
154 157  
155 158 task = klass_type.constantize.new(params[:task])
156 159 task.requestor_id = current_person.id
... ... @@ -163,15 +166,24 @@ module Api
163 166 present_partial task, :with => Entities::Task
164 167 end
165 168  
166   - def present_task(asset)
167   - task = find_task(asset, params[:id])
  169 + def find_tasks(asset, method_or_relation = 'tasks')
  170 + return forbidden! if !current_person.has_permission?(:perform_task, asset)
  171 + tasks = select_filtered_collection_of(asset, method_or_relation, params)
  172 + tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)}
  173 + tasks
  174 + end
  175 +
  176 + def present_task(asset, method_or_relation = 'tasks')
  177 + task = find_task(asset, method_or_relation, params[:id])
168 178 present_partial task, :with => Entities::Task
169 179 end
170 180  
171   - def present_tasks(asset)
172   - tasks = select_filtered_collection_of(asset, 'tasks', params)
173   - tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)}
174   - return forbidden! if tasks.empty? && !current_person.has_permission?(:perform_task, asset)
  181 + def present_tasks_for_asset(asset, method_or_relation = 'tasks')
  182 + tasks = find_tasks(asset, method_or_relation)
  183 + present_tasks(tasks)
  184 + end
  185 +
  186 + def present_tasks(tasks)
175 187 present_partial tasks, :with => Entities::Task
176 188 end
177 189  
... ... @@ -180,7 +192,6 @@ module Api
180 192 conditions = {}
181 193 from_date = DateTime.parse(parsed_params.delete(:from)) if parsed_params[:from]
182 194 until_date = DateTime.parse(parsed_params.delete(:until)) if parsed_params[:until]
183   -
184 195 conditions[:type] = parse_content_type(parsed_params.delete(:content_type)) unless parsed_params[:content_type].nil?
185 196  
186 197 conditions[:created_at] = period(from_date, until_date) if from_date || until_date
... ... @@ -190,7 +201,7 @@ module Api
190 201 end
191 202  
192 203 # changing make_order_with_parameters to avoid sql injection
193   - def make_order_with_parameters(object, method, params)
  204 + def make_order_with_parameters(object, method_or_relation, params)
194 205 order = "created_at DESC"
195 206 unless params[:order].blank?
196 207 if params[:order].include? '\'' or params[:order].include? '"'
... ... @@ -199,9 +210,9 @@ module Api
199 210 order = 'RANDOM()'
200 211 else
201 212 field_name, direction = params[:order].split(' ')
202   - assoc = object.class.reflect_on_association(method.to_sym)
203   - if !field_name.blank? and assoc
204   - if assoc.klass.attribute_names.include? field_name
  213 + assoc_class = extract_associated_classname(method_or_relation)
  214 + if !field_name.blank? and assoc_class
  215 + if assoc_class.attribute_names.include? field_name
205 216 if direction.present? and ['ASC','DESC'].include? direction.upcase
206 217 order = "#{field_name} #{direction.upcase}"
207 218 end
... ... @@ -212,12 +223,14 @@ module Api
212 223 return order
213 224 end
214 225  
215   - def make_timestamp_with_parameters_and_method(params, method)
  226 + def make_timestamp_with_parameters_and_method(params, method_or_relation)
216 227 timestamp = nil
217 228 if params[:timestamp]
218 229 datetime = DateTime.parse(params[:timestamp])
219   - table_name = method.to_s.singularize.camelize.constantize.table_name
220   - timestamp = "#{table_name}.updated_at >= '#{datetime}'"
  230 + table_name = extract_associated_tablename(method_or_relation)
  231 + assoc_class = extract_associated_classname(method_or_relation)
  232 + date_atrr = assoc_class.attribute_names.include?('updated_at') ? 'updated_at' : 'created_at'
  233 + timestamp = "#{table_name}.#{date_atrr} >= '#{datetime}'"
221 234 end
222 235  
223 236 timestamp
... ... @@ -242,12 +255,12 @@ module Api
242 255 end
243 256 end
244 257  
245   - def select_filtered_collection_of(object, method, params)
  258 + def select_filtered_collection_of(object, method_or_relation, params)
246 259 conditions = make_conditions_with_parameter(params)
247   - order = make_order_with_parameters(object,method,params)
248   - timestamp = make_timestamp_with_parameters_and_method(params, method)
  260 + order = make_order_with_parameters(object,method_or_relation,params)
  261 + timestamp = make_timestamp_with_parameters_and_method(params, method_or_relation)
249 262  
250   - objects = object.send(method)
  263 + objects = is_a_relation?(method_or_relation) ? method_or_relation : object.send(method_or_relation)
251 264 objects = by_reference(objects, params)
252 265 objects = by_categories(objects, params)
253 266  
... ... @@ -302,12 +315,12 @@ module Api
302 315 end
303 316  
304 317 def cant_be_saved_request!(attribute)
305   - message = _("(Invalid request) %s can't be saved") % attribute
  318 + message = _("(Invalid request) %s can't be saved").html_safe % attribute
306 319 render_api_error!(message, 400)
307 320 end
308 321  
309 322 def bad_request!(attribute)
310   - message = _("(Invalid request) %s not given") % attribute
  323 + message = _("(Invalid request) %s not given").html_safe % attribute
311 324 render_api_error!(message, 400)
312 325 end
313 326  
... ... @@ -393,10 +406,27 @@ module Api
393 406 end
394 407 private
395 408  
  409 + def extract_associated_tablename(method_or_relation)
  410 + extract_associated_classname(method_or_relation).table_name
  411 + end
  412 +
  413 + def extract_associated_classname(method_or_relation)
  414 + if is_a_relation?(method_or_relation)
  415 + method_or_relation.blank? ? '' : method_or_relation.first.class
  416 + else
  417 + method_or_relation.to_s.singularize.camelize.constantize
  418 + end
  419 + end
  420 +
  421 + def is_a_relation?(method_or_relation)
  422 + method_or_relation.kind_of?(ActiveRecord::Relation)
  423 + end
  424 +
  425 +
396 426 def parser_params(params)
397 427 parsed_params = {}
398 428 params.map do |k,v|
399   - parsed_params[k.to_sym] = v if DEFAULT_ALLOWED_PARAMETERS.include?(k.to_sym)
  429 + parsed_params[k.to_sym] = v if ALLOWED_PARAMETERS.include?(k.to_sym)
400 430 end
401 431 parsed_params
402 432 end
... ...
app/api/v1/people.rb
... ... @@ -119,6 +119,20 @@ module Api
119 119 members = select_filtered_collection_of(profile, 'members', params)
120 120 present members, :with => Entities::Person, :current_person => current_person
121 121 end
  122 +
  123 + post do
  124 + authenticate!
  125 + profile = environment.profiles.find_by id: params[:profile_id]
  126 + profile.add_member(current_person) rescue forbidden!
  127 + {pending: !current_person.is_member_of?(profile)}
  128 + end
  129 +
  130 + delete do
  131 + authenticate!
  132 + profile = environment.profiles.find_by id: params[:profile_id]
  133 + profile.remove_member(current_person)
  134 + present current_person, :with => Entities::Person, :current_person => current_person
  135 + end
122 136 end
123 137 end
124 138 end
... ...
app/api/v1/roles.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +module Api
  2 + module V1
  3 + class Roles < Grape::API
  4 + before { authenticate! }
  5 +
  6 + MAX_PER_PAGE = 50
  7 +
  8 + resource :profiles do
  9 + segment "/:profile_id" do
  10 + resource :roles do
  11 +
  12 + paginate max_per_page: MAX_PER_PAGE
  13 + get do
  14 + profile = environment.profiles.find(params[:profile_id])
  15 + return forbidden! unless profile.kind_of?(Organization)
  16 + roles = Profile::Roles.organization_roles(profile.environment.id, profile.id)
  17 + present_partial paginate(roles), with: Entities::Role
  18 + end
  19 +
  20 + end
  21 + end
  22 + end
  23 + end
  24 + end
  25 +end
... ...
app/api/v1/tasks.rb
1 1 module Api
2 2 module V1
3 3 class Tasks < Grape::API
4   -# before { authenticate! }
  4 + before { authenticate! }
5 5  
6   -# ARTICLE_TYPES = Article.descendants.map{|a| a.to_s}
  6 + MAX_PER_PAGE = 50
7 7  
8 8 resource :tasks do
9 9  
10   - # Collect tasks
  10 + paginate max_per_page: MAX_PER_PAGE
  11 + # Collect all tasks that current person has permission
11 12 #
12 13 # Parameters:
13 14 # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created
... ... @@ -17,15 +18,27 @@ module Api
17 18 # Example Request:
18 19 # GET host/api/v1/tasks?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317
19 20 get do
20   - tasks = select_filtered_collection_of(environment, 'tasks', params)
21   - tasks = tasks.select {|t| current_person.has_permission?(t.permission, environment)}
22   - present_partial tasks, :with => Entities::Task
  21 + tasks = Task.to(current_person)
  22 + present_tasks_for_asset(current_person, tasks)
23 23 end
24 24  
25 25 desc "Return the task id"
26 26 get ':id' do
27   - task = find_task(environment, params[:id])
28   - present_partial task, :with => Entities::Task
  27 + present_task(current_person, Task.to(current_person))
  28 + end
  29 +
  30 + %w[finish cancel].each do |action|
  31 + desc "#{action.capitalize} a task"
  32 + put ":id/#{action}" do
  33 + task = find_task(current_person, Task.to(current_person), params[:id])
  34 + begin
  35 + task.update(params[:task])
  36 + task.send(action, current_person) if (task.status == Task::Status::ACTIVE)
  37 + present_partial task, :with => Entities::Task
  38 + rescue Exception => ex
  39 + render_api_error!(ex.message, 500)
  40 + end
  41 + end
29 42 end
30 43 end
31 44  
... ... @@ -36,7 +49,8 @@ module Api
36 49 resource :tasks do
37 50 get do
38 51 profile = environment.send(kind.pluralize).find(params["#{kind}_id"])
39   - present_tasks(profile)
  52 + tasks = Task.to(profile)
  53 + present_tasks_for_asset(profile, tasks)
40 54 end
41 55  
42 56 get ':id' do
... ...
app/controllers/admin/categories_controller.rb
... ... @@ -44,7 +44,7 @@ class CategoriesController &lt; AdminController
44 44 if request.post?
45 45 @category.update!(params[:category])
46 46 @saved = true
47   - session[:notice] = _("Category %s saved." % @category.name)
  47 + session[:notice] = _("Category %s saved." % @category.name).html_safe
48 48 redirect_to :action => 'index'
49 49 end
50 50 rescue Exception => e
... ...
app/controllers/application_controller.rb
... ... @@ -14,6 +14,20 @@ class ApplicationController &lt; ActionController::Base
14 14 before_filter :redirect_to_current_user
15 15  
16 16 before_filter :set_session_theme
  17 +
  18 + # FIXME: only include necessary methods
  19 + include ApplicationHelper
  20 +
  21 + # concerns
  22 + include PermissionCheck
  23 + include CustomDesign
  24 + include NeedsProfile
  25 +
  26 + # implementations
  27 + include FindByContents
  28 + include Noosfero::Plugin::HotSpot
  29 + include SearchTermHelper
  30 +
17 31 def set_session_theme
18 32 if params[:theme]
19 33 session[:theme] = environment.theme_ids.include?(params[:theme]) ? params[:theme] : nil
... ... @@ -48,7 +62,6 @@ class ApplicationController &lt; ActionController::Base
48 62 end
49 63 end
50 64  
51   - include ApplicationHelper
52 65 layout :get_layout
53 66 def get_layout
54 67 return false if request.format == :js or request.xhr?
... ... @@ -74,9 +87,6 @@ class ApplicationController &lt; ActionController::Base
74 87 helper :document
75 88 helper :language
76 89  
77   - include DesignHelper
78   - include PermissionCheck
79   -
80 90 before_filter :set_locale
81 91 def set_locale
82 92 FastGettext.available_locales = environment.available_locales
... ... @@ -89,8 +99,6 @@ class ApplicationController &lt; ActionController::Base
89 99 end
90 100 end
91 101  
92   - include NeedsProfile
93   -
94 102 attr_reader :environment
95 103  
96 104 # declares that the given <tt>actions</tt> cannot be accessed by other HTTP
... ... @@ -107,6 +115,10 @@ class ApplicationController &lt; ActionController::Base
107 115  
108 116 protected
109 117  
  118 + def accept_only_post
  119 + return render_not_found if !request.post?
  120 + end
  121 +
110 122 def verified_request?
111 123 super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
112 124 end
... ... @@ -151,8 +163,6 @@ class ApplicationController &lt; ActionController::Base
151 163 end
152 164 end
153 165  
154   - include Noosfero::Plugin::HotSpot
155   -
156 166 # FIXME this filter just loads @plugins to children controllers and helpers
157 167 def init_noosfero_plugins
158 168 plugins
... ... @@ -184,9 +194,6 @@ class ApplicationController &lt; ActionController::Base
184 194 end
185 195 end
186 196  
187   - include SearchTermHelper
188   - include FindByContents
189   -
190 197 def find_suggestions(query, context, asset, options={})
191 198 plugins.dispatch_first(:find_suggestions, query, context, asset, options)
192 199 end
... ...
app/controllers/box_organizer_controller.rb
... ... @@ -109,7 +109,7 @@ class BoxOrganizerController &lt; ApplicationController
109 109 def show_block_type_info
110 110 type = params[:type]
111 111 if type.blank? || !available_blocks.map(&:name).include?(type)
112   - raise ArgumentError.new("Type %s is not allowed. Go away." % type)
  112 + raise ArgumentError.new("Type %s is not allowed. Go away.".html_safe % type)
113 113 end
114 114 @block = type.constantize.new
115 115 @block.box = Box.new(:owner => boxes_holder)
... ... @@ -122,7 +122,7 @@ class BoxOrganizerController &lt; ApplicationController
122 122  
123 123 def new_block(type, box)
124 124 if !available_blocks.map(&:name).include?(type)
125   - raise ArgumentError.new("Type %s is not allowed. Go away." % type)
  125 + raise ArgumentError.new("Type %s is not allowed. Go away.".html_safe % type)
126 126 end
127 127 block = type.constantize.new
128 128 box.blocks << block
... ...
app/controllers/concerns/authenticated_system.rb 0 → 100644
... ... @@ -0,0 +1,169 @@
  1 +module AuthenticatedSystem
  2 +
  3 + protected
  4 +
  5 + extend ActiveSupport::Concern
  6 +
  7 + included do
  8 + if self < ActionController::Base
  9 + around_filter :user_set_current
  10 + before_filter :override_user
  11 + before_filter :login_from_cookie
  12 + end
  13 +
  14 + # Inclusion hook to make #current_user and #logged_in?
  15 + # available as ActionView helper methods.
  16 + helper_method :current_user, :logged_in?
  17 + end
  18 +
  19 + # Returns true or false if the user is logged in.
  20 + # Preloads @current_user with the user model if they're logged in.
  21 + def logged_in?
  22 + current_user != nil
  23 + end
  24 +
  25 + # Accesses the current user from the session.
  26 + def current_user user_id = session[:user]
  27 + @current_user ||= begin
  28 + user = User.find_by id: user_id if user_id
  29 + user.session = session if user
  30 + User.current = user
  31 + user
  32 + end
  33 + end
  34 +
  35 + # Store the given user in the session.
  36 + def current_user=(new_user)
  37 + if new_user.nil?
  38 + session.delete(:user)
  39 + else
  40 + session[:user] = new_user.id
  41 + new_user.session = session
  42 + new_user.register_login
  43 + end
  44 + @current_user = User.current = new_user
  45 + end
  46 +
  47 + # See impl. from http://stackoverflow.com/a/2513456/670229
  48 + def user_set_current
  49 + User.current = current_user
  50 + yield
  51 + ensure
  52 + # to address the thread variable leak issues in Puma/Thin webserver
  53 + User.current = nil
  54 + end
  55 +
  56 + # Check if the user is authorized.
  57 + #
  58 + # Override this method in your controllers if you want to restrict access
  59 + # to only a few actions or if you want to check if the user
  60 + # has the correct rights.
  61 + #
  62 + # Example:
  63 + #
  64 + # # only allow nonbobs
  65 + # def authorize?
  66 + # current_user.login != "bob"
  67 + # end
  68 + def authorized?
  69 + true
  70 + end
  71 +
  72 + # Filter method to enforce a login requirement.
  73 + #
  74 + # To require logins for all actions, use this in your controllers:
  75 + #
  76 + # before_filter :login_required
  77 + #
  78 + # To require logins for specific actions, use this in your controllers:
  79 + #
  80 + # before_filter :login_required, :only => [ :edit, :update ]
  81 + #
  82 + # To skip this in a subclassed controller:
  83 + #
  84 + # skip_before_filter :login_required
  85 + #
  86 + def login_required
  87 + username, passwd = get_auth_data
  88 + if username && passwd
  89 + self.current_user ||= User.authenticate(username, passwd) || nil
  90 + end
  91 + if logged_in? && authorized?
  92 + true
  93 + else
  94 + if params[:require_login_popup]
  95 + render :json => { :require_login_popup => true }
  96 + else
  97 + access_denied
  98 + end
  99 + end
  100 + end
  101 +
  102 + # Redirect as appropriate when an access request fails.
  103 + #
  104 + # The default action is to redirect to the login screen.
  105 + #
  106 + # Override this method in your controllers if you want to have special
  107 + # behavior in case the user is not authorized
  108 + # to access the requested action. For example, a popup window might
  109 + # simply close itself.
  110 + def access_denied
  111 + respond_to do |accepts|
  112 + accepts.html do
  113 + if request.xhr?
  114 + render :text => _('Access denied'), :status => 401
  115 + else
  116 + store_location
  117 + redirect_to :controller => '/account', :action => 'login'
  118 + end
  119 + end
  120 + accepts.xml do
  121 + headers["Status"] = "Unauthorized"
  122 + headers["WWW-Authenticate"] = %(Basic realm="Web Password")
  123 + render :text => "Could't authenticate you", :status => '401 Unauthorized'
  124 + end
  125 + end
  126 + false
  127 + end
  128 +
  129 + # Store the URI of the current request in the session.
  130 + #
  131 + # We can return to this location by calling #redirect_back_or_default.
  132 + def store_location(location = request.url)
  133 + session[:return_to] = location
  134 + end
  135 +
  136 + # Redirect to the URI stored by the most recent store_location call or
  137 + # to the passed default.
  138 + def redirect_back_or_default(default)
  139 + if session[:return_to]
  140 + redirect_to(session.delete(:return_to))
  141 + else
  142 + redirect_to(default)
  143 + end
  144 + end
  145 +
  146 + def override_user
  147 + return if params[:override_user].blank?
  148 + return unless logged_in? and user.is_admin? environment
  149 + @current_user = nil
  150 + current_user params[:override_user]
  151 + end
  152 +
  153 + # When called with before_filter :login_from_cookie will check for an :auth_token
  154 + # cookie and log the user back in if apropriate
  155 + def login_from_cookie
  156 + return if cookies[:auth_token].blank? or logged_in?
  157 + user = User.where(remember_token: cookies[:auth_token]).first
  158 + self.current_user = user if user and user.remember_token?
  159 + end
  160 +
  161 + private
  162 + @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization)
  163 + # gets BASIC auth info
  164 + def get_auth_data
  165 + auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) }
  166 + auth_data = request.env[auth_key].to_s.split unless auth_key.blank?
  167 + return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil]
  168 + end
  169 +end
... ...
app/controllers/concerns/custom_design.rb 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +module CustomDesign
  2 +
  3 + extend ActiveSupport::Concern
  4 +
  5 + included do
  6 + extend ClassMethods
  7 + include InstanceMethods
  8 + before_filter :load_custom_design if self.respond_to? :before_filter
  9 + end
  10 +
  11 + module ClassMethods
  12 +
  13 + def no_design_blocks
  14 + @no_design_blocks = true
  15 + end
  16 +
  17 + def use_custom_design options = {}
  18 + @custom_design = options
  19 + end
  20 +
  21 + def custom_design
  22 + @custom_design ||= {}
  23 + end
  24 +
  25 + def uses_design_blocks?
  26 + !@no_design_blocks
  27 + end
  28 +
  29 + end
  30 +
  31 + module InstanceMethods
  32 +
  33 + protected
  34 +
  35 + def uses_design_blocks?
  36 + !@no_design_blocks && self.class.uses_design_blocks?
  37 + end
  38 +
  39 + def load_custom_design
  40 + # see also: LayoutHelper#body_classes
  41 + @layout_template = self.class.custom_design[:layout_template]
  42 + end
  43 +
  44 + def custom_design
  45 + @custom_design || self.class.custom_design
  46 + end
  47 +
  48 + end
  49 +
  50 +end
... ...
app/controllers/concerns/needs_profile.rb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +module NeedsProfile
  2 +
  3 + module ClassMethods
  4 + def needs_profile
  5 + before_filter :load_profile
  6 + end
  7 + end
  8 +
  9 + def self.included(including)
  10 + including.send(:extend, NeedsProfile::ClassMethods)
  11 + end
  12 +
  13 + def boxes_holder
  14 + profile || environment # prefers profile, but defaults to environment
  15 + end
  16 +
  17 + def profile
  18 + @profile
  19 + end
  20 +
  21 + protected
  22 +
  23 + def load_profile
  24 + if params[:profile]
  25 + params[:profile].downcase!
  26 + @profile ||= environment.profiles.where(identifier: params[:profile]).first
  27 + end
  28 +
  29 + if @profile
  30 + profile_hostname = @profile.hostname
  31 + if profile_hostname && profile_hostname != request.host
  32 + params.delete(:profile)
  33 + redirect_to(Noosfero.url_options.merge(params).merge(:host => profile_hostname))
  34 + end
  35 + else
  36 + render_not_found
  37 + end
  38 + end
  39 +
  40 +end
... ...
app/controllers/my_profile/circles_controller.rb 0 → 100644
... ... @@ -0,0 +1,58 @@
  1 +class CirclesController < MyProfileController
  2 +
  3 + before_action :accept_only_post, :only => [:create, :update, :destroy]
  4 +
  5 + def index
  6 + @circles = profile.circles
  7 + end
  8 +
  9 + def new
  10 + @circle = Circle.new
  11 + end
  12 +
  13 + def create
  14 + @circle = Circle.new(params[:circle].merge({ :person => profile }))
  15 + if @circle.save
  16 + redirect_to :action => 'index'
  17 + else
  18 + render :action => 'new'
  19 + end
  20 + end
  21 +
  22 + def xhr_create
  23 + if request.xhr?
  24 + circle = Circle.new(params[:circle].merge({:person => profile }))
  25 + if circle.save
  26 + render :partial => "circle_checkbox", :locals => { :circle => circle },
  27 + :status => 201
  28 + else
  29 + render :text => _('The circle could not be saved'), :status => 400
  30 + end
  31 + else
  32 + render_not_found
  33 + end
  34 + end
  35 +
  36 + def edit
  37 + @circle = Circle.find_by_id(params[:id])
  38 + render_not_found if @circle.nil?
  39 + end
  40 +
  41 + def update
  42 + @circle = Circle.find_by_id(params[:id])
  43 + return render_not_found if @circle.nil?
  44 +
  45 + if @circle.update(params[:circle])
  46 + redirect_to :action => 'index'
  47 + else
  48 + render :action => 'edit'
  49 + end
  50 + end
  51 +
  52 + def destroy
  53 + @circle = Circle.find_by_id(params[:id])
  54 + return render_not_found if @circle.nil?
  55 + @circle.destroy
  56 + redirect_to :action => 'index'
  57 + end
  58 +end
... ...
app/controllers/my_profile/followers_controller.rb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +class FollowersController < MyProfileController
  2 +
  3 + before_action :only_for_person, :only => :index
  4 + before_action :accept_only_post, :only => [:update_category]
  5 +
  6 + def index
  7 + @followed_people = profile.followed_profiles.order(:type)
  8 + @profile_types = {_('All profiles') => nil}.merge(Circle.profile_types).to_a
  9 +
  10 + if params['filter'].present?
  11 + @followed_people = @followed_people.where(:type => params['filter'])
  12 + @active_filter = params['filter']
  13 + end
  14 +
  15 + @followed_people = @followed_people.paginate(:per_page => 15, :page => params[:npage])
  16 + end
  17 +
  18 + def set_category_modal
  19 + followed_profile = Profile.find(params[:followed_profile_id])
  20 + circles = Circle.where(:person => profile, :profile_type => followed_profile.class.name)
  21 + render :partial => 'followers/edit_circles_modal', :locals => { :circles => circles, :followed_profile => followed_profile }
  22 + end
  23 +
  24 + def update_category
  25 + followed_profile = Profile.find_by(:id => params["followed_profile_id"])
  26 +
  27 + selected_circles = params[:circles].map{ |circle_name, circle_id| Circle.find_by(:id => circle_id) }.select{ |c| c.present? }
  28 +
  29 + if followed_profile
  30 + profile.update_profile_circles(followed_profile, selected_circles)
  31 + render :text => _("Circles of %s updated successfully") % followed_profile.name, :status => 200
  32 + else
  33 + render :text => _("Error: No profile to follow."), :status => 400
  34 + end
  35 + end
  36 +
  37 + protected
  38 +
  39 + def only_for_person
  40 + render_not_found unless profile.person?
  41 + end
  42 +
  43 +end
... ...
app/controllers/my_profile/tasks_controller.rb
... ... @@ -14,7 +14,7 @@ class TasksController &lt; MyProfileController
14 14 @filter_text = params[:filter_text].presence
15 15 @filter_responsible = params[:filter_responsible]
16 16 @task_types = Task.pending_types_for(profile)
17   - @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
  17 + @tasks = Task.pending_all_by_filter(profile, @filter_type, @filter_text).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
18 18 @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present?
19 19 @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
20 20 @failed = params ? params[:failed] : {}
... ... @@ -101,7 +101,7 @@ class TasksController &lt; MyProfileController
101 101 def search_tasks
102 102 filter_type = params[:filter_type].presence
103 103 filter_text = params[:filter_text].presence
104   - result = Task.pending_all(profile,filter_type, filter_text)
  104 + result = Task.pending_all_by_filter(profile,filter_type, filter_text)
105 105  
106 106 render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} }
107 107 end
... ...
app/controllers/public/account_controller.rb
... ... @@ -205,7 +205,7 @@ class AccountController &lt; ApplicationController
205 205 if params[:value].blank?
206 206 @change_password.errors[:base] << _('Can not recover user password with blank value.')
207 207 else
208   - @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]]
  208 + @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".').html_safe % [fields_label, params[:value]]
209 209 end
210 210 rescue ActiveRecord::RecordInvalid
211 211 @change_password.errors[:base] << _('Could not perform password recovery for the user.')
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -128,9 +128,9 @@ class ContentViewerController &lt; ApplicationController
128 128 end
129 129  
130 130 unless @page.display_to?(user)
131   - if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank?
  131 + if !profile.visible? || profile.secret? || (user && profile.in_social_circle?(user)) || user.blank?
132 132 render_access_denied
133   - else #!profile.public?
  133 + else
134 134 private_profile_partial_parameters
135 135 render :template => 'profile/_private_profile', :status => 403, :formats => [:html]
136 136 end
... ...
app/controllers/public/profile_controller.rb
... ... @@ -3,7 +3,9 @@ class ProfileController &lt; PublicController
3 3 needs_profile
4 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
6   - before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
  6 + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail, :follow, :unfollow]
  7 + before_filter :allow_followers?, :only => [:follow, :unfollow]
  8 + before_filter :accept_only_post, :only => [:follow, :unfollow]
7 9  
8 10 helper TagsHelper
9 11 helper ActionTrackerHelper
... ... @@ -42,8 +44,8 @@ class ProfileController &lt; PublicController
42 44 feed_writer = FeedWriter.new
43 45 data = feed_writer.write(
44 46 tagged,
45   - :title => _("%s's contents tagged with \"%s\"") % [profile.name, @tag],
46   - :description => _("%s's contents tagged with \"%s\"") % [profile.name, @tag],
  47 + :title => _("%s's contents tagged with \"%s\"").html_safe % [profile.name, @tag],
  48 + :description => _("%s's contents tagged with \"%s\"").html_safe % [profile.name, @tag],
47 49 :link => url_for(profile.url)
48 50 )
49 51 render :text => data, :content_type => "text/xml"
... ... @@ -65,6 +67,14 @@ class ProfileController &lt; PublicController
65 67 end
66 68 end
67 69  
  70 + def following
  71 + @followed_people = profile.followed_profiles.paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.followed_profiles.count)
  72 + end
  73 +
  74 + def followed
  75 + @followed_by = profile.followers.paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.followers.count)
  76 + end
  77 +
68 78 def members
69 79 if is_cache_expired?(profile.members_cache_key(params))
70 80 sort = (params[:sort] == 'desc') ? params[:sort] : 'asc'
... ... @@ -88,7 +98,7 @@ class ProfileController &lt; PublicController
88 98  
89 99 def join_modal
90 100 profile.add_member(user)
91   - session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name
  101 + session[:notice] = _('%s administrator still needs to accept you as member.').html_safe % profile.name
92 102 redirect_to :action => :index
93 103 end
94 104  
... ... @@ -98,12 +108,12 @@ class ProfileController &lt; PublicController
98 108  
99 109 profile.add_member(user)
100 110 if !profile.members.include?(user)
101   - render :text => {:message => _('%s administrator still needs to accept you as member.') % profile.name}.to_json
  111 + render :text => {:message => _('%s administrator still needs to accept you as member.').html_safe % profile.name}.to_json
102 112 else
103   - render :text => {:message => _('You just became a member of %s.') % profile.name}.to_json
  113 + render :text => {:message => _('You just became a member of %s.').html_safe % profile.name}.to_json
104 114 end
105 115 else
106   - render :text => {:message => _('You are already a member of %s.') % profile.name}.to_json
  116 + render :text => {:message => _('You are already a member of %s.').html_safe % profile.name}.to_json
107 117 end
108 118 end
109 119  
... ... @@ -125,7 +135,7 @@ class ProfileController &lt; PublicController
125 135 render :text => current_person.leave(profile, params[:reload])
126 136 end
127 137 else
128   - render :text => {:message => _('You are not a member of %s.') % profile.name}.to_json
  138 + render :text => {:message => _('You are not a member of %s.').html_safe % profile.name}.to_json
129 139 end
130 140 end
131 141  
... ... @@ -145,12 +155,41 @@ class ProfileController &lt; PublicController
145 155 # FIXME this shouldn't be in Person model?
146 156 if !user.memberships.include?(profile)
147 157 AddFriend.create!(:person => user, :friend => profile)
148   - render :text => _('%s still needs to accept being your friend.') % profile.name
  158 + render :text => _('%s still needs to accept being your friend.').html_safe % profile.name
149 159 else
150   - render :text => _('You are already a friend of %s.') % profile.name
  160 + render :text => _('You are already a friend of %s.').html_safe % profile.name
  161 + end
  162 + end
  163 +
  164 + def follow
  165 + if profile.followed_by?(current_person)
  166 + render :text => _("You are already following %s.") % profile.name, :status => 400
  167 + else
  168 + selected_circles = params[:circles].map{ |circle_name, circle_id| Circle.find_by(:id => circle_id) }.select{ |c| c.present? }
  169 + if selected_circles.present?
  170 + current_person.follow(profile, selected_circles)
  171 + render :text => _("You are now following %s") % profile.name, :status => 200
  172 + else
  173 + render :text => _("Select at least one circle to follow %s.") % profile.name, :status => 400
  174 + end
151 175 end
152 176 end
153 177  
  178 + def find_profile_circles
  179 + circles = Circle.where(:person => current_person, :profile_type => profile.class.name)
  180 + render :partial => 'blocks/profile_info_actions/circles', :locals => { :circles => circles, :profile_types => Circle.profile_types.to_a }
  181 + end
  182 +
  183 + def unfollow
  184 + follower = params[:follower_id].present? ? Person.find_by(id: params[:follower_id]) : current_person
  185 +
  186 + if follower && follower.follows?(profile)
  187 + follower.unfollow(profile)
  188 + end
  189 + redirect_url = params["redirect_to"] ? params["redirect_to"] : profile.url
  190 + redirect_to redirect_url
  191 + end
  192 +
154 193 def check_friendship
155 194 unless logged_in?
156 195 render :text => ''
... ... @@ -178,7 +217,7 @@ class ProfileController &lt; PublicController
178 217 def unblock
179 218 if current_user.person.is_admin?(profile.environment)
180 219 profile.unblock
181   - session[:notice] = _("You have unblocked %s successfully. ") % profile.name
  220 + session[:notice] = _("You have unblocked %s successfully. ").html_safe % profile.name
182 221 redirect_to :controller => 'profile', :action => 'index'
183 222 else
184 223 message = _('You are not allowed to unblock enterprises in this environment.')
... ... @@ -437,4 +476,8 @@ class ProfileController &lt; PublicController
437 476 [:image, :domains, :preferred_domain, :environment]
438 477 end
439 478  
  479 + def allow_followers?
  480 + render_not_found unless profile.allow_followers?
  481 + end
  482 +
440 483 end
... ...
app/helpers/action_tracker_helper.rb
... ... @@ -14,13 +14,23 @@ module ActionTrackerHelper
14 14 }
15 15 end
16 16  
  17 + def new_follower_description ta
  18 + n_('has 1 new follower:<br />%{name}', 'has %{num} new followers:<br />%{name}', ta.get_follower_name.size).html_safe % {
  19 + num: ta.get_follower_name.size,
  20 + name: safe_join(ta.collect_group_with_index(:follower_name) do |n,i|
  21 + link_to image_tag(ta.get_follower_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")),
  22 + ta.get_follower_url[i], title: n
  23 + end)
  24 + }
  25 + end
  26 +
17 27 def join_community_description ta
18   - n_('has joined 1 community:<br />%{name}'.html_safe, 'has joined %{num} communities:<br />%{name}'.html_safe, ta.get_resource_name.size) % {
  28 + n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size).html_safe % {
19 29 num: ta.get_resource_name.size,
20   - name: ta.collect_group_with_index(:resource_name) do |n,i|
  30 + name: safe_join(ta.collect_group_with_index(:resource_name) do |n,i|
21 31 link = link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")),
22 32 ta.get_resource_url[i], title: n
23   - end.join.html_safe
  33 + end)
24 34 }
25 35 end
26 36  
... ... @@ -68,9 +78,9 @@ module ActionTrackerHelper
68 78 end
69 79  
70 80 def favorite_enterprise_description ta
71   - _('favorited enterprise %{title}') % {
  81 + (_('favorited enterprise %{title}') % {
72 82 title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url),
73   - }
  83 + }).html_safe
74 84 end
75 85  
76 86 end
... ...
app/helpers/application_helper.rb
... ... @@ -880,7 +880,7 @@ module ApplicationHelper
880 880 link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => user.identifier)
881 881 end
882 882 link = list.map do |element|
883   - link_to(content_tag('strong', _('<span>Manage</span> %s') % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s') % element.short_name)
  883 + link_to(content_tag('strong', _('<span>Manage</span> %s').html_safe % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s').html_safe % element.short_name)
884 884 end
885 885 if link_to_all
886 886 link << link_to_all
... ... @@ -921,7 +921,7 @@ module ApplicationHelper
921 921 logout_link = link_to(logout_icon.html_safe, { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
922 922 join_result = safe_join(
923 923 [welcome_span.html_safe, render_environment_features(:usermenu).html_safe, admin_link.html_safe,
924   - manage_enterprises.html_safe, manage_communities.html_safe, ctrl_panel_link.html_safe,
  924 + manage_enterprises, manage_communities, ctrl_panel_link.html_safe,
925 925 pending_tasks_count.html_safe, logout_link.html_safe], "")
926 926 join_result
927 927 end
... ...
app/helpers/boxes_helper.rb
... ... @@ -285,7 +285,7 @@ module BoxesHelper
285 285 end
286 286  
287 287 if block.respond_to?(:help)
288   - buttons << modal_inline_icon(:help, _('Help on this block'), {}, "#help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + modal_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
  288 + buttons << modal_inline_icon(:help, _('Help on this block'), {}, "#help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help.html_safe, :style => 'margin-bottom: 1em;') + modal_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
289 289 end
290 290  
291 291 if block.embedable?
... ...
app/helpers/forms_helper.rb
... ... @@ -128,14 +128,14 @@ module FormsHelper
128 128 counter += 1
129 129 row << item
130 130 if counter % per_row == 0
131   - rows << content_tag('tr', row.join("\n"))
  131 + rows << content_tag('tr', row.join("\n").html_safe)
132 132 counter = 0
133 133 row = []
134 134 end
135 135 end
136   - rows << content_tag('tr', row.join("\n"))
  136 + rows << content_tag('tr', row.join("\n").html_safe)
137 137  
138   - content_tag('table',rows.join("\n"))
  138 + content_tag('table',rows.join("\n").html_safe)
139 139 end
140 140  
141 141 def date_field(name, value, datepicker_options = {}, html_options = {})
... ...
app/helpers/profile_helper.rb
... ... @@ -11,7 +11,7 @@ module ProfileHelper
11 11 PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality]
12 12 PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity]
13 13 PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study]
14   - PERSON_CATEGORIES[:network] = [:friends, :communities, :enterprises]
  14 + PERSON_CATEGORIES[:network] = [:friends, :followers, :followed_profiles, :communities, :enterprises]
15 15 PERSON_CATEGORIES.merge!(COMMON_CATEGORIES)
16 16  
17 17 ORGANIZATION_CATEGORIES = {}
... ... @@ -42,7 +42,8 @@ module ProfileHelper
42 42 :created_at => _('Profile created at'),
43 43 :members_count => _('Members'),
44 44 :privacy_setting => _('Privacy setting'),
45   - :article_tags => _('Tags')
  45 + :article_tags => _('Tags'),
  46 + :followed_profiles => _('Following')
46 47 }
47 48  
48 49 EXCEPTION = {
... ... @@ -144,6 +145,14 @@ module ProfileHelper
144 145 link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url)
145 146 end
146 147  
  148 + def treat_followers(followers)
  149 + link_to(profile.followers.count, {:action=>"followed", :controller=>"profile", :profile=>"#{profile.identifier}"})
  150 + end
  151 +
  152 + def treat_followed_profiles(followed_profiles)
  153 + link_to(profile.followed_profiles.count, {:action=>"following", :controller=>"profile", :profile=>"#{profile.identifier}"})
  154 + end
  155 +
147 156 def treat_events(events)
148 157 link_to events.published.count, :controller => 'events', :action => 'events'
149 158 end
... ...
app/jobs/notify_activity_to_profiles_job.rb
... ... @@ -19,8 +19,8 @@ class NotifyActivityToProfilesJob &lt; Struct.new(:tracked_action_id)
19 19 # Notify the user
20 20 ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id)
21 21  
22   - # Notify all friends
23   - ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select f.friend_id, #{tracked_action.id} from friendships as f where person_id=#{tracked_action.user.id} and f.friend_id not in (select atn.profile_id from action_tracker_notifications as atn where atn.action_tracker_id = #{tracked_action.id})")
  22 + # Notify all followers
  23 + ActionTrackerNotification.connection.execute("INSERT INTO action_tracker_notifications(profile_id, action_tracker_id) SELECT DISTINCT c.person_id, #{tracked_action.id} FROM profiles_circles AS p JOIN circles as c ON c.id = p.circle_id WHERE p.profile_id = #{tracked_action.user.id} AND (c.person_id NOT IN (SELECT atn.profile_id FROM action_tracker_notifications AS atn WHERE atn.action_tracker_id = #{tracked_action.id}))")
24 24  
25 25 if tracked_action.user.is_a? Organization
26 26 ActionTrackerNotification.connection.execute "insert into action_tracker_notifications(profile_id, action_tracker_id) " +
... ...
app/mailers/contact.rb
... ... @@ -47,8 +47,8 @@ class Contact
47 47 content_type: 'text/html',
48 48 to: contact.dest.notification_emails,
49 49 reply_to: contact.email,
50   - subject: "[#{contact.dest.short_name(30)}] " + contact.subject,
51   - from: "#{contact.name} <#{contact.dest.environment.noreply_email}>"
  50 + subject: "[#{contact.dest.short_name(30)}] #{contact.subject}".html_safe,
  51 + from: "#{contact.name} <#{contact.dest.environment.noreply_email}>".html_safe
52 52 }
53 53  
54 54 if contact.sender
... ...
app/mailers/environment_mailing.rb
... ... @@ -30,7 +30,7 @@ class EnvironmentMailing &lt; Mailing
30 30 end
31 31  
32 32 def signature_message
33   - _('Sent by %s.') % source.name
  33 + _('Sent by %s.').html_safe % source.name
34 34 end
35 35  
36 36 def url
... ...
app/mailers/mailing.rb
... ... @@ -2,7 +2,8 @@ require_dependency &#39;mailing_job&#39;
2 2  
3 3 class Mailing < ApplicationRecord
4 4  
5   - acts_as_having_settings :field => :data
  5 + extend ActsAsHavingSettings::ClassMethods
  6 + acts_as_having_settings field: :data
6 7  
7 8 attr_accessible :subject, :body, :data
8 9  
... ... @@ -23,11 +24,11 @@ class Mailing &lt; ApplicationRecord
23 24 end
24 25  
25 26 def generate_from
26   - "#{source.name} <#{if source.is_a? Environment then source.noreply_email else source.contact_email end}>"
  27 + "#{source.name} <#{if source.is_a? Environment then source.noreply_email else source.contact_email end}>".html_safe
27 28 end
28 29  
29 30 def generate_subject
30   - '[%s] %s' % [source.name, subject]
  31 + '[%s] %s'.html_safe % [source.name, subject]
31 32 end
32 33  
33 34 def signature_message
... ...
app/mailers/organization_mailing.rb
... ... @@ -30,7 +30,7 @@ class OrganizationMailing &lt; Mailing
30 30 end
31 31  
32 32 def signature_message
33   - _('Sent by community %s.') % source.name
  33 + _('Sent by community %s.').html_safe % source.name
34 34 end
35 35  
36 36 include Rails.application.routes.url_helpers
... ...
app/mailers/pending_task_notifier.rb
... ... @@ -12,8 +12,8 @@ class PendingTaskNotifier &lt; ApplicationMailer
12 12  
13 13 mail(
14 14 to: person.email,
15   - from: "#{person.environment.name} <#{person.environment.noreply_email}>",
16   - subject: _("[%s] Pending tasks") % person.environment.name
  15 + from: "#{person.environment.name} <#{person.environment.noreply_email}>".html_safe,
  16 + subject: _("[%s] Pending tasks").html_safe % person.environment.name
17 17 )
18 18 end
19 19  
... ...
app/mailers/scrap_notifier.rb
... ... @@ -14,8 +14,8 @@ class ScrapNotifier &lt; ApplicationMailer
14 14 @url = sender.environment.top_url
15 15 mail(
16 16 to: receiver.email,
17   - from: "#{sender.environment.name} <#{sender.environment.noreply_email}>",
18   - subject: _("[%s] You received a scrap!") % [sender.environment.name]
  17 + from: "#{sender.environment.name} <#{sender.environment.noreply_email}>".html_safe,
  18 + subject: _("[%s] You received a scrap!").html_safe % [sender.environment.name]
19 19 )
20 20 end
21 21 end
... ...
app/mailers/task_mailer.rb
... ... @@ -14,7 +14,7 @@ class TaskMailer &lt; ApplicationMailer
14 14 mail(
15 15 to: task.target.notification_emails.compact,
16 16 from: self.class.generate_from(task),
17   - subject: "[%s] %s" % [task.environment.name, task.target_notification_description]
  17 + subject: "[%s] %s".html_safe % [task.environment.name, task.target_notification_description]
18 18 )
19 19 end
20 20  
... ... @@ -27,7 +27,7 @@ class TaskMailer &lt; ApplicationMailer
27 27 mail(
28 28 to: task.friend_email,
29 29 from: self.class.generate_from(task),
30   - subject: '[%s] %s' % [ task.requestor.environment.name, task.target_notification_description ]
  30 + subject: '[%s] %s'.html_safe % [ task.requestor.environment.name, task.target_notification_description ]
31 31 )
32 32 end
33 33  
... ... @@ -43,7 +43,7 @@ class TaskMailer &lt; ApplicationMailer
43 43 mail_with_template(
44 44 to: task.requestor.notification_emails,
45 45 from: self.class.generate_from(task),
46   - subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description],
  46 + subject: '[%s] %s'.html_safe % [task.requestor.environment.name, task.target_notification_description],
47 47 email_template: task.email_template,
48 48 template_params: {:environment => task.requestor.environment, :task => task, :message => @message, :url => @url, :requestor => task.requestor}
49 49 )
... ...
app/mailers/user_mailer.rb
... ... @@ -13,8 +13,8 @@ class UserMailer &lt; ApplicationMailer
13 13  
14 14 mail(
15 15 to: user_email,
16   - from: "#{user.environment.name} <#{user.environment.contact_email}>",
17   - subject: _("[%{environment}] Welcome to %{environment} mail!") % { :environment => user.environment.name }
  16 + from: "#{user.environment.name} <#{user.environment.contact_email}>".html_safe,
  17 + subject: _("[%{environment}] Welcome to %{environment} mail!").html_safe % { :environment => user.environment.name }
18 18 )
19 19 end
20 20  
... ... @@ -30,7 +30,7 @@ class UserMailer &lt; ApplicationMailer
30 30 mail_with_template(
31 31 from: "#{user.environment.name} <#{user.environment.contact_email}>",
32 32 to: user.email,
33   - subject: _("[%s] Activate your account") % [user.environment.name],
  33 + subject: _("[%s] Activate your account").html_safe % [user.environment.name],
34 34 template_params: {:environment => user.environment, :activation_code => @activation_code, :redirection => @redirection, :join => @join, :person => user.person, :url => @url},
35 35 email_template: user.environment.email_templates.find_by_template_type(:user_activation),
36 36 )
... ... @@ -44,8 +44,8 @@ class UserMailer &lt; ApplicationMailer
44 44 mail(
45 45 content_type: 'text/html',
46 46 to: user.email,
47   - from: "#{user.environment.name} <#{user.environment.contact_email}>",
48   - subject: email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject,
  47 + from: "#{user.environment.name} <#{user.environment.contact_email}>".html_safe,
  48 + subject: email_subject.blank? ? _("Welcome to environment %s").html_safe % [user.environment.name] : email_subject,
49 49 body: @body
50 50 )
51 51 end
... ... @@ -63,8 +63,8 @@ class UserMailer &lt; ApplicationMailer
63 63 mail(
64 64 content_type: 'text/html',
65 65 to: user.email,
66   - from: "#{user.environment.name} <#{user.environment.contact_email}>",
67   - subject: _("[%s] What about grow up your network?") % user.environment.name
  66 + from: "#{user.environment.name} <#{user.environment.contact_email}>".html_safe,
  67 + subject: _("[%s] What about grow up your network?").html_safe % user.environment.name
68 68 )
69 69 end
70 70  
... ...
app/models/abuse_complaint.rb
... ... @@ -25,7 +25,7 @@ class AbuseComplaint &lt; Task
25 25 end
26 26  
27 27 def title
28   - abuse_reports.count > 1 ? (_('Abuse complaint (%s)') % abuse_reports.count) :_('Abuse complaint')
  28 + abuse_reports.count > 1 ? (_('Abuse complaint (%s)').html_safe % abuse_reports.count) :_('Abuse complaint')
29 29 end
30 30  
31 31 def linked_subject
... ... @@ -57,15 +57,15 @@ class AbuseComplaint &lt; Task
57 57 end
58 58  
59 59 def task_activated_message
60   - _('Your profile was reported by the users of %s due to inappropriate behavior. The administrators of the environment are now reviewing the report. To solve this misunderstanding, please contact the administrators.') % environment.name
  60 + _('Your profile was reported by the users of %s due to inappropriate behavior. The administrators of the environment are now reviewing the report. To solve this misunderstanding, please contact the administrators.').html_safe % environment.name
61 61 end
62 62  
63 63 def task_finished_message
64   - _('Your profile was disabled by the administrators of %s due to inappropriate behavior. To solve this misunderstanding please contact them.') % environment.name
  64 + _('Your profile was disabled by the administrators of %s due to inappropriate behavior. To solve this misunderstanding please contact them.').html_safe % environment.name
65 65 end
66 66  
67 67 def target_notification_description
68   - _('%s was reported due to inappropriate behavior.') % reported.name
  68 + _('%s was reported due to inappropriate behavior.').html_safe % reported.name
69 69 end
70 70  
71 71 def target_notification_message
... ...
app/models/add_member.rb
... ... @@ -22,6 +22,7 @@ class AddMember &lt; Task
22 22 self.roles = [Profile::Roles.member(organization.environment.id).id]
23 23 end
24 24 target.affiliate(requestor, self.roles.select{|r| !r.to_i.zero? }.map{|i| Role.find(i)})
  25 + person.follow(organization, Circle.find_or_create_by(:person => person, :name =>_('memberships'), :profile_type => 'Community'))
25 26 end
26 27  
27 28 def title
... ... @@ -56,7 +57,7 @@ class AddMember &lt; Task
56 57 def target_notification_description
57 58 requestor_email = " (#{requestor.email})" if requestor.may_display_field_to?("email")
58 59  
59   - _("%{requestor}%{requestor_email} wants to be a member of '%{organization}'.") % {:requestor => requestor.name, :requestor_email => requestor_email, :organization => organization.name}
  60 + _("%{requestor}%{requestor_email} wants to be a member of '%{organization}'.").html_safe % {:requestor => requestor.name, :requestor_email => requestor_email, :organization => organization.name}
60 61 end
61 62  
62 63 def target_notification_message
... ...
app/models/article.rb
... ... @@ -13,7 +13,9 @@ class Article &lt; ApplicationRecord
13 13 :image_builder, :show_to_followers, :archived,
14 14 :author, :display_preview, :published_at, :person_followers
15 15  
  16 + extend ActsAsHavingImage::ClassMethods
16 17 acts_as_having_image
  18 +
17 19 include Noosfero::Plugin::HotSpot
18 20  
19 21 SEARCHABLE_FIELDS = {
... ... @@ -91,7 +93,8 @@ class Article &lt; ApplicationRecord
91 93 has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization'
92 94 has_many :categories_including_virtual, :through => :article_categorizations_including_virtual, :source => :category
93 95  
94   - acts_as_having_settings :field => :setting
  96 + extend ActsAsHavingSettings::ClassMethods