Commit 2cdcd813d955c0e5f5d50d0e5acd907a3b087979

Authored by Evandro Junior
2 parents 3a14efd3 9db1b539

Merge branch 'production' of gitlab.com:participa/noosfero into production

* 'production' of gitlab.com:participa/noosfero: (173 commits)
  update submodule
  update submodule
  add rubygems source
  fixed tasks_controller_test
  added random as a possible value for make_order_with_parameters
  added sql injection protection to method make_order_with_parameters
  HOTFIX: removing wrong comment
  HOTFIX: fix tests
  fix new content url in not found content
  submodule: updating submodule
  Adapting views and helpers to datime format
  Remove admins.map that generate a SQL query for each user causing performance problems.
  Translated using Weblate (Armenian)
  scheduler: scope into Noosfero
  change event start date and ende date to datetime
  search: realign search box and search button
  Avoid unecessary user save after update person
  scrap_test: destroy actiontracker to stabilize #last
  Remove letfover selectordie files
  Update proposals discussion plugin
  ...
Showing 185 changed files with 64518 additions and 62530 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 185 files displayed.

.gitlab-ci.yml
1 before_script: 1 before_script:
2 - mkdir -p tmp/pids log 2 - mkdir -p tmp/pids log
3 - bundle check || bundle install 3 - bundle check || bundle install
  4 +# workaround for plugins with Gemfile
  5 + - perl -pi -e 's/--local //' script/noosfero-plugins
4 - script/noosfero-plugins disableall 6 - script/noosfero-plugins disableall
5 - bundle exec rake makemo &>/dev/null 7 - bundle exec rake makemo &>/dev/null
6 # database 8 # database
@@ -28,3 +28,9 @@ @@ -28,3 +28,9 @@
28 [submodule "public/proposal-app"] 28 [submodule "public/proposal-app"]
29 path = public/proposal-app 29 path = public/proposal-app
30 url = https://gitlab.com/participa/proposal-app.git 30 url = https://gitlab.com/participa/proposal-app.git
  31 +[submodule "plugins/gravatar-provider"]
  32 + path = plugins/gravatar-provider
  33 + url = https://gitlab.com/noosfero-plugins/gravatar-provider.git
  34 +[submodule "plugins/juventude"]
  35 + path = plugins/juventude
  36 + url = https://gitlab.com/noosfero-plugins/juventude.git
@@ -2,7 +2,6 @@ language: ruby @@ -2,7 +2,6 @@ language: ruby
2 rvm: 2 rvm:
3 # for 2.2 support we need to upgrade the pg gem 3 # for 2.2 support we need to upgrade the pg gem
4 - 2.1.6 4 - 2.1.6
5 -cache: bundler  
6 5
7 sudo: false 6 sudo: false
8 addons: 7 addons:
@@ -19,9 +18,20 @@ addons: @@ -19,9 +18,20 @@ addons:
19 - libsqlite3-dev 18 - libsqlite3-dev
20 - libxslt1-dev 19 - libxslt1-dev
21 20
  21 +before_install:
  22 + - gem env
  23 +
  24 +# workaround for https://github.com/travis-ci/travis-ci/issues/4536
  25 +before_install:
  26 + - export GEM_HOME=$PWD/vendor/bundle/ruby/2.1.0
  27 + - gem install bundler
  28 +cache: bundler
  29 +
22 before_script: 30 before_script:
23 - mkdir -p tmp/pids log 31 - mkdir -p tmp/pids log
24 - - bundle check || bundle install 32 +# workaround for plugins with Gemfile
  33 + - perl -pi -e 's/cat .+ > \$gemfile/echo "source \\"https:\/\/rubygems.org\\"" > \$gemfile && cat \$source\/Gemfile >> \$gemfile/' script/noosfero-plugins
  34 + - perl -pi -e 's/--local --quiet/install --jobs=3 --retry=3/' script/noosfero-plugins
25 - script/noosfero-plugins disableall 35 - script/noosfero-plugins disableall
26 - bundle exec rake makemo &>/dev/null 36 - bundle exec rake makemo &>/dev/null
27 # database 37 # database
@@ -28,6 +28,11 @@ gem 'grape-entity' @@ -28,6 +28,11 @@ gem 'grape-entity'
28 gem 'grape_logging', :git => 'https://github.com/aceunreal/grape_logging.git', :ref => '100091b' 28 gem 'grape_logging', :git => 'https://github.com/aceunreal/grape_logging.git', :ref => '100091b'
29 gem 'rack-cors' 29 gem 'rack-cors'
30 gem 'rack-contrib' 30 gem 'rack-contrib'
  31 +gem 'liquid', '~> 3.0.3'
  32 +#gem 'grape-swagger-rails'
  33 +
  34 +# FIXME list here all actual dependencies (i.e. the ones in debian/control),
  35 +# with their GEM names (not the Debian package names)
31 36
32 gem 'api-pagination', '~> 4.1.1' 37 gem 'api-pagination', '~> 4.1.1'
33 38
app/controllers/admin/environment_email_templates_controller.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +class EnvironmentEmailTemplatesController < EmailTemplatesController
  2 +
  3 + protect 'manage_email_templates', :environment
  4 +
  5 + protected
  6 +
  7 + def owner
  8 + environment
  9 + end
  10 +
  11 + before_filter :only => :index do
  12 + @back_to = url_for(:controller => :admin_panel)
  13 + end
  14 +
  15 +end
app/controllers/email_templates_controller.rb 0 → 100644
@@ -0,0 +1,62 @@ @@ -0,0 +1,62 @@
  1 +class EmailTemplatesController < ApplicationController
  2 +
  3 + def index
  4 + @email_templates = owner.email_templates
  5 + end
  6 +
  7 + def show
  8 + @email_template = owner.email_templates.find(params[:id])
  9 +
  10 + respond_to do |format|
  11 + format.html # show.html.erb
  12 + format.json { render json: @email_template }
  13 + end
  14 + end
  15 +
  16 + def show_parsed
  17 + @email_template = owner.email_templates.find(params[:id])
  18 + template_params = {:profile => owner, :environment => environment}
  19 + render json: {:parsed_body => @email_template.parsed_body(template_params), :parsed_subject => @email_template.parsed_subject(template_params)}
  20 + end
  21 +
  22 + def new
  23 + @email_template = owner.email_templates.build(:owner => owner)
  24 + end
  25 +
  26 + def edit
  27 + @email_template = owner.email_templates.find(params[:id])
  28 + end
  29 +
  30 + def create
  31 + @email_template = owner.email_templates.build(params[:email_template])
  32 + @email_template.owner = owner
  33 +
  34 + if @email_template.save
  35 + session[:notice] = _('Email template was successfully created.')
  36 + redirect_to url_for(:action => :index)
  37 + else
  38 + render action: "new"
  39 + end
  40 + end
  41 +
  42 + def update
  43 + @email_template = owner.email_templates.find(params[:id])
  44 +
  45 + if @email_template.update_attributes(params[:email_template])
  46 + session[:notice] = _('Email template was successfully updated.')
  47 + redirect_to url_for(:action => :index)
  48 + else
  49 + render action: "edit"
  50 + end
  51 + end
  52 +
  53 + def destroy
  54 + @email_template = owner.email_templates.find(params[:id])
  55 + @email_template.destroy
  56 +
  57 + respond_to do |format|
  58 + format.html { redirect_to url_for(:action => :index)}
  59 + format.json { head :no_content }
  60 + end
  61 + end
  62 +end
app/controllers/my_profile/manage_products_controller.rb
@@ -206,7 +206,8 @@ class ManageProductsController &lt; ApplicationController @@ -206,7 +206,8 @@ class ManageProductsController &lt; ApplicationController
206 end 206 end
207 207
208 def certifiers_for_selection 208 def certifiers_for_selection
209 - @qualifier = Qualifier.exists?(params[:id]) ? Qualifier.find(params[:id]) : nil 209 + # updated to use hash as argument to exists? to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  210 + @qualifier = Qualifier.exists?(:id => params[:id]) ? Qualifier.find(params[:id]) : nil
210 render :update do |page| 211 render :update do |page|
211 page.replace_html params[:certifier_area], :partial => 'certifiers_for_selection' 212 page.replace_html params[:certifier_area], :partial => 'certifiers_for_selection'
212 end 213 end
app/controllers/my_profile/profile_email_templates_controller.rb 0 → 100644
@@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
  1 +class ProfileEmailTemplatesController < EmailTemplatesController
  2 +
  3 + needs_profile
  4 + protect 'manage_email_templates', :profile
  5 +
  6 + protected
  7 +
  8 + def owner
  9 + profile
  10 + end
  11 +
  12 + before_filter :only => :index do
  13 + @back_to = url_for(:controller => :profile_editor)
  14 + end
  15 +
  16 +end
app/controllers/my_profile/tasks_controller.rb
1 class TasksController < MyProfileController 1 class TasksController < MyProfileController
2 2
3 protect [:perform_task, :view_tasks], :profile, :only => [:index, :save_tags, :search_tags] 3 protect [:perform_task, :view_tasks], :profile, :only => [:index, :save_tags, :search_tags]
4 - protect :perform_task, :profile, :except => [:index, :save_tags, :search_tags] 4 + protect :perform_task, :profile, :only => [:processed, :change_responsible, :close, :new, :list_requested, :ticket_details, :search_tags]
5 5
6 def index 6 def index
  7 + @rejection_email_templates = profile.email_templates.find_all_by_template_type(:task_rejection)
  8 + @acceptance_email_templates = profile.email_templates.find_all_by_template_type(:task_acceptance)
  9 +
7 @filter_type = params[:filter_type].presence 10 @filter_type = params[:filter_type].presence
8 @filter_text = params[:filter_text].presence 11 @filter_text = params[:filter_text].presence
9 @filter_responsible = params[:filter_responsible] 12 @filter_responsible = params[:filter_responsible]
@@ -19,13 +22,17 @@ class TasksController &lt; MyProfileController @@ -19,13 +22,17 @@ class TasksController &lt; MyProfileController
19 22
20 @failed = params ? params[:failed] : {} 23 @failed = params ? params[:failed] : {}
21 24
22 - @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization? 25 + @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task') && !r.has_permission?('view_tasks')}) if profile.organization?
23 26
24 @view_only = !current_person.has_permission?(:perform_task, profile) 27 @view_only = !current_person.has_permission?(:perform_task, profile)
25 end 28 end
26 29
27 def processed 30 def processed
28 - @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at) 31 + @tasks = Task.to(profile).without_spam.closed.order('tasks.created_at DESC')
  32 + @filter = params[:filter] || {}
  33 + @tasks = filter_tasks(@filter, @tasks)
  34 + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
  35 + @task_types = Task.closed_types_for(profile)
29 end 36 end
30 37
31 def change_responsible 38 def change_responsible
@@ -78,6 +85,7 @@ class TasksController &lt; MyProfileController @@ -78,6 +85,7 @@ class TasksController &lt; MyProfileController
78 end 85 end
79 86
80 url = { :action => 'index' } 87 url = { :action => 'index' }
  88 +
81 if failed.blank? 89 if failed.blank?
82 session[:notice] = _("All decisions were applied successfully.") 90 session[:notice] = _("All decisions were applied successfully.")
83 else 91 else
@@ -109,9 +117,9 @@ class TasksController &lt; MyProfileController @@ -109,9 +117,9 @@ class TasksController &lt; MyProfileController
109 end 117 end
110 118
111 def search_tasks 119 def search_tasks
112 -  
113 - params[:filter_type] = params[:filter_type].blank? ? nil : params[:filter_type]  
114 - result = Task.pending_all(profile,params) 120 + filter_type = params[:filter_type].presence
  121 + filter_text = params[:filter_text].presence
  122 + result = Task.pending_all(profile,filter_type, filter_text)
115 123
116 render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} } 124 render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} }
117 end 125 end
@@ -125,10 +133,9 @@ class TasksController &lt; MyProfileController @@ -125,10 +133,9 @@ class TasksController &lt; MyProfileController
125 133
126 ActsAsTaggableOn.remove_unused_tags = true 134 ActsAsTaggableOn.remove_unused_tags = true
127 135
128 - task = Task.to(profile).find_by_id params[:task_id]  
129 - save = user.tag(task, with: params[:tag_list], on: :tags)  
130 -  
131 - if save 136 + task = profile.tasks.find_by_id(params[:task_id])
  137 +
  138 + if task && task.update_attributes(:tag_list => params[:tag_list])
132 result[:success] = true 139 result[:success] = true
133 end 140 end
134 end 141 end
@@ -149,7 +156,39 @@ class TasksController &lt; MyProfileController @@ -149,7 +156,39 @@ class TasksController &lt; MyProfileController
149 result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"]) 156 result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
150 157
151 render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json' 158 render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json'
  159 + end
  160 +
  161 + protected
  162 +
  163 + def filter_by_closed_date(filter, tasks)
  164 + filter[:closed_from] = Date.parse(filter[:closed_from]) unless filter[:closed_from].blank?
  165 + filter[:closed_until] = Date.parse(filter[:closed_until]) unless filter[:closed_until].blank?
  166 +
  167 + tasks = tasks.where('tasks.end_date >= ?', filter[:closed_from].beginning_of_day) unless filter[:closed_from].blank?
  168 + tasks = tasks.where('tasks.end_date <= ?', filter[:closed_until].end_of_day) unless filter[:closed_until].blank?
  169 + tasks
  170 + end
  171 +
  172 + def filter_by_creation_date(filter, tasks)
  173 + filter[:created_from] = Date.parse(filter[:created_from]) unless filter[:created_from].blank?
  174 + filter[:created_until] = Date.parse(filter[:created_until]) unless filter[:created_until].blank?
  175 +
  176 + tasks = tasks.where('tasks.created_at >= ?', filter[:created_from].beginning_of_day) unless filter[:created_from].blank?
  177 + tasks = tasks.where('tasks.created_at <= ?', filter[:created_until].end_of_day) unless filter[:created_until].blank?
  178 + tasks
  179 + end
152 180
  181 + def filter_tasks(filter, tasks)
  182 + tasks = tasks.includes(:requestor, :closed_by)
  183 + tasks = tasks.of(filter[:type].presence)
  184 + tasks = tasks.where(:status => filter[:status]) unless filter[:status].blank?
  185 + tasks = filter_by_creation_date(filter, tasks)
  186 + tasks = filter_by_closed_date(filter, tasks)
  187 +
  188 + tasks = tasks.like('profiles.name', filter[:requestor]) unless filter[:requestor].blank?
  189 + tasks = tasks.like('closed_bies_tasks.name', filter[:closed_by]) unless filter[:closed_by].blank?
  190 + tasks = tasks.like('tasks.data', filter[:text]) unless filter[:text].blank?
  191 + tasks
153 end 192 end
154 193
155 end 194 end
app/controllers/public/contact_controller.rb
@@ -6,8 +6,9 @@ class ContactController &lt; PublicController @@ -6,8 +6,9 @@ class ContactController &lt; PublicController
6 def new 6 def new
7 @contact = build_contact 7 @contact = build_contact
8 if request.post? && params[:confirm] == 'true' 8 if request.post? && params[:confirm] == 'true'
9 - @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil  
10 - @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil 9 + # updated to use hash as argument to exists? to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  10 + @contact.city = (!params[:city].blank? && City.exists?(:id => params[:city])) ? City.find(params[:city]).name : nil
  11 + @contact.state = (!params[:state].blank? && State.exists?(:id => params[:state])) ? State.find(params[:state]).name : nil
11 if @contact.deliver 12 if @contact.deliver
12 session[:notice] = _('Contact successfully sent') 13 session[:notice] = _('Contact successfully sent')
13 redirect_to :action => 'new' 14 redirect_to :action => 'new'
app/controllers/public/profile_controller.rb
@@ -356,6 +356,7 @@ class ProfileController &lt; PublicController @@ -356,6 +356,7 @@ class ProfileController &lt; PublicController
356 356
357 def send_mail 357 def send_mail
358 @mailing = profile.mailings.build(params[:mailing]) 358 @mailing = profile.mailings.build(params[:mailing])
  359 + @email_templates = profile.email_templates.find_all_by_template_type(:organization_members)
359 if request.post? 360 if request.post?
360 @mailing.locale = locale 361 @mailing.locale = locale
361 @mailing.person = user 362 @mailing.person = user
app/controllers/public/search_controller.rb
@@ -95,10 +95,10 @@ class SearchController &lt; PublicController @@ -95,10 +95,10 @@ class SearchController &lt; PublicController
95 95
96 def events 96 def events
97 if params[:year].blank? && params[:year].blank? && params[:day].blank? 97 if params[:year].blank? && params[:year].blank? && params[:day].blank?
98 - @date = Date.today 98 + @date = DateTime.now
99 else 99 else
100 - year = (params[:year] ? params[:year].to_i : Date.today.year)  
101 - month = (params[:month] ? params[:month].to_i : Date.today.month) 100 + year = (params[:year] ? params[:year].to_i : DateTime.now.year)
  101 + month = (params[:month] ? params[:month].to_i : DateTime.now.month)
102 day = (params[:day] ? params[:day].to_i : 1) 102 day = (params[:day] ? params[:day].to_i : 1)
103 @date = build_date(year, month, day) 103 @date = build_date(year, month, day)
104 end 104 end
@@ -109,9 +109,7 @@ class SearchController &lt; PublicController @@ -109,9 +109,7 @@ class SearchController &lt; PublicController
109 @events = @category ? 109 @events = @category ?
110 environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) : 110 environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
111 environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page]) 111 environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page])
112 - end  
113 -  
114 - if params[:year] || params[:month] 112 + elsif params[:year] || params[:month]
115 @events = @category ? 113 @events = @category ?
116 environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) : 114 environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
117 environment.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page]) 115 environment.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page])
app/helpers/application_helper.rb
@@ -44,6 +44,8 @@ module ApplicationHelper @@ -44,6 +44,8 @@ module ApplicationHelper
44 44
45 include PluginsHelper 45 include PluginsHelper
46 46
  47 + include TaskHelper
  48 +
47 def locale 49 def locale
48 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale 50 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale
49 end 51 end
@@ -606,24 +608,14 @@ module ApplicationHelper @@ -606,24 +608,14 @@ module ApplicationHelper
606 trigger_class = 'enterprise-trigger' 608 trigger_class = 'enterprise-trigger'
607 end 609 end
608 end 610 end
609 -  
610 - extra_info_tag = ''  
611 - img_class = 'profile-image'  
612 -  
613 - if extra_info.is_a? Hash  
614 - extra_info_tag = content_tag( 'span', extra_info[:value], :class => 'extra_info '+extra_info[:class])  
615 - img_class +=' '+extra_info[:class]  
616 - else  
617 - extra_info_tag = content_tag( 'span', extra_info, :class => 'extra_info' )  
618 - end  
619 - #extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) 611 + extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' )
620 links = links_for_balloon(profile) 612 links = links_for_balloon(profile)
621 content_tag('div', content_tag(tag, 613 content_tag('div', content_tag(tag,
622 (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") + 614 (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") +
623 link_to( 615 link_to(
624 - content_tag( 'span', profile_image( profile, size ), :class => img_class ) + 616 + content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) +
625 content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + 617 content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) +
626 - extra_info_tag + profile_sex_icon( profile ) + profile_cat_icons( profile ), 618 + extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ),
627 profile.url, 619 profile.url,
628 :class => 'profile_link url', 620 :class => 'profile_link url',
629 :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, 621 :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name,
app/helpers/content_viewer_helper.rb
@@ -51,7 +51,7 @@ module ContentViewerHelper @@ -51,7 +51,7 @@ module ContentViewerHelper
51 elsif date_format == 'past_time' 51 elsif date_format == 'past_time'
52 left_time = true 52 left_time = true
53 end 53 end
54 - content_tag('span', show_date(article.published_at, use_numbers , year, left_time), :class => 'date') 54 + content_tag('span', show_time(article.published_at, use_numbers , year, left_time), :class => 'date')
55 end 55 end
56 56
57 def link_to_comments(article, args = {}) 57 def link_to_comments(article, args = {})
app/helpers/dates_helper.rb
@@ -43,9 +43,14 @@ module DatesHelper @@ -43,9 +43,14 @@ module DatesHelper
43 end 43 end
44 44
45 # formats a datetime for displaying. 45 # formats a datetime for displaying.
46 - def show_time(time)  
47 - if time  
48 - _('%{day} %{month} %{year}, %{hour}:%{minutes}') % { :year => time.year, :month => month_name(time.month), :day => time.day, :hour => time.hour, :minutes => time.strftime("%M") } 46 + def show_time(time, use_numbers = false, year = true, left_time = false)
  47 + if time && use_numbers
  48 + _('%{month}/%{day}/%{year}, %{hour}:%{minutes}') % { :year => (year ? time.year : ''), :month => time.month, :day => time.day, :hour => time.hour, :minutes => time.strftime("%M") }
  49 + elsif time && left_time
  50 + date_format = time_ago_in_words(time)
  51 + elsif time
  52 + date_format = year ? _('%{month_name} %{day}, %{year} %{hour}:%{minutes}') : _('%{month_name} %{day} %{hour}:%{minutes}')
  53 + date_format % { :day => time.day, :month_name => month_name(time.month), :year => time.year, :hour => time.hour, :minutes => time.strftime("%M") }
49 else 54 else
50 '' 55 ''
51 end 56 end
@@ -53,7 +58,7 @@ module DatesHelper @@ -53,7 +58,7 @@ module DatesHelper
53 58
54 def show_period(date1, date2 = nil, use_numbers = false) 59 def show_period(date1, date2 = nil, use_numbers = false)
55 if (date1 == date2) || (date2.nil?) 60 if (date1 == date2) || (date2.nil?)
56 - show_date(date1, use_numbers) 61 + show_time(date1, use_numbers)
57 else 62 else
58 if date1.year == date2.year 63 if date1.year == date2.year
59 if date1.month == date2.month 64 if date1.month == date2.month
@@ -72,8 +77,8 @@ module DatesHelper @@ -72,8 +77,8 @@ module DatesHelper
72 end 77 end
73 else 78 else
74 _('from %{date1} to %{date2}') % { 79 _('from %{date1} to %{date2}') % {
75 - :date1 => show_date(date1, use_numbers),  
76 - :date2 => show_date(date2, use_numbers) 80 + :date1 => show_time(date1, use_numbers),
  81 + :date2 => show_time(date2, use_numbers)
77 } 82 }
78 end 83 end
79 end 84 end
@@ -106,18 +111,18 @@ module DatesHelper @@ -106,18 +111,18 @@ module DatesHelper
106 111
107 def build_date(year, month, day = 1) 112 def build_date(year, month, day = 1)
108 if year.blank? and month.blank? and day.blank? 113 if year.blank? and month.blank? and day.blank?
109 - Date.today 114 + DateTime.now
110 else 115 else
111 if year.blank? 116 if year.blank?
112 - year = Date.today.year 117 + year = DateTime.now.year
113 end 118 end
114 if month.blank? 119 if month.blank?
115 - month = Date.today.month 120 + month = DateTime.now.month
116 end 121 end
117 if day.blank? 122 if day.blank?
118 day = 1 123 day = 1
119 end 124 end
120 - Date.new(year.to_i, month.to_i, day.to_i) 125 + DateTime.new(year.to_i, month.to_i, day.to_i)
121 end 126 end
122 end 127 end
123 128
app/helpers/email_template_helper.rb 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +module EmailTemplateHelper
  2 +
  3 + def mail_with_template(params={})
  4 + if params[:email_template].present?
  5 + params[:body] = params[:email_template].parsed_body(params[:template_params])
  6 + params[:subject] = params[:email_template].parsed_subject(params[:template_params])
  7 + params[:content_type] = "text/html"
  8 + end
  9 + mail(params.except(:email_template))
  10 + end
  11 +
  12 +end
app/helpers/events_helper.rb
@@ -16,7 +16,7 @@ module EventsHelper @@ -16,7 +16,7 @@ module EventsHelper
16 16
17 content_tag( 'tr', 17 content_tag( 'tr',
18 content_tag('td', 18 content_tag('td',
19 - content_tag('div', show_date(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_date(article.end_date))),:class => 'event-date' ) + 19 + content_tag('div', show_time(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_time(article.end_date))),:class => 'event-date' ) +
20 content_tag('div',link_to(article.name,article.url),:class => 'event-title') + 20 content_tag('div',link_to(article.name,article.url),:class => 'event-title') +
21 content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place') 21 content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place')
22 ) 22 )
@@ -30,7 +30,7 @@ module EventsHelper @@ -30,7 +30,7 @@ module EventsHelper
30 # the day itself 30 # the day itself
31 date, 31 date,
32 # is there any events in this date? 32 # is there any events in this date?
33 - events.any? {|event| event.date_range.include?(date)}, 33 + events.any? {|event| event.date_range.cover?(date)},
34 # is this date in the current month? 34 # is this date in the current month?
35 true 35 true
36 ] 36 ]
app/helpers/forms_helper.rb
@@ -151,7 +151,7 @@ module FormsHelper @@ -151,7 +151,7 @@ module FormsHelper
151 datepicker_options[:close_text] ||= _('Done') 151 datepicker_options[:close_text] ||= _('Done')
152 datepicker_options[:constrain_input] ||= true 152 datepicker_options[:constrain_input] ||= true
153 datepicker_options[:current_text] ||= _('Today') 153 datepicker_options[:current_text] ||= _('Today')
154 - datepicker_options[:date_format] ||= 'mm/dd/yy' 154 + datepicker_options[:date_format] ||= 'yy/mm/dd'
155 datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')] 155 datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
156 datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')] 156 datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')]
157 datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')] 157 datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')]
@@ -236,7 +236,7 @@ module FormsHelper @@ -236,7 +236,7 @@ module FormsHelper
236 weekHeader: #{datepicker_options[:week_header].to_json}, 236 weekHeader: #{datepicker_options[:week_header].to_json},
237 yearRange: #{datepicker_options[:year_range].to_json}, 237 yearRange: #{datepicker_options[:year_range].to_json},
238 yearSuffix: #{datepicker_options[:year_suffix].to_json} 238 yearSuffix: #{datepicker_options[:year_suffix].to_json}
239 - }) 239 + }).datepicker('setDate', new Date('#{value}'))
240 </script> 240 </script>
241 ".html_safe 241 ".html_safe
242 result 242 result
app/helpers/task_helper.rb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +module TaskHelper
  2 +
  3 + def task_email_template(description, email_templates, task, include_blank=true)
  4 + return '' unless email_templates.present?
  5 +
  6 + content_tag(
  7 + :div,
  8 + labelled_form_field(description, select_tag("tasks[#{task.id}][task][email_template_id]", options_from_collection_for_select(email_templates, :id, :name), :include_blank => include_blank, 'data-url' => url_for(:controller => 'profile_email_templates', :action => 'show_parsed', :profile => profile.identifier))),
  9 + :class => 'template-selection'
  10 + )
  11 + end
  12 +
  13 + def task_action action
  14 + base_url = { action: action }
  15 + url_for(base_url.merge(filter_params))
  16 + end
  17 +
  18 + def filter_params
  19 + filter_fields = ['filter_type', 'filter_text', 'filter_responsible', 'filter_tags']
  20 + params.select {|filter| filter if filter_fields.include? filter }
  21 + end
  22 +
  23 +end
app/mailers/task_mailer.rb
1 class TaskMailer < ActionMailer::Base 1 class TaskMailer < ActionMailer::Base
2 2
  3 + include EmailTemplateHelper
  4 +
3 def target_notification(task, message) 5 def target_notification(task, message)
4 @message = extract_message(message) 6 @message = extract_message(message)
5 @target = task.target.name 7 @target = task.target.name
@@ -34,10 +36,12 @@ class TaskMailer &lt; ActionMailer::Base @@ -34,10 +36,12 @@ class TaskMailer &lt; ActionMailer::Base
34 @environment = task.requestor.environment.name 36 @environment = task.requestor.environment.name
35 @url = url_for(:host => task.requestor.environment.default_hostname, :controller => 'home') 37 @url = url_for(:host => task.requestor.environment.default_hostname, :controller => 'home')
36 38
37 - mail( 39 + mail_with_template(
38 to: task.requestor.notification_emails, 40 to: task.requestor.notification_emails,
39 from: self.class.generate_from(task), 41 from: self.class.generate_from(task),
40 - subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description] 42 + subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description],
  43 + email_template: task.email_template,
  44 + template_params: {:environment => task.requestor.environment, :task => task, :message => @message, :url => @url, :requestor => task.requestor}
41 ) 45 )
42 end 46 end
43 47
app/mailers/user_mailer.rb
1 class UserMailer < ActionMailer::Base 1 class UserMailer < ActionMailer::Base
  2 +
  3 + include EmailTemplateHelper
  4 +
2 def activation_email_notify(user) 5 def activation_email_notify(user)
3 user_email = "#{user.login}@#{user.email_domain}" 6 user_email = "#{user.login}@#{user.email_domain}"
4 @name = user.name 7 @name = user.name
@@ -22,10 +25,12 @@ class UserMailer &lt; ActionMailer::Base @@ -22,10 +25,12 @@ class UserMailer &lt; ActionMailer::Base
22 @redirection = (true if user.return_to) 25 @redirection = (true if user.return_to)
23 @join = (user.community_to_join if user.community_to_join) 26 @join = (user.community_to_join if user.community_to_join)
24 27
25 - mail( 28 + mail_with_template(
26 from: "#{user.environment.name} <#{user.environment.contact_email}>", 29 from: "#{user.environment.name} <#{user.environment.contact_email}>",
27 to: user.email, 30 to: user.email,
28 subject: _("[%s] Activate your account") % [user.environment.name], 31 subject: _("[%s] Activate your account") % [user.environment.name],
  32 + template_params: {:environment => user.environment, :activation_code => @activation_code, :redirection => @redirection, :join => @join},
  33 + email_template: user.environment.email_templates.find_by_template_type(:user_activation),
29 ) 34 )
30 end 35 end
31 36
app/models/article.rb
@@ -645,6 +645,14 @@ class Article &lt; ActiveRecord::Base @@ -645,6 +645,14 @@ class Article &lt; ActiveRecord::Base
645 can_display_hits? && display_hits 645 can_display_hits? && display_hits
646 end 646 end
647 647
  648 + def display_media_panel?
  649 + can_display_media_panel? && environment.enabled?('media_panel')
  650 + end
  651 +
  652 + def can_display_media_panel?
  653 + false
  654 + end
  655 +
648 def image? 656 def image?
649 false 657 false
650 end 658 end
@@ -813,6 +821,10 @@ class Article &lt; ActiveRecord::Base @@ -813,6 +821,10 @@ class Article &lt; ActiveRecord::Base
813 "content_viewer/view_page" 821 "content_viewer/view_page"
814 end 822 end
815 823
  824 + def to_liquid
  825 + HashWithIndifferentAccess.new :name => name, :abstract => abstract, :body => body, :id => id, :parent_id => parent_id, :author => author
  826 + end
  827 +
816 private 828 private
817 829
818 def sanitize_tag_list 830 def sanitize_tag_list
app/models/change_password.rb
@@ -28,6 +28,13 @@ class ChangePassword &lt; Task @@ -28,6 +28,13 @@ class ChangePassword &lt; Task
28 validates_presence_of :password_confirmation, :on => :update, :if => lambda { |change| change.status != Task::Status::CANCELLED } 28 validates_presence_of :password_confirmation, :on => :update, :if => lambda { |change| change.status != Task::Status::CANCELLED }
29 validates_confirmation_of :password, :if => lambda { |change| change.status != Task::Status::CANCELLED } 29 validates_confirmation_of :password, :if => lambda { |change| change.status != Task::Status::CANCELLED }
30 30
  31 + before_save :set_email_template
  32 +
  33 + def set_email_template
  34 + template = environment.email_templates.find_by_template_type(:user_change_password)
  35 + data[:email_template_id] = template.id unless template.nil?
  36 + end
  37 +
31 def environment 38 def environment
32 requestor.environment unless requestor.nil? 39 requestor.environment unless requestor.nil?
33 end 40 end
app/models/email_template.rb 0 → 100644
@@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
  1 +class EmailTemplate < ActiveRecord::Base
  2 +
  3 + belongs_to :owner, :polymorphic => true
  4 +
  5 + attr_accessible :template_type, :subject, :body, :owner, :name
  6 +
  7 + validates_presence_of :name
  8 +
  9 + validates :name, uniqueness: { scope: [:owner_type, :owner_id] }
  10 +
  11 + validates :template_type, uniqueness: { scope: [:owner_type, :owner_id] }, if: :unique_by_type?
  12 +
  13 + def parsed_body(params)
  14 + @parsed_body ||= parse(body, params)
  15 + end
  16 +
  17 + def parsed_subject(params)
  18 + @parsed_subject ||= parse(subject, params)
  19 + end
  20 +
  21 + def self.available_types
  22 + {
  23 + :task_rejection => {:description => _('Task Rejection'), :owner_type => Profile},
  24 + :task_acceptance => {:description => _('Task Acceptance'), :owner_type => Profile},
  25 + :organization_members => {:description => _('Organization Members'), :owner_type => Profile},
  26 + :user_activation => {:description => _('User Activation'), :unique => true, :owner_type => Environment},
  27 + :user_change_password => {:description => _('Change User Password'), :unique => true, :owner_type => Environment}
  28 + }
  29 + end
  30 +
  31 + def available_types
  32 + HashWithIndifferentAccess.new EmailTemplate.available_types.select {|k, v| owner.kind_of?(v[:owner_type])}
  33 + end
  34 +
  35 + def type_description
  36 + available_types.fetch(template_type, {})[:description]
  37 + end
  38 +
  39 + def unique_by_type?
  40 + available_types.fetch(template_type, {})[:unique]
  41 + end
  42 +
  43 + protected
  44 +
  45 + def parse(source, params)
  46 + template = Liquid::Template.parse(source)
  47 + template.render(HashWithIndifferentAccess.new(params))
  48 + end
  49 +
  50 +end
app/models/enterprise_homepage.rb
@@ -35,4 +35,8 @@ class EnterpriseHomepage &lt; Article @@ -35,4 +35,8 @@ class EnterpriseHomepage &lt; Article
35 false 35 false
36 end 36 end
37 37
  38 + def can_display_media_panel?
  39 + true
  40 + end
  41 +
38 end 42 end
app/models/environment.rb
@@ -21,6 +21,7 @@ class Environment &lt; ActiveRecord::Base @@ -21,6 +21,7 @@ class Environment &lt; ActiveRecord::Base
21 21
22 has_many :tasks, :dependent => :destroy, :as => 'target' 22 has_many :tasks, :dependent => :destroy, :as => 'target'
23 has_many :search_terms, :as => :context 23 has_many :search_terms, :as => :context
  24 + has_many :email_templates, :foreign_key => :owner_id
24 25
25 IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/ 26 IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
26 27
@@ -50,6 +51,7 @@ class Environment &lt; ActiveRecord::Base @@ -50,6 +51,7 @@ class Environment &lt; ActiveRecord::Base
50 'manage_environment_licenses' => N_('Manage environment licenses'), 51 'manage_environment_licenses' => N_('Manage environment licenses'),
51 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'), 52 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'),
52 'edit_appearance' => N_('Edit appearance'), 53 'edit_appearance' => N_('Edit appearance'),
  54 + 'manage_email_templates' => N_('Manage Email Templates'),
53 } 55 }
54 56
55 module Roles 57 module Roles
@@ -985,6 +987,10 @@ class Environment &lt; ActiveRecord::Base @@ -985,6 +987,10 @@ class Environment &lt; ActiveRecord::Base
985 self.licenses.any? 987 self.licenses.any?
986 end 988 end
987 989
  990 + def to_liquid
  991 + HashWithIndifferentAccess.new :name => name
  992 + end
  993 +
988 private 994 private
989 995
990 def default_language_available 996 def default_language_available
app/models/event.rb
@@ -3,13 +3,14 @@ require &#39;builder&#39; @@ -3,13 +3,14 @@ require &#39;builder&#39;
3 3
4 class Event < Article 4 class Event < Article
5 5
6 - attr_accessible :start_date, :end_date, :link, :address 6 + attr_accessible :start_date, :end_date, :link, :address, :presenter
7 7
8 def self.type_name 8 def self.type_name
9 _('Event') 9 _('Event')
10 end 10 end
11 11
12 settings_items :address, :type => :string 12 settings_items :address, :type => :string
  13 + settings_items :presenter, :type => :string
13 14
14 def link=(value) 15 def link=(value)
15 self.setting[:link] = maybe_add_http(value) 16 self.setting[:link] = maybe_add_http(value)
@@ -23,7 +24,7 @@ class Event &lt; Article @@ -23,7 +24,7 @@ class Event &lt; Article
23 24
24 def initialize(*args) 25 def initialize(*args)
25 super(*args) 26 super(*args)
26 - self.start_date ||= Date.today 27 + self.start_date ||= DateTime.now
27 end 28 end
28 29
29 validates_presence_of :title, :start_date 30 validates_presence_of :title, :start_date
@@ -35,7 +36,7 @@ class Event &lt; Article @@ -35,7 +36,7 @@ class Event &lt; Article
35 end 36 end
36 37
37 scope :by_day, lambda { |date| 38 scope :by_day, lambda { |date|
38 - { :conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}], 39 + { :conditions => [' start_date >= :start_date AND start_date <= :end_date AND end_date IS NULL OR (start_date <= :end_date AND end_date >= :start_date)', {:start_date => date.beginning_of_day, :end_date => date.end_of_day}],
39 :order => 'start_date ASC' 40 :order => 'start_date ASC'
40 } 41 }
41 } 42 }
@@ -80,7 +81,7 @@ class Event &lt; Article @@ -80,7 +81,7 @@ class Event &lt; Article
80 81
81 def self.date_range(year, month) 82 def self.date_range(year, month)
82 if year.nil? || month.nil? 83 if year.nil? || month.nil?
83 - today = Date.today 84 + today = DateTime.now
84 year = today.year 85 year = today.year
85 month = today.month 86 month = today.month
86 else 87 else
@@ -88,7 +89,7 @@ class Event &lt; Article @@ -88,7 +89,7 @@ class Event &lt; Article
88 month = month.to_i 89 month = month.to_i
89 end 90 end
90 91
91 - first_day = Date.new(year, month, 1) 92 + first_day = DateTime.new(year, month, 1)
92 last_day = first_day + 1.month - 1.day 93 last_day = first_day + 1.month - 1.day
93 94
94 first_day..last_day 95 first_day..last_day
@@ -134,6 +135,10 @@ class Event &lt; Article @@ -134,6 +135,10 @@ class Event &lt; Article
134 true 135 true
135 end 136 end
136 137
  138 + def can_display_media_panel?
  139 + true
  140 + end
  141 +
137 include Noosfero::TranslatableContent 142 include Noosfero::TranslatableContent
138 include MaybeAddHttp 143 include MaybeAddHttp
139 144
app/models/organization.rb
@@ -178,7 +178,11 @@ class Organization &lt; Profile @@ -178,7 +178,11 @@ class Organization &lt; Profile
178 end 178 end
179 179
180 def notification_emails 180 def notification_emails
  181 + # TODO: Add performance improvement here!
  182 + #emails = [contact_email].select(&:present?) + admins([:user]).pluck(:email)
  183 + # Revert change to make the tests pass
181 emails = [contact_email].select(&:present?) + admins.map(&:email) 184 emails = [contact_email].select(&:present?) + admins.map(&:email)
  185 +
182 if emails.empty? 186 if emails.empty?
183 emails << environment.contact_email 187 emails << environment.contact_email
184 end 188 end
app/models/person.rb
@@ -19,12 +19,13 @@ class Person &lt; Profile @@ -19,12 +19,13 @@ class Person &lt; Profile
19 acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)} 19 acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)}
20 acts_as_accessor 20 acts_as_accessor
21 21
22 - acts_as_tagger  
23 22
24 - scope :members_of, lambda { |resources| 23 + scope :members_of, lambda { |resources, extra_joins = nil|
25 resources = [resources] if !resources.kind_of?(Array) 24 resources = [resources] if !resources.kind_of?(Array)
26 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') 25 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ')
27 - { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] } 26 + joins = [:role_assignments]
  27 + joins += extra_joins if extra_joins.is_a? Array
  28 + { :select => 'DISTINCT profiles.*', :joins => joins, :conditions => [conditions] }
28 } 29 }
29 30
30 scope :not_members_of, lambda { |resources| 31 scope :not_members_of, lambda { |resources|
@@ -33,10 +34,11 @@ class Person &lt; Profile @@ -33,10 +34,11 @@ class Person &lt; Profile
33 { :select => 'DISTINCT profiles.*', :conditions => ['"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "role_assignments" ON "role_assignments"."accessor_id" = "profiles"."id" AND "role_assignments"."accessor_type" = (\'Profile\') WHERE "profiles"."type" IN (\'Person\') AND (%s))' % conditions] } 34 { :select => 'DISTINCT profiles.*', :conditions => ['"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "role_assignments" ON "role_assignments"."accessor_id" = "profiles"."id" AND "role_assignments"."accessor_type" = (\'Profile\') WHERE "profiles"."type" IN (\'Person\') AND (%s))' % conditions] }
34 } 35 }
35 36
36 - scope :by_role, lambda { |roles| 37 + scope :by_role, lambda { |roles, extra_joins = nil|
37 roles = [roles] unless roles.kind_of?(Array) 38 roles = [roles] unless roles.kind_of?(Array)
38 - { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.role_id IN (?)',  
39 -roles] } 39 + joins = [:role_assignments]
  40 + joins += extra_joins if extra_joins.is_a? Array
  41 + { :select => 'DISTINCT profiles.*', :joins => joins, :conditions => ['role_assignments.role_id IN (?)',roles] }
40 } 42 }
41 43
42 scope :not_friends_of, lambda { |resources| 44 scope :not_friends_of, lambda { |resources|
@@ -216,7 +218,7 @@ roles] } @@ -216,7 +218,7 @@ roles] }
216 contact_informatioin 218 contact_informatioin
217 ] 219 ]
218 220
219 - xss_terminate :only => [ :custom_footer, :custom_header, :description, :preferred_domain, :nickname, :sex, :nationality, :country, :state, :city, :district, :zip_code, :address, :address_reference, :cell_phone, :comercial_phone, :personal_website, :jabber_id, :schooling, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization, :organization_website, :contact_phone, :contact_information ], :with => 'white_list' 221 + xss_terminate :only => [ :custom_footer, :custom_header, :description, :nickname, :sex, :nationality, :country, :state, :city, :district, :zip_code, :address, :address_reference, :cell_phone, :comercial_phone, :personal_website, :jabber_id, :schooling, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization, :organization_website, :contact_phone, :contact_information ], :with => 'white_list'
220 222
221 validates_multiparameter_assignments 223 validates_multiparameter_assignments
222 224
@@ -310,7 +312,7 @@ roles] } @@ -310,7 +312,7 @@ roles] }
310 end 312 end
311 313
312 after_update do |person| 314 after_update do |person|
313 - person.user.save! 315 + person.user.save! unless person.user.changes.blank?
314 end 316 end
315 317
316 def is_admin?(environment = nil) 318 def is_admin?(environment = nil)
app/models/product_category.rb
@@ -13,8 +13,11 @@ class ProductCategory &lt; Category @@ -13,8 +13,11 @@ class ProductCategory &lt; Category
13 scope :by_environment, lambda { |environment| { 13 scope :by_environment, lambda { |environment| {
14 :conditions => ['environment_id = ?', environment.id] 14 :conditions => ['environment_id = ?', environment.id]
15 }} 15 }}
  16 +
  17 + # updated scope method to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  18 + # explicited to_i on level argument
16 scope :unique_by_level, lambda { |level| { 19 scope :unique_by_level, lambda { |level| {
17 - :select => "DISTINCT ON (filtered_category) split_part(path, '/', #{level}) AS filtered_category, categories.*" 20 + :select => "DISTINCT ON (filtered_category) split_part(path, '/', #{level.to_i}) AS filtered_category, categories.*"
18 }} 21 }}
19 22
20 def all_products 23 def all_products
app/models/profile.rb
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 # which by default is the one returned by Environment:default. 3 # which by default is the one returned by Environment:default.
4 class Profile < ActiveRecord::Base 4 class Profile < ActiveRecord::Base
5 5
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, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :custom_fields 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, :redirection_after_login, :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :custom_fields, :administrator_mail_notification, :region
7 7
8 # use for internationalizable human type names in search facets 8 # use for internationalizable human type names in search facets
9 # reimplement on subclasses 9 # reimplement on subclasses
@@ -107,6 +107,7 @@ class Profile &lt; ActiveRecord::Base @@ -107,6 +107,7 @@ class Profile &lt; ActiveRecord::Base
107 'invite_members' => N_('Invite members'), 107 'invite_members' => N_('Invite members'),
108 'send_mail_to_members' => N_('Send e-Mail to members'), 108 'send_mail_to_members' => N_('Send e-Mail to members'),
109 'manage_custom_roles' => N_('Manage custom roles'), 109 'manage_custom_roles' => N_('Manage custom roles'),
  110 + 'manage_email_templates' => N_('Manage Email Templates'),
110 } 111 }
111 112
112 acts_as_accessible 113 acts_as_accessible
@@ -191,8 +192,8 @@ class Profile &lt; ActiveRecord::Base @@ -191,8 +192,8 @@ class Profile &lt; ActiveRecord::Base
191 alias_method_chain :count, :distinct 192 alias_method_chain :count, :distinct
192 end 193 end
193 194
194 - def members_by_role(roles)  
195 - Person.members_of(self).by_role(roles) 195 + def members_by_role(roles, with_entities = nil)
  196 + Person.members_of(self, with_entities).by_role(roles, with_entities)
196 end 197 end
197 198
198 acts_as_having_boxes 199 acts_as_having_boxes
@@ -223,6 +224,8 @@ class Profile &lt; ActiveRecord::Base @@ -223,6 +224,8 @@ class Profile &lt; ActiveRecord::Base
223 224
224 has_many :comments_received, :class_name => 'Comment', :through => :articles, :source => :comments 225 has_many :comments_received, :class_name => 'Comment', :through => :articles, :source => :comments
225 226
  227 + has_many :email_templates, :foreign_key => :owner_id
  228 +
226 # Although this should be a has_one relation, there are no non-silly names for 229 # Although this should be a has_one relation, there are no non-silly names for
227 # a foreign key on article to reference the template to which it is 230 # a foreign key on article to reference the template to which it is
228 # welcome_page... =P 231 # welcome_page... =P
@@ -250,6 +253,7 @@ class Profile &lt; ActiveRecord::Base @@ -250,6 +253,7 @@ class Profile &lt; ActiveRecord::Base
250 settings_items :description 253 settings_items :description
251 settings_items :fields_privacy, :type => :hash, :default => {} 254 settings_items :fields_privacy, :type => :hash, :default => {}
252 settings_items :email_suggestions, :type => :boolean, :default => false 255 settings_items :email_suggestions, :type => :boolean, :default => false
  256 + settings_items :administrator_mail_notification, :type => :boolean, :default => true
253 257
254 validates_length_of :description, :maximum => 550, :allow_nil => true 258 validates_length_of :description, :maximum => 550, :allow_nil => true
255 259
@@ -543,6 +547,10 @@ class Profile &lt; ActiveRecord::Base @@ -543,6 +547,10 @@ class Profile &lt; ActiveRecord::Base
543 self.articles.find(:all, options) 547 self.articles.find(:all, options)
544 end 548 end
545 549
  550 + def to_liquid
  551 + HashWithIndifferentAccess.new :name => name, :identifier => identifier
  552 + end
  553 +
546 class << self 554 class << self
547 555
548 # finds a profile by its identifier. This method is a shortcut to 556 # finds a profile by its identifier. This method is a shortcut to
@@ -685,15 +693,15 @@ private :generate_url, :url_options @@ -685,15 +693,15 @@ private :generate_url, :url_options
685 after_create :insert_default_article_set 693 after_create :insert_default_article_set
686 def insert_default_article_set 694 def insert_default_article_set
687 if template 695 if template
688 - copy_articles_from template 696 + self.save! if copy_articles_from template
689 else 697 else
690 default_set_of_articles.each do |article| 698 default_set_of_articles.each do |article|
691 article.profile = self 699 article.profile = self
692 article.advertise = false 700 article.advertise = false
693 article.save! 701 article.save!
694 end 702 end
  703 + self.save!
695 end 704 end
696 - self.save!  
697 end 705 end
698 706
699 # Override this method in subclasses of Profile to create a default article 707 # Override this method in subclasses of Profile to create a default article
@@ -714,10 +722,12 @@ private :generate_url, :url_options @@ -714,10 +722,12 @@ private :generate_url, :url_options
714 end 722 end
715 723
716 def copy_articles_from other 724 def copy_articles_from other
  725 + return false if other.top_level_articles.empty?
717 other.top_level_articles.each do |a| 726 other.top_level_articles.each do |a|
718 copy_article_tree a 727 copy_article_tree a
719 end 728 end
720 self.articles.reload 729 self.articles.reload
  730 + true
721 end 731 end
722 732
723 def copy_article_tree(article, parent=nil) 733 def copy_article_tree(article, parent=nil)
@@ -762,6 +772,29 @@ private :generate_url, :url_options @@ -762,6 +772,29 @@ private :generate_url, :url_options
762 end 772 end
763 end 773 end
764 774
  775 + # Adds many people to profile by id's
  776 + def add_members_by_id(people_ids)
  777 +
  778 + unless people_ids.nil? && people_ids.empty?
  779 +
  780 + people = Person.where(id: people_ids)
  781 + people.each do |person|
  782 +
  783 + add_member(person) unless person.is_member_of?(self)
  784 + end
  785 + end
  786 + end
  787 +
  788 + # Adds many people to profile by email's
  789 + def add_members_by_email(people_emails)
  790 +
  791 + people = User.where(email: people_emails)
  792 + people.each do |user|
  793 +
  794 + add_member(user.person) unless user.person.is_member_of?(self)
  795 + end
  796 + end
  797 +
765 def remove_member(person) 798 def remove_member(person)
766 self.disaffiliate(person, Profile::Roles.all_roles(environment.id)) 799 self.disaffiliate(person, Profile::Roles.all_roles(environment.id))
767 end 800 end
@@ -893,11 +926,11 @@ private :generate_url, :url_options @@ -893,11 +926,11 @@ private :generate_url, :url_options
893 self.forums.count.nonzero? 926 self.forums.count.nonzero?
894 end 927 end
895 928
896 - def admins 929 + def admins(with_entities = nil)
897 return [] if environment.blank? 930 return [] if environment.blank?
898 admin_role = Profile::Roles.admin(environment.id) 931 admin_role = Profile::Roles.admin(environment.id)
899 return [] if admin_role.blank? 932 return [] if admin_role.blank?
900 - self.members_by_role(admin_role) 933 + self.members_by_role(admin_role, with_entities)
901 end 934 end
902 935
903 def enable_contact? 936 def enable_contact?
app/models/task.rb
@@ -42,6 +42,8 @@ class Task &lt; ActiveRecord::Base @@ -42,6 +42,8 @@ class Task &lt; ActiveRecord::Base
42 42
43 attr_protected :status 43 attr_protected :status
44 44
  45 + settings_items :email_template_id, :type => :integer
  46 +
45 def initialize(*args) 47 def initialize(*args)
46 super 48 super
47 self.status = (args.first ? args.first[:status] : nil) || Task::Status::ACTIVE 49 self.status = (args.first ? args.first[:status] : nil) || Task::Status::ACTIVE
@@ -68,14 +70,28 @@ class Task &lt; ActiveRecord::Base @@ -68,14 +70,28 @@ class Task &lt; ActiveRecord::Base
68 begin 70 begin
69 target_msg = task.target_notification_message 71 target_msg = task.target_notification_message
70 if target_msg && task.target && !task.target.notification_emails.empty? 72 if target_msg && task.target && !task.target.notification_emails.empty?
71 - TaskMailer.target_notification(task, target_msg).deliver 73 + if target_profile_accepts_notification?(task)
  74 + TaskMailer.target_notification(task, target_msg).deliver
  75 + end
72 end 76 end
73 - rescue NotImplementedError => ex 77 + rescue Exception => ex
74 Rails.logger.info ex.to_s 78 Rails.logger.info ex.to_s
75 end 79 end
76 end 80 end
77 end 81 end
78 82
  83 + def target_profile_accepts_notification?(task)
  84 + if target_is_profile?(task)
  85 + return task.target.administrator_mail_notification
  86 + else
  87 + true
  88 + end
  89 + end
  90 +
  91 + def target_is_profile?(task)
  92 + task.target.kind_of? Profile
  93 + end
  94 +
79 # this method finished the task. It calls #perform, which must be overriden 95 # this method finished the task. It calls #perform, which must be overriden
80 # by subclasses. At the end a message (as returned by #finish_message) is 96 # by subclasses. At the end a message (as returned by #finish_message) is
81 # sent to the requestor with #notify_requestor. 97 # sent to the requestor with #notify_requestor.
@@ -282,15 +298,56 @@ class Task &lt; ActiveRecord::Base @@ -282,15 +298,56 @@ class Task &lt; ActiveRecord::Base
282 end 298 end
283 end 299 end
284 300
  301 + def email_template
  302 + @email_template ||= email_template_id.present? ? EmailTemplate.find_by_id(email_template_id) : nil
  303 + end
  304 +
  305 + def to_liquid
  306 + HashWithIndifferentAccess.new({
  307 + :requestor => requestor,
  308 + :reject_explanation => reject_explanation,
  309 + :code => code
  310 + })
  311 + end
  312 +
285 scope :pending, :conditions => { :status => Task::Status::ACTIVE } 313 scope :pending, :conditions => { :status => Task::Status::ACTIVE }
286 scope :hidden, :conditions => { :status => Task::Status::HIDDEN } 314 scope :hidden, :conditions => { :status => Task::Status::HIDDEN }
287 scope :finished, :conditions => { :status => Task::Status::FINISHED } 315 scope :finished, :conditions => { :status => Task::Status::FINISHED }
288 scope :canceled, :conditions => { :status => Task::Status::CANCELLED } 316 scope :canceled, :conditions => { :status => Task::Status::CANCELLED }
289 scope :closed, :conditions => { :status => [Task::Status::CANCELLED, Task::Status::FINISHED] } 317 scope :closed, :conditions => { :status => [Task::Status::CANCELLED, Task::Status::FINISHED] }
290 scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] } 318 scope :opened, :conditions => { :status => [Task::Status::ACTIVE, Task::Status::HIDDEN] }
291 - scope :of, lambda { |type| conditions = type ? "type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} } 319 +
  320 + # # updated scope method to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  321 + # def self.of type
  322 + # if type
  323 + # where "type LIKE ?", type
  324 + # else
  325 + # all
  326 + # end
  327 + # end
  328 + #
  329 + # # updated scope method to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  330 + # def self.order_by attribute_name, sort_order
  331 + # if Task.column_names.include? attribute_name
  332 + # # TODO future versions of rails accepts a hash as param to order method
  333 + # # which helps to prevent sql injection in an shorter way
  334 + # sort_order_filtered = ("ASC".eql? "#{sort_order}".upcase) ? 'asc' : 'desc'
  335 + # sort_expression = Task.column_names.collect {|column_name| "#{column_name} #{sort_order_filtered}" if column_name.eql? attribute_name}
  336 + # order(sort_expression.join) unless sort_expression.join.empty?
  337 + # end
  338 + # end
  339 + #
  340 + # # updated scope method to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  341 + # def self.like field, value
  342 + # if value and Tasks.column_names.include? field
  343 + # where("LOWER(?) LIKE ?", "#{field}", "%#{value.downcase}%")
  344 + # end
  345 + # end
  346 +
  347 + scope :of, lambda { |type| conditions = type ? "tasks.type LIKE '#{type}'" : "1=1"; {:conditions => [conditions]} }
292 scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} } 348 scope :order_by, lambda { |attribute, ord| {:order => "#{attribute} #{ord}"} }
293 scope :like, lambda { |field, value| where("LOWER(#{field}) LIKE ?", "%#{value.downcase}%") if value} 349 scope :like, lambda { |field, value| where("LOWER(#{field}) LIKE ?", "%#{value.downcase}%") if value}
  350 +
294 scope :pending_all, lambda { |profile, filter_type, filter_text| 351 scope :pending_all, lambda { |profile, filter_type, filter_text|
295 self.to(profile).without_spam.pending.of(filter_type).like('data', filter_text) 352 self.to(profile).without_spam.pending.of(filter_type).like('data', filter_text)
296 } 353 }
@@ -310,6 +367,10 @@ class Task &lt; ActiveRecord::Base @@ -310,6 +367,10 @@ class Task &lt; ActiveRecord::Base
310 Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] } 367 Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] }
311 end 368 end
312 369
  370 + def self.closed_types_for(profile)
  371 + Task.to(profile).closed.select('distinct type').map { |t| [t.class.name, t.title] }
  372 + end
  373 +
313 def opened? 374 def opened?
314 status == Task::Status::ACTIVE || status == Task::Status::HIDDEN 375 status == Task::Status::ACTIVE || status == Task::Status::HIDDEN
315 end 376 end
app/models/textile_article.rb
@@ -24,6 +24,10 @@ class TextileArticle &lt; TextArticle @@ -24,6 +24,10 @@ class TextileArticle &lt; TextArticle
24 true 24 true
25 end 25 end
26 26
  27 + def can_display_media_panel?
  28 + true
  29 + end
  30 +
27 protected 31 protected
28 32
29 def convert_to_html(textile) 33 def convert_to_html(textile)
app/models/tiny_mce_article.rb
@@ -28,4 +28,8 @@ class TinyMceArticle &lt; TextArticle @@ -28,4 +28,8 @@ class TinyMceArticle &lt; TextArticle
28 true 28 true
29 end 29 end
30 30
  31 + def can_display_media_panel?
  32 + true
  33 + end
  34 +
31 end 35 end
app/models/user.rb
@@ -102,18 +102,20 @@ class User &lt; ActiveRecord::Base @@ -102,18 +102,20 @@ class User &lt; ActiveRecord::Base
102 # Virtual attribute for the unencrypted password 102 # Virtual attribute for the unencrypted password
103 attr_accessor :password, :name 103 attr_accessor :password, :name
104 104
105 - validates_presence_of :login, :email  
106 - validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?}) 105 + validates_presence_of :login
  106 + validates_presence_of :email
  107 + validates_format_of :login, :message => _('incorrect format'), :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?})
107 validates_presence_of :password, :if => :password_required? 108 validates_presence_of :password, :if => :password_required?
108 validates_presence_of :password_confirmation, :if => :password_required? 109 validates_presence_of :password_confirmation, :if => :password_required?
109 - validates_length_of :password, :within => 4..40, :if => :password_required? 110 + validates_length_of :password, :message => _('length must be within 4 to 40 characters'), :within => 4..40, :if => :password_required?
110 validates_confirmation_of :password, :if => :password_required? 111 validates_confirmation_of :password, :if => :password_required?
111 - validates_length_of :login, :within => 2..40, :if => (lambda {|user| !user.login.blank?})  
112 - validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?})  
113 - validates_uniqueness_of :login, :email, :case_sensitive => false, :scope => :environment_id 112 + validates_length_of :login, :message => _('length must be within 2 to 40 characters'), :within => 2..40, :if => (lambda {|user| !user.login.blank?})
  113 + validates_length_of :email, :message => _('length must be within 3 to 100 characters'),:within => 3..100, :if => (lambda {|user| !user.email.blank?})
  114 + validates_uniqueness_of :login, :case_sensitive => false, :scope => :environment_id
  115 + validates_uniqueness_of :email, :case_sensitive => false, :scope => :environment_id
114 before_save :encrypt_password 116 before_save :encrypt_password
115 before_save :normalize_email, if: proc{ |u| u.email.present? } 117 before_save :normalize_email, if: proc{ |u| u.email.present? }
116 - validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?}) 118 + validates_format_of :email, :message => _('incorrect format'), :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?})
117 119
118 validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n 120 validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n
119 121
@@ -392,7 +394,7 @@ class User &lt; ActiveRecord::Base @@ -392,7 +394,7 @@ class User &lt; ActiveRecord::Base
392 394
393 def deliver_activation_code 395 def deliver_activation_code
394 return if person.is_template? 396 return if person.is_template?
395 - UserMailer.activation_code(self).deliver unless self.activation_code.blank? 397 + Delayed::Job.enqueue(UserMailer::Job.new(self, :activation_code)) unless self.activation_code.blank?
396 end 398 end
397 399
398 def delay_activation_check 400 def delay_activation_check
app/views/admin_panel/index.html.erb
@@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
12 <tr><td><%= link_to _('Licenses'), :controller =>'licenses' %></td></tr> 12 <tr><td><%= link_to _('Licenses'), :controller =>'licenses' %></td></tr>
13 <tr><td><%= link_to _('Trusted sites'), :controller =>'trusted_sites' %></td></tr> 13 <tr><td><%= link_to _('Trusted sites'), :controller =>'trusted_sites' %></td></tr>
14 <tr><td><%= link_to _('Blocks'), :controller => 'features', :action => 'manage_blocks' %></td></tr> 14 <tr><td><%= link_to _('Blocks'), :controller => 'features', :action => 'manage_blocks' %></td></tr>
  15 + <tr><td><%= link_to _('Email templates'), :controller =>'environment_email_templates' %></td></tr>
15 </table> 16 </table>
16 17
17 <h2><%= _('Profiles') %></h2> 18 <h2><%= _('Profiles') %></h2>
app/views/cms/_event.html.erb
@@ -8,9 +8,9 @@ @@ -8,9 +8,9 @@
8 <%= render :partial => 'general_fields' %> 8 <%= render :partial => 'general_fields' %>
9 <%= render :partial => 'translatable' %> 9 <%= render :partial => 'translatable' %>
10 10
11 -<%= labelled_form_field(_('Start date'), pick_date(:article, :start_date)) %> 11 +<%= date_range_field('article[start_date]', 'article[end_date]', @article.start_date, @article.end_date, _('%Y-%m-%d %H:%M'), {:time => true}, {:id => 'article_start_date'} ) %>
12 12
13 -<%= labelled_form_field(_('End date'), pick_date(:article, :end_date)) %> 13 +<%= labelled_form_field(_('Presenter:'), text_field(:article, :presenter)) %>
14 14
15 <%= labelled_form_field(_('Event website:'), text_field(:article, :link)) %> 15 <%= labelled_form_field(_('Event website:'), text_field(:article, :link)) %>
16 16
app/views/cms/edit.html.erb
1 <%= error_messages_for 'article' %> 1 <%= error_messages_for 'article' %>
2 2
3 -<% show_media_panel = environment.enabled?('media_panel') && [TinyMceArticle, TextileArticle, Event, EnterpriseHomepage, ProposalsDiscussionPlugin::Topic, ProposalsDiscussionPlugin::Discussion].any?{|klass| @article.kind_of?(klass)} %>  
4 -  
5 -<div class='<%= (show_media_panel ? 'with_media_panel' : 'no_media_panel') %>'> 3 +<div class='<%= (@article.display_media_panel? ? 'with_media_panel' : 'no_media_panel') %>'>
6 <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %> 4 <%= labelled_form_for 'article', :html => { :multipart => true, :class => @type } do |f| %>
7 5
8 <%= hidden_field_tag("type", @type) if @type %> 6 <%= hidden_field_tag("type", @type) if @type %>
@@ -68,7 +66,7 @@ @@ -68,7 +66,7 @@
68 <% end %> 66 <% end %>
69 </div> 67 </div>
70 68
71 -<% if show_media_panel %> 69 +<% if @article.display_media_panel? %>
72 <%= render :partial => 'text_editor_sidebar' %> 70 <%= render :partial => 'text_editor_sidebar' %>
73 <% end %> 71 <% end %>
74 72
app/views/content_viewer/_publishing_info.html.erb
1 <span class="publishing-info"> 1 <span class="publishing-info">
2 <span class="date"> 2 <span class="date">
3 - <%= show_date(@page.published_at) %> 3 + <%= show_time(@page.published_at) %>
4 </span> 4 </span>
5 <span class="author"> 5 <span class="author">
6 <%= _(", by %s") % (@page.author ? link_to(@page.author_name, @page.author_url) : @page.author_name) %> 6 <%= _(", by %s") % (@page.author ? link_to(@page.author_name, @page.author_url) : @page.author_name) %>
app/views/email_templates/_form.html.erb 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +<%= form_for(@email_template, :url => {:action => @email_template.persisted? ? :update : :create, :id => @email_template.id}) do |f| %>
  2 +
  3 + <%= error_messages_for :email_template if @email_template.errors.any? %>
  4 +
  5 + <div class="template-fields">
  6 + <div class="header-fields">
  7 + <%= labelled_form_field(_('Template Name:'), f.text_field(:name)) %>
  8 + <%= labelled_form_field(_('Template Type:'), f.select(:template_type, @email_template.available_types.map {|k,v| [v[:description], k]}, :include_blank => true)) %>
  9 + <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>
  10 + </div>
  11 + <div class="available-params">
  12 + <div class="reference">
  13 + <a target="_blank" href="https://github.com/Shopify/liquid/wiki/Liquid-for-Designers"><%= _('Template language reference') %></a>
  14 + </div>
  15 + <div class="label">
  16 + <%= _('The following parameters may be used in subject and body:') %>
  17 + </div>
  18 + <div class="values">
  19 + {{profile.name}}, {{profile.identifier}}, {{environment.name}}
  20 + </div>
  21 + </div>
  22 + <%= render :file => 'shared/tiny_mce' %>
  23 + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %>
  24 + </div>
  25 +
  26 + <div class="actions">
  27 + <%= submit_button(:save, _('Save')) %>
  28 + <%= button(:back, _('Back'), :action => :index) %>
  29 + </div>
  30 +
  31 +<% end %>
app/views/email_templates/edit.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1><%= _('Editing Email Template') %></h1>
  2 +
  3 +<%= render 'form' %>
app/views/email_templates/index.html.erb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +<div class="email-templates">
  2 + <h1><%= _('Email Templates') %></h1>
  3 +
  4 + <table>
  5 + <tr>
  6 + <th><%= _('Name') %></th>
  7 + <th><%= _('Type') %></th>
  8 + <th><%= _('Actions') %></th>
  9 + </tr>
  10 +
  11 + <% @email_templates.each do |email_template| %>
  12 + <tr>
  13 + <td><%= email_template.name %></td>
  14 + <td><%= email_template.type_description %></td>
  15 + <td>
  16 + <%= button_without_text(:edit, _('Edit'), {:action => :edit, :id => email_template.id}) %>
  17 + <%= button_without_text(:remove, _('Remove'), {:action => :destroy, :id => email_template.id}, method: :delete, data: { confirm: 'Are you sure?' }) %>
  18 + </td>
  19 + </tr>
  20 + <% end %>
  21 + </table>
  22 +
  23 + <br />
  24 +
  25 + <%= button(:new, _('New template'), :action => :new) %>
  26 + <%= button(:back, _('Back'), @back_to) %>
  27 +</div>
app/views/email_templates/new.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1><%= _('New Email Template') %></h1>
  2 +
  3 +<%= render 'form' %>
app/views/email_templates/show.html.erb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<p id="notice"><%= notice %></p>
  2 +
  3 +
  4 +<%= link_to 'Edit', url_for(:action => :edit, :id => @email_template.id) %> |
  5 +<%= link_to 'Back', url_for(:action => :index) %>
app/views/profile/send_mail.html.erb
@@ -4,6 +4,12 @@ @@ -4,6 +4,12 @@
4 4
5 <%= error_messages_for :mailing %> 5 <%= error_messages_for :mailing %>
6 6
  7 +<% if @email_templates.present? %>
  8 + <div class="template-selection">
  9 + <%= labelled_form_field(_('Select a template:'), select_tag(:template, options_from_collection_for_select(@email_templates, :id, :name), :include_blank => true, 'data-url' => url_for(:controller => 'profile_email_templates', :action => 'show_parsed'))) %>
  10 + </div>
  11 +<% end %>
  12 +
7 <%= form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %> 13 <%= form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %>
8 14
9 <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %> 15 <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>
app/views/profile_editor/_moderation.html.erb
1 <h2><%= _('Moderation options') %></h2> 1 <h2><%= _('Moderation options') %></h2>
2 <% if profile.community? %> 2 <% if profile.community? %>
3 <div style='margin-bottom: 1em'> 3 <div style='margin-bottom: 1em'>
  4 + <h4><%= _('Email Configuration:')%></h4>
  5 + </div>
  6 + <div style='margin-bottom: 0.5em'>
  7 + <%= check_box(:profile_data, :administrator_mail_notification, :style => 'float: left') %>
  8 + <div style='margin-left: 30px'>
  9 + <%= _('Send administrator Email for every task (Default: yes)') %>
  10 + </div>
  11 + </div>
  12 +
  13 + <div style='margin-bottom: 1em'>
4 <h4><%= _('Invitation moderation:')%></h4> 14 <h4><%= _('Invitation moderation:')%></h4>
5 </div> 15 </div>
6 <div style='margin-bottom: 0.5em'> 16 <div style='margin-bottom: 0.5em'>
app/views/profile_editor/index.html.erb
@@ -72,6 +72,8 @@ @@ -72,6 +72,8 @@
72 72
73 <%= control_panel_button(_('Edit welcome page'), 'welcome-page', :action => 'welcome_page') if has_welcome_page %> 73 <%= control_panel_button(_('Edit welcome page'), 'welcome-page', :action => 'welcome_page') if has_welcome_page %>
74 74
  75 + <%= control_panel_button(_('Email Templates'), 'email-templates', :controller => :profile_email_templates) if profile.organization? %>
  76 +
75 <% @plugins.dispatch(:control_panel_buttons).each do |button| %> 77 <% @plugins.dispatch(:control_panel_buttons).each do |button| %>
76 <%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %> 78 <%= control_panel_button(button[:title], button[:icon], button[:url], button[:html_options]) %>
77 <% end %> 79 <% end %>
app/views/profile_members/_members_list.html.erb
@@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
20 :loading => "jQuery('#members-list').addClass('loading')", 20 :loading => "jQuery('#members-list').addClass('loading')",
21 :success => "jQuery('#tr-#{m.identifier}').show()", 21 :success => "jQuery('#tr-#{m.identifier}').show()",
22 :complete => "jQuery('#members-list').removeClass('loading')", 22 :complete => "jQuery('#members-list').removeClass('loading')",
  23 + :confirm => _('Are you sure you want to remove this user?'),
23 :url => { :id => m }.merge(remove_action)) if m != user %> 24 :url => { :id => m }.merge(remove_action)) if m != user %>
24 </div> 25 </div>
25 </td> 26 </td>
app/views/shared/not_found.html.erb
1 <div id='not-found'> 1 <div id='not-found'>
2 - <h1><%= _('Nonexistent content: %s') % (content_tag('tt', @path)) %></h1> 2 + <h1><%= _('There is no such page: %s') % (content_tag('tt', @path)) %></h1>
3 <p> 3 <p>
4 <%= _('.You may have clicked an expired link or mistyped the address.') %> 4 <%= _('.You may have clicked an expired link or mistyped the address.') %>
5 - <%= _('.This page does not exist. Would you like to: Create a new conteúdoou Locate existing content.') %> 5 + <%= _('.This page does not exist. Would you like to: Create a new content or locate existing content.') %>
6 <!-- <%= _('If you clicked a link that was in another site, or was given to you by someone else, it would be nice if you tell them that their link is not valid anymore.') %> --> 6 <!-- <%= _('If you clicked a link that was in another site, or was given to you by someone else, it would be nice if you tell them that their link is not valid anymore.') %> -->
7 </p> 7 </p>
8 8
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 <%= button :home, _('Go to the home page'), '/' %> 11 <%= button :home, _('Go to the home page'), '/' %>
12 <% if logged_in? %> 12 <% if logged_in? %>
13 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %> 13 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
14 - <%= modal_button('new', _('New content'), :controller => 'cms', :action => 'new', :parent_id => parent_id, :cms => true) %> 14 + <%= modal_button('new', _('New content'), myprofile_path(:profile => current_person.identifier, :controller => 'cms', :action => 'new', :parent_id => parent_id)) %>
15 <% end %> 15 <% end %>
16 <% end %> 16 <% end %>
17 <form action="/search"> 17 <form action="/search">
app/views/tasks/_approve_article_accept_details.html.erb
  1 +<%= task_email_template(_('Select an acceptance email template:'), @acceptance_email_templates, task) %>
  2 +
1 <%= render :file => 'shared/tiny_mce' %> 3 <%= render :file => 'shared/tiny_mce' %>
2 4
3 <%= labelled_form_field(_('Create a link'), f.check_box(:create_link)) %> 5 <%= labelled_form_field(_('Create a link'), f.check_box(:create_link)) %>
app/views/tasks/_task_processed.html.erb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +<div class="title">
  2 + <%= task_information(task) %>
  3 +</div>
  4 +<div class="status">
  5 + <%= _(Task::Status.names[task.status]) %>
  6 +</div>
  7 +<div class="dates">
  8 + <span class="created">
  9 + <span class="label"><%= _('Created:') %></span>
  10 + <span class="value"><%= show_date(task.created_at) %></span>
  11 + </span>
  12 + &nbsp; &#151; &nbsp;
  13 + <span class="processed">
  14 + <span class="label"><%= _('Processed:') %></span>
  15 + <span class="value"><%= show_date(task.end_date) %></span>
  16 + </span>
  17 +</div>
  18 +<% if task.closed_by.present? %>
  19 + <div class="closed-by">
  20 + <span class="label"><%= _('Closed by:') %></span>
  21 + <span class="value"><%= link_to(task.closed_by.name, task.closed_by.url) %></span>
  22 + </div>
  23 +<% end %>
app/views/tasks/_task_reject_details.html.erb
  1 +<%= task_email_template(_('Select a rejection email template:'), @rejection_email_templates, task) %>
  2 +
1 <%= labelled_form_field(_('Rejection explanation'), f.text_area(:reject_explanation, :rows => 5)) %> 3 <%= labelled_form_field(_('Rejection explanation'), f.text_area(:reject_explanation, :rows => 5)) %>
app/views/tasks/index.html.erb
@@ -50,7 +50,7 @@ @@ -50,7 +50,7 @@
50 <em><%= _('No pending tasks for %s') % profile.name %></em> 50 <em><%= _('No pending tasks for %s') % profile.name %></em>
51 </p> 51 </p>
52 <% else %> 52 <% else %>
53 - <%= form_tag :action => 'close' do%> 53 + <%= form_tag task_action('close') do%>
54 <% button_bar(:class => 'task-actions') do %> 54 <% button_bar(:class => 'task-actions') do %>
55 <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %> 55 <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
56 <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %> 56 <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
@@ -67,7 +67,9 @@ @@ -67,7 +67,9 @@
67 <% end %> 67 <% end %>
68 68
69 <div class="task_boxes"> 69 <div class="task_boxes">
70 - <%= render :partial => 'task', :collection => @tasks %> 70 + <% @tasks.each do |task| %>
  71 + <%= render :partial => partial_for_class(task.class, nil, nil), :locals => {:task => task} %>
  72 + <% end %>
71 </div> 73 </div>
72 74
73 <% unless @view_only %> 75 <% unless @view_only %>
app/views/tasks/processed.html.erb
  1 +<%= stylesheet_link_tag 'tasks' %>
  2 +
  3 +<div class="task-processed">
1 <h1><%= _("%s's processed tasks") % profile.name %></h1> 4 <h1><%= _("%s's processed tasks") % profile.name %></h1>
2 5
  6 +<div class="task-processed-filter">
  7 +<%
  8 + type_collection = [[nil, _('All')]] + @task_types
  9 +%>
  10 + <%= form_tag '#', :method => 'get' do %>
  11 + <%= field_set_tag _('Filter'), :class => 'filter_fields' do %>
  12 + <div>
  13 + <%= labelled_select(_('Type of task')+': ', 'filter[type]', :first, :last, @filter[:type], type_collection, {:id => 'filter-type'}) %>
  14 + <%= labelled_select(_('Status:'), 'filter[status]', :last, :first, @filter[:status], [[_('Any'), nil], [_(Task::Status.names[Task::Status::CANCELLED]), 2], [_(Task::Status.names[Task::Status::FINISHED]), 3] ]) %>
  15 + </div>
  16 +
  17 + <div>
  18 + <%= labelled_text_field(_('Text Filter:'), 'filter[text]', @filter[:text]) %>
  19 + </div>
  20 +
  21 + <div>
  22 + <%= labelled_text_field(_('Requestor:'), 'filter[requestor]', @filter[:requestor]) %>
  23 + <%= labelled_text_field(_('Closed by:'), 'filter[closed_by]', @filter[:closed_by]) %>
  24 + </div>
  25 +
  26 + <%= labelled_form_field(_('Creation date'), date_range_field('filter[created_from]', 'filter[created_until]', @filter[:created_from], @filter[:created_until], '%Y-%m-%d', { :change_month => true, :change_year => true, :date_format => 'yy-mm-dd' }, { :size => 14, :from_id => 'filter_created_from', :to_id => 'filter_created_until' })) %>
  27 + <%= labelled_form_field(_('Processed date'), date_range_field('filter[closed_from]', 'filter[closed_until]', @filter[:closed_from], @filter[:closed_until], '%Y-%m-%d', { :change_month => true, :change_year => true, :date_format => 'yy-mm-dd' }, { :size => 14, :from_id => 'filter_closed_from', :to_id => 'filter_closed_until' })) %>
  28 +
  29 + <div class="actions">
  30 + <%= submit_button(:search, _('Search')) %>
  31 + </div>
  32 + <% end %>
  33 + <% end %>
  34 +</div>
  35 +
3 <p> 36 <p>
4 <% if @tasks.empty? %> 37 <% if @tasks.empty? %>
5 <em><%= _('No processed tasks.') %></em> 38 <em><%= _('No processed tasks.') %></em>
6 <% else %> 39 <% else %>
7 - <ul> 40 + <ul class="task-list">
8 <% @tasks.each do |item| %> 41 <% @tasks.each do |item| %>
9 - <li>  
10 - <strong><%= task_information(item) %></strong> <br/>  
11 - <small>  
12 - <%= _('Created:') +' '+ show_date(item.created_at) %>  
13 - &nbsp; &#151; &nbsp;  
14 - <%= _('Processed:') +' '+ show_date(item.end_date) %>  
15 - </small> 42 + <li class="task status-<%= item.status%>">
  43 + <%= render :partial => partial_for_class(item.class, nil, 'processed'), :locals => {:task => item} %>
16 </li> 44 </li>
17 <% end %> 45 <% end %>
18 </ul> 46 </ul>
  47 + <%= pagination_links(@tasks)%>
19 <% end %> 48 <% end %>
20 </p> 49 </p>
21 50
22 <% button_bar do %> 51 <% button_bar do %>
23 <%= button(:back, _('Back'), :action => 'index') %> 52 <%= button(:back, _('Back'), :action => 'index') %>
24 <% end %> 53 <% end %>
  54 +
  55 +</div>
config/application.rb
@@ -62,7 +62,7 @@ module Noosfero @@ -62,7 +62,7 @@ module Noosfero
62 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 62 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
63 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 63 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
64 # config.time_zone = 'Central Time (US & Canada)' 64 # config.time_zone = 'Central Time (US & Canada)'
65 - config.time_zone = 'Brasilia' 65 + #config.time_zone = 'Brasilia'
66 66
67 67
68 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 68 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
config/initializers/eager_load.rb
1 -Rails.application.eager_load! 1 +Rails.application.eager_load! if ActiveRecord::Base.connection.table_exists? 'categories'
config/initializers/unicorn.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +require_dependency 'noosfero/scheduler/defer'
  2 +
  3 +if defined? Unicorn
  4 + ObjectSpace.each_object Unicorn::HttpServer do |s|
  5 + s.extend Noosfero::Scheduler::Defer::Unicorn
  6 + end
  7 +end
  8 +
db/migrate/20150609105354_create_email_template.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +class CreateEmailTemplate < ActiveRecord::Migration
  2 +
  3 + def change
  4 + create_table :email_templates do |t|
  5 + t.string :name
  6 + t.string :template_type
  7 + t.string :subject
  8 + t.text :body
  9 + t.references :owner, :polymorphic => true
  10 + t.timestamps
  11 + end
  12 + end
  13 +
  14 +end
db/migrate/20150617222204_event_period_with_support_to_datetime.rb 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +class EventPeriodWithSupportToDatetime < ActiveRecord::Migration
  2 + def up
  3 + change_table :articles do |t|
  4 + t.change :start_date, :datetime
  5 + end
  6 +
  7 + change_table :articles do |t|
  8 + t.change :end_date, :datetime
  9 + end
  10 +
  11 + change_table :article_versions do |t|
  12 + t.change :start_date, :datetime
  13 + end
  14 +
  15 + change_table :article_versions do |t|
  16 + t.change :end_date, :datetime
  17 + end
  18 + end
  19 +
  20 + def down
  21 + change_table :articles do |t|
  22 + t.change :start_date, :date
  23 + end
  24 +
  25 + change_table :articles do |t|
  26 + t.change :end_date, :date
  27 + end
  28 +
  29 + change_table :article_versions do |t|
  30 + t.change :start_date, :date
  31 + end
  32 +
  33 + change_table :article_versions do |t|
  34 + t.change :end_date, :date
  35 + end
  36 + end
  37 +end
0 \ No newline at end of file 38 \ No newline at end of file
db/migrate/20150712194411_change_task_end_date_from_date_to_date_time.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class ChangeTaskEndDateFromDateToDateTime < ActiveRecord::Migration
  2 +
  3 + def up
  4 + change_column :tasks, :end_date, :datetime
  5 + end
  6 +
  7 + def down
  8 + change_column :tasks, :end_date, :date
  9 + end
  10 +end
db/migrate/20150722042714_change_article_date_to_datetime.rb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +class ChangeArticleDateToDatetime < ActiveRecord::Migration
  2 +
  3 + def up
  4 + change_table :articles do |t|
  5 + t.change :start_date, :datetime
  6 + t.change :end_date, :datetime
  7 + end
  8 +
  9 + change_table :article_versions do |t|
  10 + t.change :start_date, :datetime
  11 + t.change :end_date, :datetime
  12 + end
  13 + end
  14 +
  15 + def down
  16 + change_table :articles do |t|
  17 + t.change :start_date, :date
  18 + t.change :end_date, :date
  19 + end
  20 +
  21 + change_table :article_versions do |t|
  22 + t.change :start_date, :date
  23 + t.change :end_date, :date
  24 + end
  25 + end
  26 +
  27 +end
features/comment.feature
@@ -37,7 +37,7 @@ Feature: comment @@ -37,7 +37,7 @@ Feature: comment
37 And I fill in "Title" with "Hey ho, let's go!" 37 And I fill in "Title" with "Hey ho, let's go!"
38 And I fill in "Enter your comment" with "Hey ho, let's go!" 38 And I fill in "Enter your comment" with "Hey ho, let's go!"
39 When I press "Post comment" 39 When I press "Post comment"
40 - Then I should see "Hey ho, let's go" 40 + Then I should see "Hey ho, let"
41 41
42 @selenium-fixme 42 @selenium-fixme
43 Scenario: redirect to right place after comment a picture 43 Scenario: redirect to right place after comment a picture
lib/activities_counter_cache_job.rb
1 class ActivitiesCounterCacheJob 1 class ActivitiesCounterCacheJob
  2 +
  3 + # Changed to prevent sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
2 def perform 4 def perform
3 - person_activities_counts = ActiveRecord::Base.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.user_id WHERE (action_tracker.created_at >= '#{ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db)}') AND ( (profiles.type = 'Person' ) ) GROUP BY profiles.id;")  
4 - organization_activities_counts = ActiveRecord::Base.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.target_id WHERE (action_tracker.created_at >= '#{ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db)}') AND ( (profiles.type = 'Community' OR profiles.type = 'Enterprise' OR profiles.type = 'Organization' ) ) GROUP BY profiles.id;") 5 + person_activities_counts = ActiveRecord::Base.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.user_id WHERE (action_tracker.created_at >= #{ActiveRecord::Base.connection.quote(ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db))}) AND ( (profiles.type = 'Person' ) ) GROUP BY profiles.id;")
  6 + organization_activities_counts = ActiveRecord::Base.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.target_id WHERE (action_tracker.created_at >= #{ActiveRecord::Base.connection.quote(ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db))}) AND ( (profiles.type = 'Community' OR profiles.type = 'Enterprise' OR profiles.type = 'Organization' ) ) GROUP BY profiles.id;")
5 activities_counts = person_activities_counts.entries + organization_activities_counts.entries 7 activities_counts = person_activities_counts.entries + organization_activities_counts.entries
6 activities_counts.each do |count| 8 activities_counts.each do |count|
7 - ActiveRecord::Base.connection.execute("UPDATE profiles SET activities_count=#{count['count'].to_i} WHERE profiles.id=#{count['id']};") 9 + update_sql = ActiveRecord::Base.__send__(:sanitize_sql, ["UPDATE profiles SET activities_count=? WHERE profiles.id=?;", count['count'].to_i, count['id'] ], '')
  10 + ActiveRecord::Base.connection.execute(update_sql)
8 end 11 end
9 Delayed::Job.enqueue(ActivitiesCounterCacheJob.new, {:priority => -3, :run_at => 1.day.from_now}) 12 Delayed::Job.enqueue(ActivitiesCounterCacheJob.new, {:priority => -3, :run_at => 1.day.from_now})
10 end 13 end
  14 +
11 end 15 end
lib/add_members_job.rb
@@ -4,7 +4,12 @@ class AddMembersJob &lt; Struct.new(:people_ids, :profile_id, :locale) @@ -4,7 +4,12 @@ class AddMembersJob &lt; Struct.new(:people_ids, :profile_id, :locale)
4 Noosfero.with_locale(locale) do 4 Noosfero.with_locale(locale) do
5 5
6 profile = Profile.find(profile_id) 6 profile = Profile.find(profile_id)
7 - profile.add_members people_ids 7 +
  8 + if people_ids.first =~ /\@/
  9 + profile.add_members_by_email people_ids
  10 + else
  11 + profile.add_members_by_id people_ids
  12 + end
8 13
9 end 14 end
10 end 15 end
lib/noosfero/api/api.rb
@@ -12,6 +12,8 @@ module Noosfero @@ -12,6 +12,8 @@ module Noosfero
12 use GrapeLogging::Middleware::RequestLogger, { logger: logger } 12 use GrapeLogging::Middleware::RequestLogger, { logger: logger }
13 13
14 rescue_from :all do |e| 14 rescue_from :all do |e|
  15 + puts e.inspect
  16 + puts e.backtrace.inspect
15 logger.error e 17 logger.error e
16 end 18 end
17 19
lib/noosfero/api/helpers.rb
@@ -160,8 +160,27 @@ require &#39;grape&#39; @@ -160,8 +160,27 @@ require &#39;grape&#39;
160 conditions 160 conditions
161 end 161 end
162 162
163 - def make_order_with_parameters(params)  
164 - params[:order] || "created_at DESC" 163 + # changing make_order_with_parameters to avoid sql injection
  164 + def make_order_with_parameters(object, method, params)
  165 + order = "created_at DESC"
  166 + unless params[:order].blank?
  167 + if params[:order].include? '\'' or params[:order].include? '"'
  168 + order = "created_at DESC"
  169 + elsif ['RANDOM()', 'RANDOM'].include? params[:order].upcase
  170 + order = 'RANDOM()'
  171 + else
  172 + field_name, direction = params[:order].split(' ')
  173 + assoc = object.class.reflect_on_association(method.to_sym)
  174 + if !field_name.blank? and assoc
  175 + if assoc.klass.attribute_names.include? field_name
  176 + if direction.present? and ['ASC','DESC'].include? direction.upcase
  177 + order = "#{field_name} #{direction.upcase}"
  178 + end
  179 + end
  180 + end
  181 + end
  182 + end
  183 + return order
165 end 184 end
166 185
167 def by_reference(scope, params) 186 def by_reference(scope, params)
@@ -176,7 +195,7 @@ require &#39;grape&#39; @@ -176,7 +195,7 @@ require &#39;grape&#39;
176 195
177 def select_filtered_collection_of(object, method, params) 196 def select_filtered_collection_of(object, method, params)
178 conditions = make_conditions_with_parameter(params) 197 conditions = make_conditions_with_parameter(params)
179 - order = make_order_with_parameters(params) 198 + order = make_order_with_parameters(object,method,params)
180 199
181 objects = object.send(method) 200 objects = object.send(method)
182 objects = by_reference(objects, params) 201 objects = by_reference(objects, params)
lib/noosfero/api/session.rb
@@ -32,11 +32,10 @@ module Noosfero @@ -32,11 +32,10 @@ module Noosfero
32 params do 32 params do
33 requires :email, type: String, desc: _("Email") 33 requires :email, type: String, desc: _("Email")
34 requires :login, type: String, desc: _("Login") 34 requires :login, type: String, desc: _("Login")
35 - requires :password, type: String, desc: _("Password")  
36 - requires :password_confirmation, type: String, desc: _("Password confirmation") 35 + #requires :password, type: String, desc: _("Password")
  36 + #requires :password_confirmation, type: String, desc: _("Password confirmation")
37 end 37 end
38 post "/register" do 38 post "/register" do
39 - unique_attributes! User, [:email, :login]  
40 attrs = attributes_for_keys [:email, :login, :password, :password_confirmation] + environment.signup_person_fields 39 attrs = attributes_for_keys [:email, :login, :password, :password_confirmation] + environment.signup_person_fields
41 remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR']) 40 remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR'])
42 # test_captcha will render_api_error! and exit in case of any problem 41 # test_captcha will render_api_error! and exit in case of any problem
lib/noosfero/plugin.rb
@@ -138,11 +138,12 @@ class Noosfero::Plugin @@ -138,11 +138,12 @@ class Noosfero::Plugin
138 filters = [filters] 138 filters = [filters]
139 end 139 end
140 filters.each do |plugin_filter| 140 filters.each do |plugin_filter|
  141 + plugin_filter[:options] ||= {}
  142 + plugin_filter[:options][:if] = -> { environment.plugin_enabled? plugin.module_name }
  143 +
141 filter_method = "#{plugin.identifier}_#{plugin_filter[:method_name]}".to_sym 144 filter_method = "#{plugin.identifier}_#{plugin_filter[:method_name]}".to_sym
142 - controller_class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {}))  
143 - controller_class.send(:define_method, filter_method) do  
144 - instance_exec(&plugin_filter[:block]) if environment.plugin_enabled?(plugin)  
145 - end 145 + controller_class.send plugin_filter[:type], filter_method, plugin_filter[:options]
  146 + controller_class.send :define_method, filter_method, &plugin_filter[:block]
146 end 147 end
147 end 148 end
148 149
lib/noosfero/plugin/parent_methods.rb
@@ -11,6 +11,10 @@ class Noosfero::Plugin @@ -11,6 +11,10 @@ class Noosfero::Plugin
11 @identifier ||= (if self.parents.first.instance_of? Module then self.parents.first else self end).name.underscore 11 @identifier ||= (if self.parents.first.instance_of? Module then self.parents.first else self end).name.underscore
12 end 12 end
13 13
  14 + def module_name
  15 + @name ||= (if self.parents.first != Object then self.parents.first else self end).to_s
  16 + end
  17 +
14 def public_name 18 def public_name
15 @public_name ||= self.identifier.gsub '_plugin', '' 19 @public_name ||= self.identifier.gsub '_plugin', ''
16 end 20 end
lib/noosfero/scheduler/defer.rb 0 → 100644
@@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
  1 +# based on https://github.com/discourse/discourse/blob/master/lib/scheduler/defer.rb
  2 +
  3 +module Noosfero
  4 + module Scheduler
  5 + module Deferrable
  6 + def initialize
  7 + # FIXME: do some other way when not using Unicorn
  8 + @async = (not Rails.env.test?) and defined? Unicorn
  9 + @queue = Queue.new
  10 + @mutex = Mutex.new
  11 + @paused = false
  12 + @thread = nil
  13 + end
  14 +
  15 + def pause
  16 + stop!
  17 + @paused = true
  18 + end
  19 +
  20 + def resume
  21 + @paused = false
  22 + end
  23 +
  24 + # for test
  25 + def async= val
  26 + @async = val
  27 + end
  28 +
  29 + def later desc = nil, &blk
  30 + if @async
  31 + start_thread unless (@thread && @thread.alive?) || @paused
  32 + @queue << [blk, desc]
  33 + else
  34 + blk.call
  35 + end
  36 + end
  37 +
  38 + def stop!
  39 + @thread.kill if @thread and @thread.alive?
  40 + @thread = nil
  41 + end
  42 +
  43 + # test only
  44 + def stopped?
  45 + !(@thread and @thread.alive?)
  46 + end
  47 +
  48 + def do_all_work
  49 + while !@queue.empty?
  50 + do_work _non_block=true
  51 + end
  52 + end
  53 +
  54 + private
  55 +
  56 + def start_thread
  57 + @mutex.synchronize do
  58 + return if @thread && @thread.alive?
  59 + @thread = Thread.new do
  60 + while true
  61 + do_work
  62 + end
  63 + end
  64 + @thread.priority = -2
  65 + end
  66 + end
  67 +
  68 + # using non_block to match Ruby #deq
  69 + def do_work non_block=false
  70 + job, desc = @queue.deq non_block
  71 + begin
  72 + job.call
  73 + rescue => ex
  74 + ExceptionNotifier.notify_exception ex, message: "Running deferred code '#{desc}'"
  75 + end
  76 + rescue => ex
  77 + ExceptionNotifier.notify_exception ex, message: "Processing deferred code queue"
  78 + end
  79 + end
  80 +
  81 + class Defer
  82 +
  83 + module Unicorn
  84 + def process_client client
  85 + ::Noosfero::Scheduler::Defer.pause
  86 + super client
  87 + ::Noosfero::Scheduler::Defer.do_all_work
  88 + ::Noosfero::Scheduler::Defer.resume
  89 + end
  90 + end
  91 +
  92 + extend Deferrable
  93 + initialize
  94 + end
  95 +
  96 + end
  97 +end
plugins/analytics/Gemfile 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +gem 'slim'
  2 +
plugins/analytics/controllers/profile/analytics_plugin/time_on_page_controller.rb 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +class AnalyticsPlugin::TimeOnPageController < ProfileController
  2 +
  3 + before_filter :skip_page_view
  4 +
  5 + def page_load
  6 + # to avoid concurrency problems with the original deferred request, also defer this
  7 + Noosfero::Scheduler::Defer.later do
  8 + page_view = profile.page_views.where(request_id: params[:id]).first
  9 + page_view.request = request
  10 + page_view.page_load!
  11 + end
  12 +
  13 + render nothing: true
  14 + end
  15 +
  16 + def report
  17 + page_view = profile.page_views.where(request_id: params[:id]).first
  18 + page_view.request = request
  19 + page_view.increase_time_on_page!
  20 +
  21 + render nothing: true
  22 + end
  23 +
  24 + protected
  25 +
  26 + def skip_page_view
  27 + @analytics_skip_page_view = true
  28 + end
  29 +
  30 +end
plugins/analytics/db/migrate/20150715001149_init_analytics_plugin.rb 0 → 100644
@@ -0,0 +1,47 @@ @@ -0,0 +1,47 @@
  1 +class InitAnalyticsPlugin < ActiveRecord::Migration
  2 +
  3 + def up
  4 + create_table :analytics_plugin_visits do |t|
  5 + t.integer :profile_id
  6 + end
  7 +
  8 + create_table :analytics_plugin_page_views do |t|
  9 + t.string :type
  10 + t.integer :visit_id
  11 + t.integer :track_id
  12 + t.integer :referer_page_view_id
  13 + t.string :request_id
  14 +
  15 + t.integer :user_id
  16 + t.integer :session_id
  17 + t.integer :profile_id
  18 +
  19 + t.text :url
  20 + t.text :referer_url
  21 +
  22 + t.text :user_agent
  23 + t.string :remote_ip
  24 +
  25 + t.datetime :request_started_at
  26 + t.datetime :request_finished_at
  27 + t.datetime :page_loaded_at
  28 + t.integer :time_on_page, default: 0
  29 +
  30 + t.text :data, default: {}.to_yaml
  31 + end
  32 + add_index :analytics_plugin_page_views, :request_id
  33 + add_index :analytics_plugin_page_views, :referer_page_view_id
  34 +
  35 + add_index :analytics_plugin_page_views, :user_id
  36 + add_index :analytics_plugin_page_views, :session_id
  37 + add_index :analytics_plugin_page_views, :profile_id
  38 + add_index :analytics_plugin_page_views, :url
  39 + add_index :analytics_plugin_page_views, [:user_id, :session_id, :profile_id, :url], name: :analytics_plugin_referer_find
  40 + end
  41 +
  42 + def down
  43 + drop_table :analytics_plugin_visits
  44 + drop_table :analytics_plugin_page_views
  45 + end
  46 +
  47 +end
plugins/analytics/lib/analytics_plugin.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +module AnalyticsPlugin
  2 +
  3 + TimeOnPageUpdateInterval = 2.minutes * 1000
  4 +
  5 + extend Noosfero::Plugin::ParentMethods
  6 +
  7 + def self.plugin_name
  8 + I18n.t'analytics_plugin.lib.plugin.name'
  9 + end
  10 +
  11 + def self.plugin_description
  12 + I18n.t'analytics_plugin.lib.plugin.description'
  13 + end
  14 +
  15 +end
plugins/analytics/lib/analytics_plugin/base.rb 0 → 100644
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +
  2 +class AnalyticsPlugin::Base < Noosfero::Plugin
  3 +
  4 + def body_ending
  5 + return unless profile and profile.analytics_enabled?
  6 + lambda do
  7 + render 'analytics_plugin/body_ending'
  8 + end
  9 + end
  10 +
  11 + def js_files
  12 + ['analytics'].map{ |j| "javascripts/#{j}" }
  13 + end
  14 +
  15 + def application_controller_filters
  16 + [{
  17 + type: 'around_filter', options: {}, block: -> &block do
  18 + request_started_at = Time.now
  19 + block.call
  20 + request_finished_at = Time.now
  21 +
  22 + return if @analytics_skip_page_view
  23 + return unless profile and profile.analytics_enabled?
  24 +
  25 + Noosfero::Scheduler::Defer.later 'analytics: register page view' do
  26 + page_view = profile.page_views.build request: request, profile_id: profile,
  27 + request_started_at: request_started_at, request_finished_at: request_finished_at
  28 +
  29 + unless profile.analytics_anonymous?
  30 + # FIXME: use session.id in Rails 4
  31 + session_id = Marshal.load(Base64.decode64 request['_session_id'])['session_id'] rescue nil
  32 + #session_id = request.session_options[:id]
  33 + page_view.user = user
  34 + page_view.session_id = session_id
  35 + end
  36 +
  37 + page_view.save!
  38 + end
  39 + end,
  40 + }]
  41 + end
  42 +
  43 +end
plugins/analytics/lib/ext/profile.rb 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +require_dependency 'profile'
  2 +require_dependency 'community'
  3 +
  4 +([Profile] + Profile.descendants).each do |subclass|
  5 +subclass.class_eval do
  6 +
  7 + has_many :visits, foreign_key: :profile_id, class_name: 'AnalyticsPlugin::Visit'
  8 + has_many :page_views, foreign_key: :profile_id, class_name: 'AnalyticsPlugin::PageView'
  9 +
  10 +end
  11 +end
  12 +
  13 +class Profile
  14 +
  15 + def analytics_settings attrs = {}
  16 + @analytics_settings ||= Noosfero::Plugin::Settings.new self, AnalyticsPlugin, attrs
  17 + attrs.each{ |a, v| @analytics_settings.send "#{a}=", v }
  18 + @analytics_settings
  19 + end
  20 + alias_method :analytics_settings=, :analytics_settings
  21 +
  22 + def analytics_enabled?
  23 + self.analytics_settings.enabled
  24 + end
  25 +
  26 + def analytics_anonymous?
  27 + self.analytics_settings.anonymous
  28 + end
  29 +
  30 +end
plugins/analytics/locales/en.yml 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +
  2 +en: &en
  3 + analytics_plugin:
  4 + lib:
  5 + plugin:
  6 + name: 'Access tracking'
  7 + description: 'Register the access of selected profiles'
  8 +
  9 +en-US:
  10 + <<: *en
  11 +
plugins/analytics/locales/pt.yml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +
  2 +pt: &pt
  3 + analytics_plugin:
  4 + lib:
  5 + plugin:
  6 + name: 'Rastreio de accesso'
  7 + description: 'Registra o acesso de perfis selecionados'
  8 +
  9 +pt-BR:
  10 + <<: *pt
plugins/analytics/models/analytics_plugin/page_view.rb 0 → 100644
@@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
  1 +class AnalyticsPlugin::PageView < ActiveRecord::Base
  2 +
  3 + serialize :data
  4 +
  5 + attr_accessible *self.column_names
  6 + attr_accessible :user, :profile
  7 +
  8 + attr_accessor :request
  9 + attr_accessible :request
  10 +
  11 + acts_as_having_settings field: :options
  12 +
  13 + belongs_to :visit, class_name: 'AnalyticsPlugin::Visit'
  14 + belongs_to :referer_page_view, class_name: 'AnalyticsPlugin::PageView'
  15 +
  16 + belongs_to :user, class_name: 'Person'
  17 + belongs_to :session, primary_key: :session_id, foreign_key: :session_id, class_name: 'Session'
  18 + belongs_to :profile
  19 +
  20 + validates_presence_of :visit
  21 + validates_presence_of :request, on: :create
  22 + validates_presence_of :url
  23 +
  24 + before_validation :extract_request_data, on: :create
  25 + before_validation :fill_referer_page_view, on: :create
  26 + before_validation :fill_visit, on: :create
  27 +
  28 + def request_duration
  29 + self.request_finished_at - self.request_started_at
  30 + end
  31 +
  32 + def page_load!
  33 + self.page_loaded_at = Time.now
  34 + self.update_column :page_loaded_at, self.page_loaded_at
  35 + end
  36 +
  37 + def increase_time_on_page!
  38 + now = Time.now
  39 + initial_time = self.page_loaded_at || self.request_finished_at
  40 + return unless now > initial_time
  41 +
  42 + self.time_on_page = now - initial_time
  43 + self.update_column :time_on_page, self.time_on_page
  44 + end
  45 +
  46 + protected
  47 +
  48 + def extract_request_data
  49 + self.url = self.request.url.sub /\/+$/, ''
  50 + self.referer_url = self.request.referer
  51 + self.user_agent = self.request.headers['User-Agent']
  52 + self.request_id = self.request.env['action_dispatch.request_id']
  53 + self.remote_ip = self.request.remote_ip
  54 + end
  55 +
  56 + def fill_referer_page_view
  57 + self.referer_page_view = AnalyticsPlugin::PageView.order('request_started_at DESC').
  58 + where(url: self.referer_url, session_id: self.session_id, user_id: self.user_id, profile_id: self.profile_id).first if self.referer_url.present?
  59 + end
  60 +
  61 + def fill_visit
  62 + self.visit = self.referer_page_view.visit if self.referer_page_view
  63 + self.visit ||= AnalyticsPlugin::Visit.new profile: profile
  64 + end
  65 +
  66 +end
  67 +
plugins/analytics/models/analytics_plugin/visit.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class AnalyticsPlugin::Visit < ActiveRecord::Base
  2 +
  3 + attr_accessible *self.column_names
  4 + attr_accessible :profile
  5 +
  6 + default_scope -> { includes :page_views }
  7 +
  8 + belongs_to :profile
  9 + has_many :page_views, class_name: 'AnalyticsPlugin::PageView', dependent: :destroy
  10 +
  11 +end
plugins/analytics/po/pt/analytics.po 0 → 100644
@@ -0,0 +1,29 @@ @@ -0,0 +1,29 @@
  1 +# translation of analytic.po to portuguese
  2 +# Krishnamurti Lelis Lima Vieira Nunes <krishna@colivre.coop.br>, 2007.
  3 +# noosfero - Brazilian Portuguese translation
  4 +# Copyright (C) 2007,
  5 +# Forum Brasileiro de Economia Solidaria <http://www.fbes.org.br/>
  6 +# Copyright (C) 2007,
  7 +# Ynternet.org Foundation <http://www.ynternet.org/>
  8 +# This file is distributed under the same license as noosfero itself.
  9 +# Joenio Costa <joenio@colivre.coop.br>, 2008.
  10 +#
  11 +#
  12 +msgid ""
  13 +msgstr ""
  14 +"Project-Id-Version: 1.0-690-gcb6e853\n"
  15 +"POT-Creation-Date: 2015-03-05 12:10-0300\n"
  16 +"PO-Revision-Date: 2015-07-21 09:23-0300\n"
  17 +"Last-Translator: Michal Čihař <michal@cihar.com>\n"
  18 +"Language-Team: Portuguese <https://hosted.weblate.org/projects/noosfero"
  19 +"/plugin-solr/pt/>\n"
  20 +"Language: pt\n"
  21 +"MIME-Version: 1.0\n"
  22 +"Content-Type: text/plain; charset=UTF-8\n"
  23 +"Content-Transfer-Encoding: 8bit\n"
  24 +"Plural-Forms: nplurals=2; plural=n != 1;\n"
  25 +"X-Generator: Weblate 2.3-dev\n"
  26 +
  27 +msgid "Select the set of communities and users to track"
  28 +msgstr "Seleciona o conjunto de comunidades e usuários para rastrear"
  29 +
plugins/analytics/public/javascripts/analytics.js 0 → 100644
@@ -0,0 +1,39 @@ @@ -0,0 +1,39 @@
  1 +analytics = {
  2 + requestId: '',
  3 +
  4 + timeOnPage: {
  5 + updateInterval: 0,
  6 + baseUrl: '',
  7 +
  8 + report: function() {
  9 + $.ajax(analytics.timeOnPage.baseUrl+'/report', {
  10 + type: 'POST', data: {id: analytics.requestId},
  11 + success: function(data) {
  12 +
  13 + analytics.timeOnPage.poll()
  14 + },
  15 + })
  16 + },
  17 +
  18 + poll: function() {
  19 + if (analytics.timeOnPage.updateInterval)
  20 + setTimeout(analytics.timeOnPage.report, analytics.timeOnPage.updateInterval)
  21 + },
  22 + },
  23 +
  24 + init: function() {
  25 + analytics.timeOnPage.poll()
  26 + },
  27 +
  28 + pageLoad: function() {
  29 + $.ajax(analytics.timeOnPage.baseUrl+'/page_load', {
  30 + type: 'POST', data: {id: analytics.requestId},
  31 + success: function(data) {
  32 + },
  33 + });
  34 + }
  35 +
  36 +};
  37 +
  38 +$(document).ready(analytics.pageLoad)
  39 +
plugins/analytics/test/functional/content_viewer_controller_test.rb 0 → 100644
@@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
  1 +require 'test_helper'
  2 +require 'content_viewer_controller'
  3 +
  4 +class ContentViewerControllerTest < ActionController::TestCase
  5 +
  6 + def setup
  7 + @controller = ContentViewerController.new
  8 + @request = ActionController::TestRequest.new
  9 + @response = ActionController::TestResponse.new
  10 +
  11 + @environment = Environment.default
  12 + @environment.enabled_plugins += ['AnalyticsPlugin']
  13 + @environment.save!
  14 +
  15 + @user = create_user('testinguser').person
  16 + login_as @user.identifier
  17 +
  18 + @community = build Community, identifier: 'testcomm', name: 'test'
  19 + @community.analytics_settings.enabled = true
  20 + @community.analytics_settings.anonymous = false
  21 + @community.save!
  22 + @community.add_member @user
  23 + end
  24 +
  25 + should 'register page view correctly' do
  26 + @request.env['HTTP_REFERER'] = 'http://google.com'
  27 + first_url = 'http://test.host'
  28 + get :view_page, profile: @community.identifier, page: []
  29 + assert_equal 1, @community.page_views.count
  30 + assert_equal 1, @community.visits.count
  31 +
  32 + first_page_view = @community.page_views.order(:id).first
  33 + assert_equal @request.referer, first_page_view.referer_url
  34 +
  35 + @request.env['HTTP_REFERER'] = first_url
  36 + get :view_page, profile: @community.identifier, page: @community.articles.last.path.split('/')
  37 + assert_equal 2, @community.page_views.count
  38 + assert_equal 1, @community.visits.count
  39 +
  40 + second_page_view = @community.page_views.order(:id).last
  41 + assert_equal first_page_view, second_page_view.referer_page_view
  42 +
  43 + assert_equal @user, second_page_view.user
  44 +
  45 + assert second_page_view.request_duration > 0 and second_page_view.request_duration < 1
  46 + end
  47 +
  48 +end
plugins/analytics/views/analytics_plugin/_body_ending.html.slim 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +javascript:
  2 + analytics.timeOnPage.baseUrl = #{url_for(controller: 'analytics_plugin/time_on_page').to_json}
  3 + analytics.timeOnPage.updateInterval = #{AnalyticsPlugin::TimeOnPageUpdateInterval.to_json}
  4 + analytics.requestId = #{request.env['action_dispatch.request_id'].to_json}
  5 + analytics.init()
  6 +
plugins/comment_classification/po/fr/comment_classification.po
@@ -7,8 +7,8 @@ msgstr &quot;&quot; @@ -7,8 +7,8 @@ msgstr &quot;&quot;
7 "Project-Id-Version: 1.1-166-gaf47713\n" 7 "Project-Id-Version: 1.1-166-gaf47713\n"
8 "Report-Msgid-Bugs-To: \n" 8 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2015-06-01 17:26-0300\n" 9 "POT-Creation-Date: 2015-06-01 17:26-0300\n"
10 -"PO-Revision-Date: 2015-07-03 00:34+0200\n"  
11 -"Last-Translator: Christophe DANIEL <papaeng@gmail.com>\n" 10 +"PO-Revision-Date: 2015-03-07 12:26+0200\n"
  11 +"Last-Translator: Tuux <tuxa@galaxie.eu.org>\n"
12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-" 12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-"
13 "comment-classification/fr/>\n" 13 "comment-classification/fr/>\n"
14 "Language: fr\n" 14 "Language: fr\n"
@@ -16,7 +16,7 @@ msgstr &quot;&quot; @@ -16,7 +16,7 @@ msgstr &quot;&quot;
16 "Content-Type: text/plain; charset=UTF-8\n" 16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n" 17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=2; plural=n > 1;\n" 18 "Plural-Forms: nplurals=2; plural=n > 1;\n"
19 -"X-Generator: Weblate 2.4-dev\n" 19 +"X-Generator: Weblate 2.3-dev\n"
20 20
21 #: plugins/comment_classification/lib/comment_classification_plugin.rb:11 21 #: plugins/comment_classification/lib/comment_classification_plugin.rb:11
22 msgid "A plugin that allow classification of comments." 22 msgid "A plugin that allow classification of comments."
@@ -80,7 +80,7 @@ msgstr &quot;Statuts&quot; @@ -80,7 +80,7 @@ msgstr &quot;Statuts&quot;
80 80
81 #: plugins/comment_classification/views/comment_classification_plugin_myprofile/_status_form.html.erb:7 81 #: plugins/comment_classification/views/comment_classification_plugin_myprofile/_status_form.html.erb:7
82 msgid "Reason:" 82 msgid "Reason:"
83 -msgstr "Raison :" 83 +msgstr "Raison:"
84 84
85 #: plugins/comment_classification/views/comment_classification_plugin_myprofile/add_status.html.erb:1 85 #: plugins/comment_classification/views/comment_classification_plugin_myprofile/add_status.html.erb:1
86 msgid "Status for comment" 86 msgid "Status for comment"
@@ -121,7 +121,7 @@ msgstr &quot;Couleur&quot; @@ -121,7 +121,7 @@ msgstr &quot;Couleur&quot;
121 121
122 #: plugins/comment_classification/views/comment_classification_plugin_labels/_form.html.erb:8 122 #: plugins/comment_classification/views/comment_classification_plugin_labels/_form.html.erb:8
123 msgid "Enable this label?" 123 msgid "Enable this label?"
124 -msgstr "Activer ce label ?" 124 +msgstr "Activer ce label?"
125 125
126 #: plugins/comment_classification/views/comment_classification_plugin_labels/edit.html.erb:1 126 #: plugins/comment_classification/views/comment_classification_plugin_labels/edit.html.erb:1
127 msgid "Editing label %s" 127 msgid "Editing label %s"
@@ -149,7 +149,7 @@ msgstr &quot;Label&quot; @@ -149,7 +149,7 @@ msgstr &quot;Label&quot;
149 #: plugins/comment_classification/views/comment_classification_plugin_labels/index.html.erb:11 149 #: plugins/comment_classification/views/comment_classification_plugin_labels/index.html.erb:11
150 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:10 150 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:10
151 msgid "Enabled" 151 msgid "Enabled"
152 -msgstr "Activé(e)" 152 +msgstr "Activé"
153 153
154 #: plugins/comment_classification/views/comment_classification_plugin_labels/index.html.erb:12 154 #: plugins/comment_classification/views/comment_classification_plugin_labels/index.html.erb:12
155 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:12 155 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:12
@@ -162,7 +162,7 @@ msgstr &quot;Êtes-vous sûr(e) que vous voulez retirer ce label ?&quot; @@ -162,7 +162,7 @@ msgstr &quot;Êtes-vous sûr(e) que vous voulez retirer ce label ?&quot;
162 162
163 #: plugins/comment_classification/views/comment_classification_plugin_status/_form.html.erb:7 163 #: plugins/comment_classification/views/comment_classification_plugin_status/_form.html.erb:7
164 msgid "Enable this status?" 164 msgid "Enable this status?"
165 -msgstr "Activer ce statut ?" 165 +msgstr "Activer ce statut?"
166 166
167 #: plugins/comment_classification/views/comment_classification_plugin_status/edit.html.erb:1 167 #: plugins/comment_classification/views/comment_classification_plugin_status/edit.html.erb:1
168 msgid "Editing status %s" 168 msgid "Editing status %s"
@@ -177,12 +177,13 @@ msgid &quot;(no status registered yet)&quot; @@ -177,12 +177,13 @@ msgid &quot;(no status registered yet)&quot;
177 msgstr "(il n'y a pas de statut enregistré pour le moment)" 177 msgstr "(il n'y a pas de statut enregistré pour le moment)"
178 178
179 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:11 179 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:11
  180 +#, fuzzy
180 msgid "Reason enabled?" 181 msgid "Reason enabled?"
181 -msgstr "Raison activée ?" 182 +msgstr "%s n'était pas activé(e)"
182 183
183 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:21 184 #: plugins/comment_classification/views/comment_classification_plugin_status/index.html.erb:21
184 msgid "Are you sure you want to remove this status?" 185 msgid "Are you sure you want to remove this status?"
185 -msgstr "Êtes-vous sûr(e) de vouloir supprimer ce statut ?" 186 +msgstr "Êtes-vous sûr(e) de vouloir supprimer ce statut?"
186 187
187 #: plugins/comment_classification/views/comment/comments_labels_select.html.erb:3 188 #: plugins/comment_classification/views/comment/comments_labels_select.html.erb:3
188 msgid "[Select ...]" 189 msgid "[Select ...]"
plugins/community_hub/Gemfile
  1 +source 'https://rubygems.org'
1 gem 'twitter', '~> 5.8.0' 2 gem 'twitter', '~> 5.8.0'
2 gem 'proxifier', '~> 1.0.3' 3 gem 'proxifier', '~> 1.0.3'
plugins/community_track/lib/community_track_plugin/step.rb
@@ -76,20 +76,20 @@ class CommunityTrackPlugin::Step &lt; Folder @@ -76,20 +76,20 @@ class CommunityTrackPlugin::Step &lt; Folder
76 end 76 end
77 77
78 def active? 78 def active?
79 - (start_date..end_date).include?(Date.today) 79 + (start_date.to_date..end_date.to_date).include?(Date.today)
80 end 80 end
81 81
82 def finished? 82 def finished?
83 - Date.today > end_date 83 + Date.today > end_date.to_date
84 end 84 end
85 85
86 def waiting? 86 def waiting?
87 - Date.today < start_date 87 + Date.today < start_date.to_date
88 end 88 end
89 89
90 def schedule_activation 90 def schedule_activation
91 return if !changes['start_date'] && !changes['end_date'] 91 return if !changes['start_date'] && !changes['end_date']
92 - if Date.today <= end_date || accept_comments 92 + if Date.today <= end_date.to_date || accept_comments
93 schedule_date = !accept_comments ? start_date : end_date + 1.day 93 schedule_date = !accept_comments ? start_date : end_date + 1.day
94 CommunityTrackPlugin::ActivationJob.find(id).destroy_all 94 CommunityTrackPlugin::ActivationJob.find(id).destroy_all
95 Delayed::Job.enqueue(CommunityTrackPlugin::ActivationJob.new(self.id), :run_at => schedule_date) 95 Delayed::Job.enqueue(CommunityTrackPlugin::ActivationJob.new(self.id), :run_at => schedule_date)
plugins/custom_forms/po/fr/custom_forms.po
@@ -7,7 +7,7 @@ msgstr &quot;&quot; @@ -7,7 +7,7 @@ msgstr &quot;&quot;
7 "Project-Id-Version: 1.1-166-gaf47713\n" 7 "Project-Id-Version: 1.1-166-gaf47713\n"
8 "Report-Msgid-Bugs-To: \n" 8 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2015-06-01 17:26-0300\n" 9 "POT-Creation-Date: 2015-06-01 17:26-0300\n"
10 -"PO-Revision-Date: 2015-07-03 00:36+0200\n" 10 +"PO-Revision-Date: 2015-06-29 14:17+0200\n"
11 "Last-Translator: Christophe DANIEL <papaeng@gmail.com>\n" 11 "Last-Translator: Christophe DANIEL <papaeng@gmail.com>\n"
12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-" 12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-"
13 "custom-forms/fr/>\n" 13 "custom-forms/fr/>\n"
@@ -20,12 +20,13 @@ msgstr &quot;&quot; @@ -20,12 +20,13 @@ msgstr &quot;&quot;
20 20
21 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:67 21 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:67
22 msgid "Invalid string format of access." 22 msgid "Invalid string format of access."
23 -msgstr "Format de chaîne d'accès non valide." 23 +msgstr ""
24 24
25 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:71 25 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:71
26 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:76 26 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:76
  27 +#, fuzzy
27 msgid "There is no profile with the provided id." 28 msgid "There is no profile with the provided id."
28 -msgstr "Il n'y a pas le profil avec l'ID fourni." 29 +msgstr "Il y a un problème avec les lignes suivantes : "
29 30
30 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:81 31 #: plugins/custom_forms/lib/custom_forms_plugin/form.rb:81
31 msgid "Invalid type format of access." 32 msgid "Invalid type format of access."
plugins/display_content/po/fr/display_content.po
@@ -7,8 +7,8 @@ msgstr &quot;&quot; @@ -7,8 +7,8 @@ msgstr &quot;&quot;
7 "Project-Id-Version: 1.1-166-gaf47713\n" 7 "Project-Id-Version: 1.1-166-gaf47713\n"
8 "Report-Msgid-Bugs-To: \n" 8 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2015-06-01 17:26-0300\n" 9 "POT-Creation-Date: 2015-06-01 17:26-0300\n"
10 -"PO-Revision-Date: 2015-07-03 00:31+0200\n"  
11 -"Last-Translator: Christophe DANIEL <papaeng@gmail.com>\n" 10 +"PO-Revision-Date: 2015-03-07 02:11+0200\n"
  11 +"Last-Translator: Tuux <tuxa@galaxie.eu.org>\n"
12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-" 12 "Language-Team: French <https://hosted.weblate.org/projects/noosfero/plugin-"
13 "display-content/fr/>\n" 13 "display-content/fr/>\n"
14 "Language: fr\n" 14 "Language: fr\n"
@@ -16,14 +16,14 @@ msgstr &quot;&quot; @@ -16,14 +16,14 @@ msgstr &quot;&quot;
16 "Content-Type: text/plain; charset=UTF-8\n" 16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n" 17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=2; plural=n > 1;\n" 18 "Plural-Forms: nplurals=2; plural=n > 1;\n"
19 -"X-Generator: Weblate 2.4-dev\n" 19 +"X-Generator: Weblate 2.3-dev\n"
20 20
21 #: plugins/display_content/lib/display_content_plugin.rb:10 21 #: plugins/display_content/lib/display_content_plugin.rb:10
22 msgid "" 22 msgid ""
23 "A plugin that adds a block where you could choose any of your content and " 23 "A plugin that adds a block where you could choose any of your content and "
24 "display it." 24 "display it."
25 msgstr "" 25 msgstr ""
26 -"Un plugin qui permet d'ajouter une zone ou vous pourrez y afficher le " 26 +"Un greffon qui permet d'ajouter une zone ou vous pourrez y afficher le "
27 "contenue de votre choix." 27 "contenue de votre choix."
28 28
29 #: plugins/display_content/lib/display_content_block.rb:34 29 #: plugins/display_content/lib/display_content_block.rb:34
@@ -48,33 +48,33 @@ msgstr &quot;Résumé&quot; @@ -48,33 +48,33 @@ msgstr &quot;Résumé&quot;
48 48
49 #: plugins/display_content/lib/display_content_block.rb:151 49 #: plugins/display_content/lib/display_content_block.rb:151
50 msgid "Read more" 50 msgid "Read more"
51 -msgstr "Lire plus" 51 +msgstr "En lire plus"
52 52
53 #: plugins/display_content/lib/display_content_block.rb:194 53 #: plugins/display_content/lib/display_content_block.rb:194
54 msgid "%{month}/%{day}/%{year}" 54 msgid "%{month}/%{day}/%{year}"
55 -msgstr "%{day}/%{month}/%{year}" 55 +msgstr "%{mois}/%{jour}/%{année}"
56 56
57 #: plugins/display_content/lib/display_content_block.rb:194 57 #: plugins/display_content/lib/display_content_block.rb:194
58 msgid "%{month}/%{day}" 58 msgid "%{month}/%{day}"
59 -msgstr "%{day}/%{month}" 59 +msgstr "%{mois}/%{jour}"
60 60
61 #: plugins/display_content/lib/display_content_block.rb:197 61 #: plugins/display_content/lib/display_content_block.rb:197
62 msgid "%{month_name} %{day}, %{year}" 62 msgid "%{month_name} %{day}, %{year}"
63 -msgstr "%{day} %{month_name} %{year}" 63 +msgstr "%{nom_du_mois} %{jour}, %{année}"
64 64
65 #: plugins/display_content/lib/display_content_block.rb:197 65 #: plugins/display_content/lib/display_content_block.rb:197
66 msgid "%{month_name} %{day}" 66 msgid "%{month_name} %{day}"
67 -msgstr "%{day} %{month_name}" 67 +msgstr "%{nom_du_mois} %{jour}"
68 68
69 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:5 69 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:5
70 msgid "Choose which attributes should be displayed and drag to reorder them:" 70 msgid "Choose which attributes should be displayed and drag to reorder them:"
71 msgstr "" 71 msgstr ""
72 "Choisissez quels attribues doivent êtres afficher et glisser/déposer pour " 72 "Choisissez quels attribues doivent êtres afficher et glisser/déposer pour "
73 -"les réorganiser :" 73 +"les réorganiser:"
74 74
75 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:21 75 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:21
76 msgid "Choose which content should be displayed:" 76 msgid "Choose which content should be displayed:"
77 -msgstr "Choisissez le contenu à afficher :" 77 +msgstr "Choisissez le contenu à afficher:"
78 78
79 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:23 79 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:23
80 msgid "Choose directly" 80 msgid "Choose directly"
@@ -86,7 +86,7 @@ msgstr &quot;Choisir par type de contenu&quot; @@ -86,7 +86,7 @@ msgstr &quot;Choisir par type de contenu&quot;
86 86
87 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:28 87 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:28
88 msgid "Order by:" 88 msgid "Order by:"
89 -msgstr "Trier par :" 89 +msgstr "Trier par:"
90 90
91 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:29 91 #: plugins/display_content/views/box_organizer/_display_content_block.html.erb:29
92 msgid "Most recent" 92 msgid "Most recent"
@@ -98,7 +98,7 @@ msgstr &quot;Le plus ancien&quot; @@ -98,7 +98,7 @@ msgstr &quot;Le plus ancien&quot;
98 98
99 #: plugins/display_content/views/box_organizer/_choose_by_content_type.html.erb:1 99 #: plugins/display_content/views/box_organizer/_choose_by_content_type.html.erb:1
100 msgid "Display content types:" 100 msgid "Display content types:"
101 -msgstr "Afficher le type de contenu :" 101 +msgstr "Afficher le types de contenue:"
102 102
103 #: plugins/display_content/views/box_organizer/_choose_by_content_type.html.erb:7 103 #: plugins/display_content/views/box_organizer/_choose_by_content_type.html.erb:7
104 msgid "more" 104 msgid "more"
@@ -106,8 +106,9 @@ msgstr &quot;plus&quot; @@ -106,8 +106,9 @@ msgstr &quot;plus&quot;
106 106
107 #: plugins/display_content/views/box_organizer/_choose_directly.html.erb:5 107 #: plugins/display_content/views/box_organizer/_choose_directly.html.erb:5
108 msgid "Dinamically load children of selected folders" 108 msgid "Dinamically load children of selected folders"
109 -msgstr "charger dynamiquement les sous répertoires des répertoires sélectionnés" 109 +msgstr ""
  110 +"Dynamiquement charger les sous répertoires des répertoires sélectionnés"
110 111
111 #: plugins/display_content/views/box_organizer/_choose_directly.html.erb:9 112 #: plugins/display_content/views/box_organizer/_choose_directly.html.erb:9
112 msgid "Limit:" 113 msgid "Limit:"
113 -msgstr "Limite :" 114 +msgstr "Limite:"
plugins/gamification
1 -Subproject commit 1f2171520eb4719fefc5a32f26ef2a002cd61f0d 1 +Subproject commit 7a9aa2a643ccbbe6d4ee2f085a5a15540a6b349d
plugins/gravatar-provider 0 → 160000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +Subproject commit 7d1cef867e1325f623638366faeb5387a9261b0a
plugins/juventude 0 → 160000
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +Subproject commit 8fb44a478abb5ccd345b8ffaf1f37817d273ad30
plugins/oauth_client/Gemfile
  1 +source 'https://rubygems.org'
1 gem 'omniauth', '~> 1.2.2' 2 gem 'omniauth', '~> 1.2.2'
2 gem 'omniauth-facebook', '~> 2.0.0' 3 gem 'omniauth-facebook', '~> 2.0.0'
3 gem "omniauth-google-oauth2", '~> 0.2.6' 4 gem "omniauth-google-oauth2", '~> 0.2.6'
plugins/oauth_client/controllers/public/oauth_client_plugin_public_controller.rb
@@ -22,7 +22,7 @@ class OauthClientPluginPublicController &lt; PublicController @@ -22,7 +22,7 @@ class OauthClientPluginPublicController &lt; PublicController
22 if session.delete(:oauth_client_popup) || params[:oauth_client_popup] 22 if session.delete(:oauth_client_popup) || params[:oauth_client_popup]
23 current_user.private_token_expired? if current_user.present? 23 current_user.private_token_expired? if current_user.present?
24 private_token = current_user.present? ? current_user.private_token : '' 24 private_token = current_user.present? ? current_user.private_token : ''
25 - render 'oauth_client_plugin_public/finish', :locals => {:private_token => private_token, :user => params[:user]}, :layout => false 25 + render 'oauth_client_plugin_public/finish', :locals => {:private_token => private_token}, :layout => false
26 else 26 else
27 redirect_to :controller => :home 27 redirect_to :controller => :home
28 end 28 end
@@ -42,22 +42,47 @@ class OauthClientPluginPublicController &lt; PublicController @@ -42,22 +42,47 @@ class OauthClientPluginPublicController &lt; PublicController
42 else 42 else
43 session[:notice] = _("Can't login with #{provider.name}") 43 session[:notice] = _("Can't login with #{provider.name}")
44 end 44 end
45 - session[:oauth_client_popup] = true if request.env["omniauth.params"]['oauth_client_popup']  
46 - session[:return_to] = url_for(:controller => :oauth_client_plugin_public, :action => :finish) 45 + session[:oauth_client_popup] = true if request.env.fetch("omniauth.params", {})['oauth_client_popup']
  46 + session[:return_to] = url_for(
  47 + :controller => :oauth_client_plugin_public,
  48 + :action => :finish,
  49 + :user => {
  50 + :login => current_user.login,
  51 + :person => {:identifier => current_user.person.identifier, :name => current_user.person.name}
  52 + } ,
  53 + :profile_data => {:name => current_user.person.name},
  54 + :oauth_client_popup => session[:oauth_client_popup]
  55 + )
47 56
48 redirect_to :controller => :account, :action => :login 57 redirect_to :controller => :account, :action => :login
49 end 58 end
50 59
51 def signup(auth) 60 def signup(auth)
52 login = auth.info.email.split('@').first 61 login = auth.info.email.split('@').first
  62 +
  63 + # reading provider from session and writing to cache to read when
  64 + # api calls register to confirm signup
  65 + auth_cach_hash = auth.to_hash
  66 + auth_cach_hash[:provider_id] = session[:provider_id]
  67 + signup_token = OauthClientPlugin::SignupDataStore.store_oauth_data(auth.info.email, auth_cach_hash)
  68 +
53 session[:oauth_data] = auth 69 session[:oauth_data] = auth
54 - session[:oauth_client_popup] = true if request.env["omniauth.params"]['oauth_client_popup'] 70 + session[:oauth_client_popup] = true if request.env.fetch("omniauth.params", {})['oauth_client_popup']
55 session[:return_to] = url_for(:controller => :oauth_client_plugin_public, :action => :finish) 71 session[:return_to] = url_for(:controller => :oauth_client_plugin_public, :action => :finish)
56 name = auth.info.name 72 name = auth.info.name
57 name ||= auth.extra && auth.extra.raw_info ? auth.extra.raw_info.name : '' 73 name ||= auth.extra && auth.extra.raw_info ? auth.extra.raw_info.name : ''
58 74
59 if session[:oauth_client_popup] 75 if session[:oauth_client_popup]
60 - redirect_to :controller => :oauth_client_plugin_public, :action => :finish, :user => {:login => login, :email => auth.info.email, :oauth_providers => [session[:provider_id]]}, :profile_data => {:name => name}, :oauth_client_popup => session[:oauth_client_popup] 76 + redirect_to :controller => :oauth_client_plugin_public,
  77 + :action => :finish,
  78 + :user => {
  79 + :signup_token => signup_token,
  80 + :login => login,
  81 + :email => auth.info.email,
  82 + :oauth_providers => [session[:provider_id]]
  83 + },
  84 + :profile_data => {:name => name},
  85 + :oauth_client_popup => session[:oauth_client_popup]
61 else 86 else
62 redirect_to :controller => :account, :action => :signup, :user => {:login => login, :email => auth.info.email}, :profile_data => {:name => name} 87 redirect_to :controller => :account, :action => :signup, :user => {:login => login, :email => auth.info.email}, :profile_data => {:name => name}
63 end 88 end
plugins/oauth_client/db/migrate/20150714200000_add_oauth_auth_fields_to_user_provider.rb 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +class AddOauthAuthFieldsToUserProvider < ActiveRecord::Migration
  2 +
  3 + def self.up
  4 + change_table :oauth_client_plugin_user_providers do |t|
  5 + t.text :oauth_data
  6 + end
  7 + end
  8 +
  9 + def self.down
  10 + remove_column :oauth_client_plugin_user_providers, :oauth_data
  11 + end
  12 +end
plugins/oauth_client/lib/ext/environment.rb
@@ -4,4 +4,10 @@ class Environment @@ -4,4 +4,10 @@ class Environment
4 4
5 has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider' 5 has_many :oauth_providers, :class_name => 'OauthClientPlugin::Provider'
6 6
  7 + def signup_person_fields_with_oauth
  8 + signup_person_fields_without_oauth + [:oauth_signup_token]
  9 + end
  10 +
  11 + alias_method_chain :signup_person_fields, :oauth
  12 +
7 end 13 end
plugins/oauth_client/lib/ext/user.rb
@@ -6,24 +6,54 @@ class User @@ -6,24 +6,54 @@ class User
6 has_many :oauth_providers, :through => :oauth_user_providers, :source => :provider 6 has_many :oauth_providers, :through => :oauth_user_providers, :source => :provider
7 7
8 def password_required_with_oauth? 8 def password_required_with_oauth?
  9 + # user creation through api does not set oauth_providers
  10 + check_providers
9 password_required_without_oauth? && oauth_providers.empty? 11 password_required_without_oauth? && oauth_providers.empty?
10 end 12 end
11 13
  14 + def oauth_data
  15 + @oauth_data
  16 + end
  17 +
  18 + def oauth_signup_token= value
  19 + @oauth_signup_token = value
  20 + end
  21 +
  22 + def oauth_signup_token
  23 + @oauth_signup_token
  24 + end
  25 +
12 alias_method_chain :password_required?, :oauth 26 alias_method_chain :password_required?, :oauth
13 27
14 after_create :activate_oauth_user 28 after_create :activate_oauth_user
15 29
  30 + # user creation through api does not set oauth_providers
  31 + # so it is being shared through a distributed cache
  32 + def check_providers
  33 + if oauth_providers.empty? && oauth_signup_token.present?
  34 + #check if is oauth user, reading oauth_data recorded at cache store
  35 + @oauth_data = OauthClientPlugin::SignupDataStore.get_oauth_data(self.email, self.oauth_signup_token)
  36 + if @oauth_data
  37 + provider_id = @oauth_data.delete(:provider_id)
  38 + self.oauth_providers = [OauthClientPlugin::Provider.find(provider_id)]
  39 + end
  40 + end
  41 + end
  42 +
16 def activate_oauth_user 43 def activate_oauth_user
17 - unless oauth_providers.empty?  
18 - activate  
19 - oauth_providers.each do |provider|  
20 - OauthClientPlugin::UserProvider.create!(:user => self, :provider => provider, :enabled => true) 44 + self.oauth_providers.each do |provider|
  45 + OauthClientPlugin::UserProvider.create! do |user_provider|
  46 + user_provider.user = self
  47 + user_provider.provider = provider
  48 + user_provider.enabled = true
  49 + user_provider.oauth_data = oauth_data
21 end 50 end
22 end 51 end
  52 + activate unless oauth_providers.empty?
23 end 53 end
24 54
25 def make_activation_code_with_oauth 55 def make_activation_code_with_oauth
26 - oauth_providers.blank? ? make_activation_code_without_oauth : nil 56 + self.oauth_providers.blank? ? make_activation_code_without_oauth : nil
27 end 57 end
28 58
29 alias_method_chain :make_activation_code, :oauth 59 alias_method_chain :make_activation_code, :oauth
plugins/oauth_client/lib/oauth_client_plugin.rb
@@ -84,8 +84,11 @@ class OauthClientPlugin &lt; Noosfero::Plugin @@ -84,8 +84,11 @@ class OauthClientPlugin &lt; Noosfero::Plugin
84 84
85 if auth.present? && params[:user].present? 85 if auth.present? && params[:user].present?
86 params[:user][:oauth_providers] = [OauthClientPlugin::Provider.find(session[:provider_id])] 86 params[:user][:oauth_providers] = [OauthClientPlugin::Provider.find(session[:provider_id])]
  87 +
87 if request.post? && auth.info.email != params[:user][:email] 88 if request.post? && auth.info.email != params[:user][:email]
88 - raise "Wrong email for oauth signup" 89 + unless params[:user][:email].blank?
  90 + raise "Wrong email for oauth signup. EMAIL: #{params[:user][:email]}"
  91 + end
89 end 92 end
90 end 93 end
91 } 94 }
plugins/oauth_client/lib/oauth_client_plugin/signup_data_store.rb 0 → 100644
@@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
  1 +# A Distributed Cache Store is needed
  2 +# to save oauth autenthication to be
  3 +# used on OAUTH flow using the Noosfero REST API.
  4 +# Because of the nature session less of api implementation
  5 +# When using more than one server is strongly recomended
  6 +# provide your Rails application with a distributed Cache Store,
  7 +# otherwise you will have to rely on client/server affinify provided by
  8 +# network infrastructure
  9 +class OauthClientPlugin::SignupDataStore
  10 +
  11 + def self.key_name_for email, signup_token
  12 + "#{email}_#{signup_token}"
  13 + end
  14 +
  15 + def self.get_oauth_data email, signup_token
  16 + key_name = key_name_for(email, signup_token)
  17 + puts "OAUTH_KEY_NAME :::: #{key_name}"
  18 + oauth_data = Rails.cache.fetch(key_name)
  19 + Rails.cache.delete(key_name)
  20 + oauth_data
  21 + end
  22 +
  23 + def self.store_oauth_data email, auth_obj
  24 + signup_token = SecureRandom.hex
  25 + Rails.cache.write(key_name_for(email, signup_token), auth_obj, :expires_in => 300)
  26 + signup_token
  27 + end
  28 +
  29 + def self.delete_cache_for email
  30 + Rails.cache.delete(cache_name_for(email))
  31 + end
  32 +
  33 +
  34 +end
plugins/oauth_client/lib/oauth_client_plugin/user_provider.rb
@@ -7,4 +7,5 @@ class OauthClientPlugin::UserProvider &lt; Noosfero::Plugin::ActiveRecord @@ -7,4 +7,5 @@ class OauthClientPlugin::UserProvider &lt; Noosfero::Plugin::ActiveRecord
7 7
8 attr_accessible :user, :provider, :enabled 8 attr_accessible :user, :provider, :enabled
9 9
  10 + acts_as_having_settings :field => :oauth_data
10 end 11 end