Commit 3dc8df023056caf93bfcb2650acd8404c69031d3

Authored by Paulo Meireles
2 parents 7ad05188 32bddd99

Merge branch 'refactoring_controllers' into mezuro-dev

Showing 343 changed files with 10093 additions and 2279 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 343 files displayed.

INSTALL.varnish
@@ -15,6 +15,10 @@ Noosfero was tested with Varnish 2.x. If you are using a Debian Lenny (and you @@ -15,6 +15,10 @@ Noosfero was tested with Varnish 2.x. If you are using a Debian Lenny (and you
15 should, unless Debian already released Squeeze by now), make sure you install 15 should, unless Debian already released Squeeze by now), make sure you install
16 varnish from the lenny-backports suite. 16 varnish from the lenny-backports suite.
17 17
  18 +Install the RPAF apache module (or skip this step if not using apache):
  19 +
  20 + # apt-get install libapache2-mod-rpaf
  21 +
18 3) Enable varnish logging: 22 3) Enable varnish logging:
19 23
20 3a) Edit /etc/default/varnishncsa and uncomment the line that contains: 24 3a) Edit /etc/default/varnishncsa and uncomment the line that contains:
app/controllers/admin/users_controller.rb
@@ -7,11 +7,12 @@ class UsersController < AdminController @@ -7,11 +7,12 @@ class UsersController < AdminController
7 format.html 7 format.html
8 format.xml do 8 format.xml do
9 @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person]) 9 @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
10 - render :xml => @users.to_xml(  
11 - :skip_types => true,  
12 - :only => %w[email login created_at updated_at],  
13 - :include => { :person => {:only => %w[name updated_at created_at address birth_date contact_phone identifier lat lng] } }  
14 - ) 10 + send_data @users.to_xml(
  11 + :skip_types => true,
  12 + :only => %w[email login created_at updated_at],
  13 + :include => { :person => {:only => %w[name updated_at created_at address birth_date contact_phone identifier lat lng] } }),
  14 + :type => 'text/xml',
  15 + :disposition => "attachment; filename=users.xml"
15 end 16 end
16 format.csv do 17 format.csv do
17 @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person]) 18 @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
app/controllers/application_controller.rb
@@ -101,9 +101,10 @@ class ApplicationController < ActionController::Base @@ -101,9 +101,10 @@ class ApplicationController < ActionController::Base
101 end 101 end
102 end 102 end
103 103
  104 + include Noosfero::Plugin::HotSpot
  105 +
104 def init_noosfero_plugins 106 def init_noosfero_plugins
105 - @plugins = Noosfero::Plugin::Manager.new(self)  
106 - @plugins.each do |plugin| 107 + plugins.each do |plugin|
107 prepend_view_path(plugin.class.view_path) 108 prepend_view_path(plugin.class.view_path)
108 end 109 end
109 init_noosfero_plugins_controller_filters 110 init_noosfero_plugins_controller_filters
@@ -112,8 +113,10 @@ class ApplicationController < ActionController::Base @@ -112,8 +113,10 @@ class ApplicationController < ActionController::Base
112 # This is a generic method that initialize any possible filter defined by a 113 # This is a generic method that initialize any possible filter defined by a
113 # plugin to the current controller being initialized. 114 # plugin to the current controller being initialized.
114 def init_noosfero_plugins_controller_filters 115 def init_noosfero_plugins_controller_filters
115 - @plugins.each do |plugin|  
116 - plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| 116 + plugins.each do |plugin|
  117 + filters = plugin.send(self.class.name.underscore + '_filters')
  118 + filters = [filters] if !filters.kind_of?(Array)
  119 + filters.each do |plugin_filter|
117 self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) 120 self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {}))
118 self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) 121 self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block])
119 end 122 end
app/controllers/box_organizer_controller.rb
@@ -68,7 +68,8 @@ class BoxOrganizerController < ApplicationController @@ -68,7 +68,8 @@ class BoxOrganizerController < ApplicationController
68 raise ArgumentError.new("Type %s is not allowed. Go away." % type) 68 raise ArgumentError.new("Type %s is not allowed. Go away." % type)
69 end 69 end
70 else 70 else
71 - @block_types = available_blocks 71 + @center_block_types = Box.acceptable_center_blocks & available_blocks
  72 + @side_block_types = Box.acceptable_side_blocks & available_blocks
72 @boxes = boxes_holder.boxes 73 @boxes = boxes_holder.boxes
73 render :action => 'add_block', :layout => false 74 render :action => 'add_block', :layout => false
74 end 75 end
app/controllers/my_profile/profile_design_controller.rb
@@ -5,7 +5,7 @@ class ProfileDesignController < BoxOrganizerController @@ -5,7 +5,7 @@ class ProfileDesignController < BoxOrganizerController
5 protect 'edit_profile_design', :profile 5 protect 'edit_profile_design', :profile
6 6
7 def available_blocks 7 def available_blocks
8 - blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock ] 8 + blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ]
9 9
10 # blocks exclusive for organizations 10 # blocks exclusive for organizations
11 if profile.has_members? 11 if profile.has_members?
app/controllers/my_profile/profile_members_controller.rb
@@ -156,18 +156,4 @@ class ProfileMembersController < MyProfileController @@ -156,18 +156,4 @@ class ProfileMembersController < MyProfileController
156 end 156 end
157 end 157 end
158 158
159 - def send_mail  
160 - @mailing = profile.mailings.build(params[:mailing])  
161 - if request.post?  
162 - @mailing.locale = locale  
163 - @mailing.person = user  
164 - if @mailing.save  
165 - session[:notice] = _('The e-mails are being sent')  
166 - redirect_to :action => 'index'  
167 - else  
168 - session[:notice] = _('Could not create the e-mail')  
169 - end  
170 - end  
171 - end  
172 -  
173 end 159 end
app/controllers/my_profile/spam_controller.rb 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +class SpamController < MyProfileController
  2 +
  3 + protect :moderate_comments, :profile
  4 +
  5 + def index
  6 + if request.post?
  7 + begin
  8 + # FIXME duplicated logic
  9 + #
  10 + # This logic more or less replicates what is already in
  11 + # ContentViewerController#view_page,
  12 + # ContentViewerController#remove_comment and
  13 + # ContentViewerController#mark_comment_as_spam
  14 + if params[:remove_comment]
  15 + profile.comments_received.find(params[:remove_comment]).destroy
  16 + end
  17 + if params[:mark_comment_as_ham]
  18 + profile.comments_received.find(params[:mark_comment_as_ham]).ham!
  19 + end
  20 + if request.xhr?
  21 + json_response(true)
  22 + else
  23 + redirect_to :action => :index
  24 + end
  25 + rescue
  26 + json_response(false)
  27 + end
  28 + return
  29 + end
  30 +
  31 + @spam = profile.comments_received.spam.paginate({:page => params[:page]})
  32 + end
  33 +
  34 + protected
  35 +
  36 + def json_response(status)
  37 + render :text => {'ok' => status }.to_json, :content_type => 'application/json'
  38 + end
  39 +
  40 +end
app/controllers/public/account_controller.rb
@@ -25,11 +25,13 @@ class AccountController &lt; ApplicationController @@ -25,11 +25,13 @@ class AccountController &lt; ApplicationController
25 25
26 # action to perform login to the application 26 # action to perform login to the application
27 def login 27 def login
28 - @user = User.new  
29 - @person = @user.build_person  
30 store_location(request.referer) unless session[:return_to] 28 store_location(request.referer) unless session[:return_to]
31 return unless request.post? 29 return unless request.post?
32 - self.current_user = User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user] 30 +
  31 + self.current_user = plugins_alternative_authentication
  32 +
  33 + self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user]
  34 +
33 if logged_in? 35 if logged_in?
34 if params[:remember_me] == "1" 36 if params[:remember_me] == "1"
35 self.current_user.remember_me 37 self.current_user.remember_me
@@ -41,7 +43,6 @@ class AccountController &lt; ApplicationController @@ -41,7 +43,6 @@ class AccountController &lt; ApplicationController
41 end 43 end
42 else 44 else
43 session[:notice] = _('Incorrect username or password') if redirect? 45 session[:notice] = _('Incorrect username or password') if redirect?
44 - redirect_to :back if redirect?  
45 end 46 end
46 end 47 end
47 48
@@ -56,6 +57,11 @@ class AccountController &lt; ApplicationController @@ -56,6 +57,11 @@ class AccountController &lt; ApplicationController
56 57
57 # action to register an user to the application 58 # action to register an user to the application
58 def signup 59 def signup
  60 + if @plugins.dispatch(:allow_user_registration).include?(false)
  61 + redirect_back_or_default(:controller => 'home')
  62 + session[:notice] = _("This environment doesn't allow user registration.")
  63 + end
  64 +
59 @invitation_code = params[:invitation_code] 65 @invitation_code = params[:invitation_code]
60 begin 66 begin
61 if params[:user] 67 if params[:user]
@@ -125,6 +131,10 @@ class AccountController &lt; ApplicationController @@ -125,6 +131,10 @@ class AccountController &lt; ApplicationController
125 # 131 #
126 # Posts back. 132 # Posts back.
127 def forgot_password 133 def forgot_password
  134 + if @plugins.dispatch(:allow_password_recovery).include?(false)
  135 + redirect_back_or_default(:controller => 'home')
  136 + session[:notice] = _("This environment doesn't allow password recovery.")
  137 + end
128 @change_password = ChangePassword.new(params[:change_password]) 138 @change_password = ChangePassword.new(params[:change_password])
129 139
130 if request.post? 140 if request.post?
@@ -303,10 +313,27 @@ class AccountController &lt; ApplicationController @@ -303,10 +313,27 @@ class AccountController &lt; ApplicationController
303 end 313 end
304 314
305 def go_to_initial_page 315 def go_to_initial_page
306 - if environment == current_user.environment  
307 - redirect_back_or_default(user.admin_url) 316 + if environment.enabled?('allow_change_of_redirection_after_login')
  317 + case user.preferred_login_redirection
  318 + when 'keep_on_same_page'
  319 + redirect_back_or_default(user.admin_url)
  320 + when 'site_homepage'
  321 + redirect_to :controller => :home
  322 + when 'user_profile_page'
  323 + redirect_to user.public_profile_url
  324 + when 'user_homepage'
  325 + redirect_to user.url
  326 + when 'user_control_panel'
  327 + redirect_to user.admin_url
  328 + else
  329 + redirect_back_or_default(user.admin_url)
  330 + end
308 else 331 else
309 - redirect_back_or_default(:controller => 'home') 332 + if environment == current_user.environment
  333 + redirect_back_or_default(user.admin_url)
  334 + else
  335 + redirect_back_or_default(:controller => 'home')
  336 + end
310 end 337 end
311 end 338 end
312 339
@@ -316,4 +343,13 @@ class AccountController &lt; ApplicationController @@ -316,4 +343,13 @@ class AccountController &lt; ApplicationController
316 end 343 end
317 end 344 end
318 345
  346 + def plugins_alternative_authentication
  347 + user = nil
  348 + @plugins.each do |plugin|
  349 + user = plugin.alternative_authentication
  350 + break unless user.nil?
  351 + end
  352 + user
  353 + end
  354 +
319 end 355 end
app/controllers/public/content_viewer_controller.rb
@@ -2,6 +2,8 @@ class ContentViewerController &lt; ApplicationController @@ -2,6 +2,8 @@ class ContentViewerController &lt; ApplicationController
2 2
3 needs_profile 3 needs_profile
4 4
  5 + before_filter :comment_author, :only => :edit_comment
  6 +
5 helper ProfileHelper 7 helper ProfileHelper
6 helper TagsHelper 8 helper TagsHelper
7 9
@@ -19,7 +21,7 @@ class ContentViewerController &lt; ApplicationController @@ -19,7 +21,7 @@ class ContentViewerController &lt; ApplicationController
19 unless @page 21 unless @page
20 page_from_old_path = profile.articles.find_by_old_path(path) 22 page_from_old_path = profile.articles.find_by_old_path(path)
21 if page_from_old_path 23 if page_from_old_path
22 - redirect_to :profile => profile.identifier, :page => page_from_old_path.explode_path 24 + redirect_to profile.url.merge(:page => page_from_old_path.explode_path)
23 return 25 return
24 end 26 end
25 end 27 end
@@ -75,8 +77,14 @@ class ContentViewerController &lt; ApplicationController @@ -75,8 +77,14 @@ class ContentViewerController &lt; ApplicationController
75 @comment = Comment.new 77 @comment = Comment.new
76 end 78 end
77 79
78 - if request.post? && params[:remove_comment]  
79 - remove_comment 80 + if request.post?
  81 + if params[:remove_comment]
  82 + remove_comment
  83 + return
  84 + elsif params[:mark_comment_as_spam]
  85 + mark_comment_as_spam
  86 + return
  87 + end
80 end 88 end
81 89
82 if @page.has_posts? 90 if @page.has_posts?
@@ -107,23 +115,46 @@ class ContentViewerController &lt; ApplicationController @@ -107,23 +115,46 @@ class ContentViewerController &lt; ApplicationController
107 end 115 end
108 end 116 end
109 117
110 - @comments = @page.comments(true).as_thread  
111 - @comments_count = @page.comments.count 118 + comments = @page.comments.without_spam
  119 + @comments = comments.as_thread
  120 + @comments_count = comments.count
112 if params[:slideshow] 121 if params[:slideshow]
113 render :action => 'slideshow', :layout => 'slideshow' 122 render :action => 'slideshow', :layout => 'slideshow'
114 end 123 end
115 end 124 end
116 125
  126 + def edit_comment
  127 + path = params[:page].join('/')
  128 + @page = profile.articles.find_by_path(path)
  129 + @form_div = 'opened'
  130 + @comment = @page.comments.find_by_id(params[:id])
  131 + if @comment
  132 + if request.post?
  133 + begin
  134 + @comment.update_attributes(params[:comment])
  135 + session[:notice] = _('Comment succesfully updated')
  136 + redirect_to :action => 'view_page', :profile => profile.identifier, :page => @comment.article.explode_path
  137 + rescue
  138 + session[:notice] = _('Comment could not be updated')
  139 + end
  140 + end
  141 + else
  142 + redirect_to @page.view_url
  143 + session[:notice] = _('Could not find the comment in the article')
  144 + end
  145 + end
  146 +
117 protected 147 protected
118 148
119 def add_comment 149 def add_comment
120 @comment.author = user if logged_in? 150 @comment.author = user if logged_in?
121 @comment.article = @page 151 @comment.article = @page
122 @comment.ip_address = request.remote_ip 152 @comment.ip_address = request.remote_ip
  153 + @comment.user_agent = request.user_agent
  154 + @comment.referrer = request.referrer
123 plugins_filter_comment(@comment) 155 plugins_filter_comment(@comment)
124 return if @comment.rejected? 156 return if @comment.rejected?
125 if (pass_without_comment_captcha? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save 157 if (pass_without_comment_captcha? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save
126 - plugins_comment_saved(@comment)  
127 @page.touch 158 @page.touch
128 @comment = nil # clear the comment form 159 @comment = nil # clear the comment form
129 redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] 160 redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view]
@@ -138,12 +169,6 @@ class ContentViewerController &lt; ApplicationController @@ -138,12 +169,6 @@ class ContentViewerController &lt; ApplicationController
138 end 169 end
139 end 170 end
140 171
141 - def plugins_comment_saved(comment)  
142 - @plugins.each do |plugin|  
143 - plugin.comment_saved(comment)  
144 - end  
145 - end  
146 -  
147 def pass_without_comment_captcha? 172 def pass_without_comment_captcha?
148 logged_in? && !environment.enabled?('captcha_for_logged_users') 173 logged_in? && !environment.enabled?('captcha_for_logged_users')
149 end 174 end
@@ -153,9 +178,24 @@ class ContentViewerController &lt; ApplicationController @@ -153,9 +178,24 @@ class ContentViewerController &lt; ApplicationController
153 @comment = @page.comments.find(params[:remove_comment]) 178 @comment = @page.comments.find(params[:remove_comment])
154 if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) 179 if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile))
155 @comment.destroy 180 @comment.destroy
156 - session[:notice] = _('Comment succesfully deleted')  
157 end 181 end
158 - redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] 182 + finish_comment_handling
  183 + end
  184 +
  185 + def mark_comment_as_spam
  186 + @comment = @page.comments.find(params[:mark_comment_as_spam])
  187 + if logged_in? && (user == @page.profile || user.has_permission?(:moderate_comments, @page.profile))
  188 + @comment.spam!
  189 + end
  190 + finish_comment_handling
  191 + end
  192 +
  193 + def finish_comment_handling
  194 + if request.xhr?
  195 + render :text => {'ok' => true}.to_json, :content_type => 'application/json'
  196 + else
  197 + redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view]
  198 + end
159 end 199 end
160 200
161 def per_page 201 def per_page
@@ -181,4 +221,13 @@ class ContentViewerController &lt; ApplicationController @@ -181,4 +221,13 @@ class ContentViewerController &lt; ApplicationController
181 end 221 end
182 end 222 end
183 223
  224 + def comment_author
  225 + comment = Comment.find_by_id(params[:id])
  226 + if comment
  227 + render_access_denied if comment.author.blank? || comment.author != user
  228 + else
  229 + render_not_found
  230 + end
  231 + end
  232 +
184 end 233 end
app/controllers/public/not_found_controller.rb
@@ -2,4 +2,8 @@ class NotFoundController &lt; ApplicationController @@ -2,4 +2,8 @@ class NotFoundController &lt; ApplicationController
2 def index 2 def index
3 render_not_found 3 render_not_found
4 end 4 end
  5 +
  6 + def nothing
  7 + render :nothing => true, :status => 404
  8 + end
5 end 9 end
app/controllers/public/profile_controller.rb
@@ -2,11 +2,13 @@ class ProfileController &lt; PublicController @@ -2,11 +2,13 @@ class ProfileController &lt; PublicController
2 2
3 needs_profile 3 needs_profile
4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 - before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse]  
6 - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity] 5 + before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
  6 + before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
7 7
8 helper TagsHelper 8 helper TagsHelper
9 9
  10 + protect 'send_mail_to_members', :profile, :only => [:send_mail]
  11 +
10 def index 12 def index
11 @network_activities = !@profile.is_a?(Person) ? @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) : [] 13 @network_activities = !@profile.is_a?(Person) ? @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) : []
12 if logged_in? && current_person.follows?(@profile) 14 if logged_in? && current_person.follows?(@profile)
@@ -49,36 +51,36 @@ class ProfileController &lt; PublicController @@ -49,36 +51,36 @@ class ProfileController &lt; PublicController
49 51
50 def communities 52 def communities
51 if is_cache_expired?(profile.communities_cache_key(params)) 53 if is_cache_expired?(profile.communities_cache_key(params))
52 - @communities = profile.communities.paginate(:per_page => per_page, :page => params[:npage]) 54 + @communities = profile.communities.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage])
53 end 55 end
54 end 56 end
55 57
56 def enterprises 58 def enterprises
57 - @enterprises = profile.enterprises 59 + @enterprises = profile.enterprises.includes(relations_to_include)
58 end 60 end
59 61
60 def friends 62 def friends
61 if is_cache_expired?(profile.friends_cache_key(params)) 63 if is_cache_expired?(profile.friends_cache_key(params))
62 - @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage]) 64 + @friends = profile.friends.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage])
63 end 65 end
64 end 66 end
65 67
66 def members 68 def members
67 if is_cache_expired?(profile.members_cache_key(params)) 69 if is_cache_expired?(profile.members_cache_key(params))
68 - @members = profile.members.paginate(:per_page => members_per_page, :page => params[:npage]) 70 + @members = profile.members.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage])
69 end 71 end
70 end 72 end
71 73
72 def fans 74 def fans
73 - @fans = profile.fans 75 + @fans = profile.fans.includes(relations_to_include)
74 end 76 end
75 77
76 def favorite_enterprises 78 def favorite_enterprises
77 - @favorite_enterprises = profile.favorite_enterprises 79 + @favorite_enterprises = profile.favorite_enterprises.includes(relations_to_include)
78 end 80 end
79 81
80 def sitemap 82 def sitemap
81 - @articles = profile.top_level_articles 83 + @articles = profile.top_level_articles.includes([:profile, :parent])
82 end 84 end
83 85
84 def join 86 def join
@@ -212,9 +214,9 @@ class ProfileController &lt; PublicController @@ -212,9 +214,9 @@ class ProfileController &lt; PublicController
212 begin 214 begin
213 scrap = current_user.person.scraps(params[:scrap_id]) 215 scrap = current_user.person.scraps(params[:scrap_id])
214 scrap.destroy 216 scrap.destroy
215 - render :text => _('Scrap successfully removed.') 217 + finish_successful_removal 'Scrap successfully removed.'
216 rescue 218 rescue
217 - render :text => _('You could not remove this scrap') 219 + finish_unsuccessful_removal 'You could not remove this scrap.'
218 end 220 end
219 end 221 end
220 222
@@ -227,9 +229,9 @@ class ProfileController &lt; PublicController @@ -227,9 +229,9 @@ class ProfileController &lt; PublicController
227 else 229 else
228 activity.destroy 230 activity.destroy
229 end 231 end
230 - render :text => _('Activity successfully removed.') 232 + finish_successful_removal 'Activity successfully removed.'
231 rescue 233 rescue
232 - render :text => _('You could not remove this activity') 234 + finish_unsuccessful_removal 'You could not remove this activity.'
233 end 235 end
234 end 236 end
235 237
@@ -244,6 +246,24 @@ class ProfileController &lt; PublicController @@ -244,6 +246,24 @@ class ProfileController &lt; PublicController
244 end 246 end
245 end 247 end
246 248
  249 + def finish_successful_removal(msg)
  250 + if request.xhr?
  251 + render :text => {'ok' => true}.to_json, :content_type => 'application/json'
  252 + else
  253 + session[:notice] = _(msg)
  254 + redirect_to :action => :index
  255 + end
  256 + end
  257 +
  258 + def finish_unsuccessful_removal(msg)
  259 + session[:notice] = _(msg)
  260 + if request.xhr?
  261 + render :text => {'redirect' => url_for(:action => :index)}.to_json, :content_type => 'application/json'
  262 + else
  263 + redirect_to :action => :index
  264 + end
  265 + end
  266 +
247 def profile_info 267 def profile_info
248 begin 268 begin
249 @block = profile.blocks.find(params[:block_id]) 269 @block = profile.blocks.find(params[:block_id])
@@ -303,9 +323,24 @@ class ProfileController &lt; PublicController @@ -303,9 +323,24 @@ class ProfileController &lt; PublicController
303 @comment = Comment.find(params[:comment_id]) 323 @comment = Comment.find(params[:comment_id])
304 if (user == @comment.author || user == profile || user.has_permission?(:moderate_comments, profile)) 324 if (user == @comment.author || user == profile || user.has_permission?(:moderate_comments, profile))
305 @comment.destroy 325 @comment.destroy
306 - session[:notice] = _('Comment successfully deleted') 326 + finish_successful_removal 'Comment successfully removed.'
  327 + else
  328 + finish_unsuccessful_removal 'You could not remove this comment.'
  329 + end
  330 + end
  331 +
  332 + def send_mail
  333 + @mailing = profile.mailings.build(params[:mailing])
  334 + if request.post?
  335 + @mailing.locale = locale
  336 + @mailing.person = user
  337 + if @mailing.save
  338 + session[:notice] = _('The e-mails are being sent')
  339 + redirect_to_previous_location
  340 + else
  341 + session[:notice] = _('Could not create the e-mail')
  342 + end
307 end 343 end
308 - redirect_to :action => :index  
309 end 344 end
310 345
311 protected 346 protected
@@ -359,4 +394,8 @@ class ProfileController &lt; PublicController @@ -359,4 +394,8 @@ class ProfileController &lt; PublicController
359 @can_edit_profile ||= user && user.has_permission?('edit_profile', profile) 394 @can_edit_profile ||= user && user.has_permission?('edit_profile', profile)
360 end 395 end
361 helper_method :can_edit_profile 396 helper_method :can_edit_profile
  397 +
  398 + def relations_to_include
  399 + [:image, :domains, :preferred_domain, :environment]
  400 + end
362 end 401 end
app/controllers/public/search_controller.rb
@@ -4,10 +4,17 @@ class SearchController &lt; PublicController @@ -4,10 +4,17 @@ class SearchController &lt; PublicController
4 include SearchHelper 4 include SearchHelper
5 include ActionView::Helpers::NumberHelper 5 include ActionView::Helpers::NumberHelper
6 6
  7 + before_filter :redirect_asset_param, :except => [:facets_browse, :assets]
7 before_filter :load_category 8 before_filter :load_category
8 before_filter :load_search_assets 9 before_filter :load_search_assets
9 before_filter :load_query 10 before_filter :load_query
10 11
  12 + # Backwards compatibility with old URLs
  13 + def redirect_asset_param
  14 + return unless params.has_key?(:asset)
  15 + redirect_to params.merge(:action => params.delete(:asset))
  16 + end
  17 +
11 no_design_blocks 18 no_design_blocks
12 19
13 def facets_browse 20 def facets_browse
@@ -39,7 +46,7 @@ class SearchController &lt; PublicController @@ -39,7 +46,7 @@ class SearchController &lt; PublicController
39 if !@empty_query 46 if !@empty_query
40 full_text_search ['public:true'] 47 full_text_search ['public:true']
41 else 48 else
42 - @results[@asset] = @environment.people.visible.send(@filter).paginate(paginate_options) 49 + @results[@asset] = visible_profiles(Person).send(@filter).paginate(paginate_options)
43 end 50 end
44 end 51 end
45 52
@@ -69,7 +76,7 @@ class SearchController &lt; PublicController @@ -69,7 +76,7 @@ class SearchController &lt; PublicController
69 full_text_search ['public:true'] 76 full_text_search ['public:true']
70 else 77 else
71 @filter_title = _('Enterprises from network') 78 @filter_title = _('Enterprises from network')
72 - @results[@asset] = @environment.enterprises.visible.paginate(paginate_options) 79 + @results[@asset] = visible_profiles(Enterprise, [{:products => :product_category}]).paginate(paginate_options)
73 end 80 end
74 end 81 end
75 82
@@ -77,7 +84,7 @@ class SearchController &lt; PublicController @@ -77,7 +84,7 @@ class SearchController &lt; PublicController
77 if !@empty_query 84 if !@empty_query
78 full_text_search ['public:true'] 85 full_text_search ['public:true']
79 else 86 else
80 - @results[@asset] = @environment.communities.visible.send(@filter).paginate(paginate_options) 87 + @results[@asset] = visible_profiles(Community).send(@filter).paginate(paginate_options)
81 end 88 end
82 end 89 end
83 90
@@ -250,10 +257,9 @@ class SearchController &lt; PublicController @@ -250,10 +257,9 @@ class SearchController &lt; PublicController
250 end 257 end
251 258
252 def limit 259 def limit
253 - searching = @searching.values.select{ |v| v }  
254 - if params[:display] == 'map' 260 + if map_search?
255 MAP_SEARCH_LIMIT 261 MAP_SEARCH_LIMIT
256 - elsif searching.size <= 1 262 + elsif !multiple_search?
257 if [:people, :communities].include? @asset 263 if [:people, :communities].include? @asset
258 BLOCKS_SEARCH_LIMIT 264 BLOCKS_SEARCH_LIMIT
259 elsif @asset == :enterprises and @empty_query 265 elsif @asset == :enterprises and @empty_query
@@ -267,31 +273,34 @@ class SearchController &lt; PublicController @@ -267,31 +273,34 @@ class SearchController &lt; PublicController
267 end 273 end
268 274
269 def paginate_options(page = params[:page]) 275 def paginate_options(page = params[:page])
  276 + page = 1 if multiple_search? or params[:display] == 'map'
270 { :per_page => limit, :page => page } 277 { :per_page => limit, :page => page }
271 end 278 end
272 279
273 def full_text_search(filters = [], options = {}) 280 def full_text_search(filters = [], options = {})
274 paginate_options = paginate_options(params[:page]) 281 paginate_options = paginate_options(params[:page])
275 asset_class = asset_class(@asset) 282 asset_class = asset_class(@asset)
276 -  
277 solr_options = options 283 solr_options = options
278 - if !@results_only and asset_class.respond_to? :facets  
279 - solr_options.merge! asset_class.facets_find_options(params[:facet])  
280 - solr_options[:all_facets] = true  
281 - solr_options[:limit] = 0 if @facets_only  
282 - end  
283 - solr_options[:filter_queries] ||= []  
284 - solr_options[:filter_queries] += filters  
285 - solr_options[:filter_queries] << "environment_id:#{environment.id}"  
286 - solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category  
287 -  
288 - solr_options[:boost_functions] ||= []  
289 - params[:order_by] = nil if params[:order_by] == 'none'  
290 - if params[:order_by]  
291 - order = SortOptions[@asset][params[:order_by].to_sym]  
292 - raise "Unknown order by" if order.nil?  
293 - order[:solr_opts].each do |opt, value|  
294 - solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value 284 + pg_options = paginate_options(params[:page])
  285 +
  286 + if !multiple_search?
  287 + if !@results_only and asset_class.respond_to? :facets
  288 + solr_options.merge! asset_class.facets_find_options(params[:facet])
  289 + solr_options[:all_facets] = true
  290 + end
  291 + solr_options[:filter_queries] ||= []
  292 + solr_options[:filter_queries] += filters
  293 + solr_options[:filter_queries] << "environment_id:#{environment.id}"
  294 + solr_options[:filter_queries] << asset_class.facet_category_query.call(@category) if @category
  295 +
  296 + solr_options[:boost_functions] ||= []
  297 + params[:order_by] = nil if params[:order_by] == 'none'
  298 + if params[:order_by]
  299 + order = SortOptions[@asset][params[:order_by].to_sym]
  300 + raise "Unknown order by" if order.nil?
  301 + order[:solr_opts].each do |opt, value|
  302 + solr_options[opt] = value.is_a?(Proc) ? instance_eval(&value) : value
  303 + end
295 end 304 end
296 end 305 end
297 306
@@ -301,4 +310,12 @@ class SearchController &lt; PublicController @@ -301,4 +310,12 @@ class SearchController &lt; PublicController
301 @all_facets = ret[:all_facets] 310 @all_facets = ret[:all_facets]
302 end 311 end
303 312
  313 + private
  314 +
  315 + def visible_profiles(klass, *extra_relations)
  316 + relations = [:image, :domains, :environment, :preferred_domain]
  317 + relations += extra_relations
  318 + @environment.send(klass.name.underscore.pluralize).visible.includes(relations)
  319 + end
  320 +
304 end 321 end
app/helpers/application_helper.rb
@@ -265,9 +265,9 @@ module ApplicationHelper @@ -265,9 +265,9 @@ module ApplicationHelper
265 265
266 VIEW_EXTENSIONS = %w[.rhtml .html.erb] 266 VIEW_EXTENSIONS = %w[.rhtml .html.erb]
267 267
268 - def partial_for_class_in_view_path(klass, view_path) 268 + def partial_for_class_in_view_path(klass, view_path, suffix = nil)
269 return nil if klass.nil? 269 return nil if klass.nil?
270 - name = klass.name.underscore 270 + name = [klass.name.underscore, suffix].compact.map(&:to_s).join('_')
271 271
272 search_name = String.new(name) 272 search_name = String.new(name)
273 if search_name.include?("/") 273 if search_name.include?("/")
@@ -282,31 +282,20 @@ module ApplicationHelper @@ -282,31 +282,20 @@ module ApplicationHelper
282 return name if File.exists?(File.join(path)) 282 return name if File.exists?(File.join(path))
283 end 283 end
284 284
285 - partial_for_class_in_view_path(klass.superclass, view_path) 285 + partial_for_class_in_view_path(klass.superclass, view_path, suffix)
286 end 286 end
287 287
288 - def partial_for_class(klass) 288 + def partial_for_class(klass, suffix=nil)
289 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? 289 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
290 name = klass.name.underscore 290 name = klass.name.underscore
291 @controller.view_paths.each do |view_path| 291 @controller.view_paths.each do |view_path|
292 - partial = partial_for_class_in_view_path(klass, view_path) 292 + partial = partial_for_class_in_view_path(klass, view_path, suffix)
293 return partial if partial 293 return partial if partial
294 end 294 end
295 295
296 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' 296 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?'
297 end 297 end
298 298
299 - def partial_for_task_class(klass, action)  
300 - raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?  
301 -  
302 - name = "#{klass.name.underscore}_#{action.to_s}"  
303 - VIEW_EXTENSIONS.each do |ext|  
304 - return name if File.exists?(File.join(RAILS_ROOT, 'app', 'views', params[:controller], '_'+name+ext))  
305 - end  
306 -  
307 - partial_for_task_class(klass.superclass, action)  
308 - end  
309 -  
310 def view_for_profile_actions(klass) 299 def view_for_profile_actions(klass)
311 raise ArgumentError, 'No profile actions view for this class.' if klass.nil? 300 raise ArgumentError, 'No profile actions view for this class.' if klass.nil?
312 301
@@ -1336,6 +1325,19 @@ module ApplicationHelper @@ -1336,6 +1325,19 @@ module ApplicationHelper
1336 end 1325 end
1337 end 1326 end
1338 1327
  1328 + def expirable_link_to(expired, content, url, options = {})
  1329 + if expired
  1330 + options[:class] = (options[:class] || '') + ' disabled'
  1331 + content_tag('a', '&nbsp;'+content_tag('span', content), options)
  1332 + else
  1333 + link_to content, url, options
  1334 + end
  1335 + end
  1336 +
  1337 + def remove_content_button(action)
  1338 + @plugins.dispatch("content_remove_#{action.to_s}", @page).include?(true)
  1339 + end
  1340 +
1339 def template_options(klass, field_name) 1341 def template_options(klass, field_name)
1340 return '' if klass.templates.count == 0 1342 return '' if klass.templates.count == 0
1341 return hidden_field_tag("#{field_name}[template_id]", klass.templates.first.id) if klass.templates.count == 1 1343 return hidden_field_tag("#{field_name}[template_id]", klass.templates.first.id) if klass.templates.count == 1
@@ -1401,4 +1403,19 @@ module ApplicationHelper @@ -1401,4 +1403,19 @@ module ApplicationHelper
1401 result 1403 result
1402 end 1404 end
1403 1405
  1406 + def expirable_content_reference(content, action, text, url, options = {})
  1407 + reason = @plugins.dispatch("content_expire_#{action.to_s}", content).first
  1408 + options[:title] = reason
  1409 + expirable_link_to reason.present?, text, url, options
  1410 + end
  1411 +
  1412 + def expirable_button(content, action, text, url, options = {})
  1413 + options[:class] = "button with-text icon-#{action.to_s}"
  1414 + expirable_content_reference content, action, text, url, options
  1415 + end
  1416 +
  1417 + def expirable_comment_link(content, action, text, url, options = {})
  1418 + options[:class] = "comment-footer comment-footer-link comment-footer-hide"
  1419 + expirable_content_reference content, action, text, url, options
  1420 + end
1404 end 1421 end
app/helpers/article_helper.rb
@@ -2,14 +2,19 @@ module ArticleHelper @@ -2,14 +2,19 @@ module ArticleHelper
2 2
3 def custom_options_for_article(article) 3 def custom_options_for_article(article)
4 @article = article 4 @article = article
  5 + content_tag('h4', _('Visibility')) +
  6 + content_tag('div',
  7 + content_tag('div',
  8 + radio_button(:article, :published, true) +
  9 + content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true')
  10 + ) +
  11 + content_tag('div',
  12 + radio_button(:article, :published, false) +
  13 + content_tag('label', _('Private'), :for => 'article_published_false')
  14 + )
  15 + ) +
5 content_tag('h4', _('Options')) + 16 content_tag('h4', _('Options')) +
6 content_tag('div', 17 content_tag('div',
7 - content_tag(  
8 - 'div',  
9 - check_box(:article, :published) +  
10 - content_tag('label', _('This article must be published (visible to other people)'), :for => 'article_published')  
11 - ) +  
12 -  
13 (article.profile.has_members? ? 18 (article.profile.has_members? ?
14 content_tag( 19 content_tag(
15 'div', 20 'div',
app/helpers/boxes_helper.rb
@@ -66,7 +66,7 @@ module BoxesHelper @@ -66,7 +66,7 @@ module BoxesHelper
66 66
67 def display_box_content(box, main_content) 67 def display_box_content(box, main_content)
68 context = { :article => @page, :request_path => request.path, :locale => locale } 68 context = { :article => @page, :request_path => request.path, :locale => locale }
69 - box_decorator.select_blocks(box.blocks, context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box) 69 + box_decorator.select_blocks(box.blocks.includes(:box), context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box)
70 end 70 end
71 71
72 def select_blocks(arr, context) 72 def select_blocks(arr, context)
@@ -162,9 +162,6 @@ module BoxesHelper @@ -162,9 +162,6 @@ module BoxesHelper
162 # 162 #
163 # +box+ is always needed 163 # +box+ is always needed
164 def block_target(box, block = nil) 164 def block_target(box, block = nil)
165 - # FIXME hardcoded  
166 - return '' if box.position == 1  
167 -  
168 id = 165 id =
169 if block.nil? 166 if block.nil?
170 "end-of-box-#{box.id}" 167 "end-of-box-#{box.id}"
@@ -172,14 +169,11 @@ module BoxesHelper @@ -172,14 +169,11 @@ module BoxesHelper
172 "before-block-#{block.id}" 169 "before-block-#{block.id}"
173 end 170 end
174 171
175 - content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => 'block', :hoverclass => 'block-target-hover') 172 + content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover')
176 end 173 end
177 174
178 # makes the given block draggable so it can be moved away. 175 # makes the given block draggable so it can be moved away.
179 def block_handle(block) 176 def block_handle(block)
180 - # FIXME hardcoded  
181 - return '' if block.box.position == 1  
182 -  
183 draggable_element("block-#{block.id}", :revert => true) 177 draggable_element("block-#{block.id}", :revert => true)
184 end 178 end
185 179
@@ -211,7 +205,7 @@ module BoxesHelper @@ -211,7 +205,7 @@ module BoxesHelper
211 end 205 end
212 206
213 if block.editable? 207 if block.editable?
214 - buttons << lightbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id }) 208 + buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
215 end 209 end
216 210
217 if !block.main? 211 if !block.main?
app/helpers/cms_helper.rb
@@ -42,13 +42,25 @@ module CmsHelper @@ -42,13 +42,25 @@ module CmsHelper
42 42
43 def display_spread_button(profile, article) 43 def display_spread_button(profile, article)
44 if profile.person? 44 if profile.person?
45 - button_without_text :spread, _('Spread this'), :action => 'publish', :id => article.id 45 + expirable_button article, :spread, _('Spread this'), :action => 'publish', :id => article.id
46 elsif profile.community? && environment.portal_community 46 elsif profile.community? && environment.portal_community
47 - button_without_text :spread, _('Spread this'), :action => 'publish_on_portal_community', :id => article.id 47 + expirable_button article, :spread, _('Spread this'), :action => 'publish_on_portal_community', :id => article.id
48 end 48 end
49 end 49 end
50 50
51 def display_delete_button(article) 51 def display_delete_button(article)
52 - button_without_text :delete, _('Delete'), { :action => 'destroy', :id => article.id }, :method => :post, :confirm => delete_article_message(article) 52 + expirable_button article, :delete, _('Delete'), { :action => 'destroy', :id => article.id }, :method => :post, :confirm => delete_article_message(article)
  53 + end
  54 +
  55 + def expirable_button(content, action, title, url, options = {})
  56 + reason = @plugins.dispatch("content_expire_#{action.to_s}", content).first
  57 + if reason.present?
  58 + options[:class] = (options[:class] || '') + ' disabled'
  59 + options[:disabled] = 'disabled'
  60 + options.delete(:confirm)
  61 + options.delete(:method)
  62 + title = reason
  63 + end
  64 + button_without_text action.to_sym, title, url, options
53 end 65 end
54 end 66 end
app/helpers/colorbox_helper.rb
@@ -8,6 +8,10 @@ module ColorboxHelper @@ -8,6 +8,10 @@ module ColorboxHelper
8 button(type, label, url, colorbox_options(options)) 8 button(type, label, url, colorbox_options(options))
9 end 9 end
10 10
  11 + def colorbox_icon_button(type, label, url, options = {})
  12 + icon_button(type, label, url, colorbox_options(options))
  13 + end
  14 +
11 # options must be an HTML options hash as passed to link_to etc. 15 # options must be an HTML options hash as passed to link_to etc.
12 # 16 #
13 # returns a new hash with colorbox class added. Keeps existing classes. 17 # returns a new hash with colorbox class added. Keeps existing classes.
app/helpers/content_viewer_helper.rb
@@ -4,11 +4,11 @@ module ContentViewerHelper @@ -4,11 +4,11 @@ module ContentViewerHelper
4 include ForumHelper 4 include ForumHelper
5 5
6 def number_of_comments(article) 6 def number_of_comments(article)
7 - n = article.comments.size 7 + n = article.comments.without_spam.count
8 if n == 0 8 if n == 0
9 _('No comments yet') 9 _('No comments yet')
10 else 10 else
11 - n_('One comment', '%{comments} comments', n) % { :comments => n } 11 + n_('One comment', '<span class="comment-count">%{comments}</span> comments', n) % { :comments => n }
12 end 12 end
13 end 13 end
14 14
app/helpers/folder_helper.rb
@@ -58,18 +58,18 @@ module FolderHelper @@ -58,18 +58,18 @@ module FolderHelper
58 58
59 def custom_options_for_article(article) 59 def custom_options_for_article(article)
60 @article = article 60 @article = article
61 - content_tag('h4', _('Options')) + 61 + content_tag('h4', _('Visibility')) +
  62 + content_tag('div',
  63 + content_tag('div',
  64 + radio_button(:article, :published, true) +
  65 + content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true')
  66 + ) +
  67 + content_tag('div',
  68 + radio_button(:article, :published, false) +
  69 + content_tag('label', _('Private'), :for => 'article_published_false')
  70 + )
  71 + ) +
62 content_tag('div', 72 content_tag('div',
63 - content_tag(  
64 - 'div',  
65 - check_box(:article, :published) +  
66 - content_tag('label', _('This article must be published (visible to other people)'), :for => 'article_published')  
67 - ) + (article.can_display_hits? ?  
68 - content_tag(  
69 - 'div',  
70 - check_box(:article, :display_hits) +  
71 - content_tag('label', _('I want this article to display the number of hits it received'), :for => 'article_display_hits')  
72 - ) : '') +  
73 hidden_field_tag('article[accept_comments]', 0) 73 hidden_field_tag('article[accept_comments]', 0)
74 ) 74 )
75 end 75 end
app/helpers/forms_helper.rb
@@ -123,6 +123,119 @@ module FormsHelper @@ -123,6 +123,119 @@ module FormsHelper
123 options_for_select.join("\n") 123 options_for_select.join("\n")
124 end 124 end
125 125
  126 + def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {})
  127 + datepicker_options[:disabled] ||= false
  128 + datepicker_options[:alt_field] ||= ''
  129 + datepicker_options[:alt_format] ||= ''
  130 + datepicker_options[:append_text] ||= ''
  131 + datepicker_options[:auto_size] ||= false
  132 + datepicker_options[:button_image] ||= ''
  133 + datepicker_options[:button_image_only] ||= false
  134 + datepicker_options[:button_text] ||= '...'
  135 + datepicker_options[:calculate_week] ||= 'jQuery.datepicker.iso8601Week'
  136 + datepicker_options[:change_month] ||= false
  137 + datepicker_options[:change_year] ||= false
  138 + datepicker_options[:close_text] ||= _('Done')
  139 + datepicker_options[:constrain_input] ||= true
  140 + datepicker_options[:current_text] ||= _('Today')
  141 + datepicker_options[:date_format] ||= 'mm/dd/yy'
  142 + datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
  143 + datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')]
  144 + datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')]
  145 + datepicker_options[:default_date] ||= nil
  146 + datepicker_options[:duration] ||= 'normal'
  147 + datepicker_options[:first_day] ||= 0
  148 + datepicker_options[:goto_current] ||= false
  149 + datepicker_options[:hide_if_no_prev_next] ||= false
  150 + datepicker_options[:is_rtl] ||= false
  151 + datepicker_options[:max_date] ||= nil
  152 + datepicker_options[:min_date] ||= nil
  153 + datepicker_options[:month_names] ||= [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), _('September'), _('October'), _('November'), _('December')]
  154 + datepicker_options[:month_names_short] ||= [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')]
  155 + datepicker_options[:navigation_as_date_format] ||= false
  156 + datepicker_options[:next_text] ||= _('Next')
  157 + datepicker_options[:number_of_months] ||= 1
  158 + datepicker_options[:prev_text] ||= _('Prev')
  159 + datepicker_options[:select_other_months] ||= false
  160 + datepicker_options[:short_year_cutoff] ||= '+10'
  161 + datepicker_options[:show_button_panel] ||= false
  162 + datepicker_options[:show_current_at_pos] ||= 0
  163 + datepicker_options[:show_month_after_year] ||= false
  164 + datepicker_options[:show_on] ||= 'focus'
  165 + datepicker_options[:show_options] ||= {}
  166 + datepicker_options[:show_other_months] ||= false
  167 + datepicker_options[:show_week] ||= false
  168 + datepicker_options[:step_months] ||= 1
  169 + datepicker_options[:week_header] ||= _('Wk')
  170 + datepicker_options[:year_range] ||= 'c-10:c+10'
  171 + datepicker_options[:year_suffix] ||= ''
  172 +
  173 + element_id = html_options[:id] || 'datepicker-date'
  174 + value = value.strftime(format) if value.present?
  175 + method = datepicker_options[:time] ? 'datetimepicker' : 'datepicker'
  176 + result = text_field_tag(name, value, html_options)
  177 + result +=
  178 + "
  179 + <script type='text/javascript'>
  180 + jQuery('##{element_id}').#{method}({
  181 + disabled: #{datepicker_options[:disabled].to_json},
  182 + altField: #{datepicker_options[:alt_field].to_json},
  183 + altFormat: #{datepicker_options[:alt_format].to_json},
  184 + appendText: #{datepicker_options[:append_text].to_json},
  185 + autoSize: #{datepicker_options[:auto_size].to_json},
  186 + buttonImage: #{datepicker_options[:button_image].to_json},
  187 + buttonImageOnly: #{datepicker_options[:button_image_only].to_json},
  188 + buttonText: #{datepicker_options[:button_text].to_json},
  189 + calculateWeek: #{datepicker_options[:calculate_week].to_json},
  190 + changeMonth: #{datepicker_options[:change_month].to_json},
  191 + changeYear: #{datepicker_options[:change_year].to_json},
  192 + closeText: #{datepicker_options[:close_text].to_json},
  193 + constrainInput: #{datepicker_options[:constrain_input].to_json},
  194 + currentText: #{datepicker_options[:current_text].to_json},
  195 + dateFormat: #{datepicker_options[:date_format].to_json},
  196 + dayNames: #{datepicker_options[:day_names].to_json},
  197 + dayNamesMin: #{datepicker_options[:day_names_min].to_json},
  198 + dayNamesShort: #{datepicker_options[:day_names_short].to_json},
  199 + defaultDate: #{datepicker_options[:default_date].to_json},
  200 + duration: #{datepicker_options[:duration].to_json},
  201 + firstDay: #{datepicker_options[:first_day].to_json},
  202 + gotoCurrent: #{datepicker_options[:goto_current].to_json},
  203 + hideIfNoPrevNext: #{datepicker_options[:hide_if_no_prev_next].to_json},
  204 + isRTL: #{datepicker_options[:is_rtl].to_json},
  205 + maxDate: #{datepicker_options[:max_date].to_json},
  206 + minDate: #{datepicker_options[:min_date].to_json},
  207 + monthNames: #{datepicker_options[:month_names].to_json},
  208 + monthNamesShort: #{datepicker_options[:month_names_short].to_json},
  209 + navigationAsDateFormat: #{datepicker_options[:navigation_as_date_format].to_json},
  210 + nextText: #{datepicker_options[:next_text].to_json},
  211 + numberOfMonths: #{datepicker_options[:number_of_months].to_json},
  212 + prevText: #{datepicker_options[:prev_text].to_json},
  213 + selectOtherMonths: #{datepicker_options[:select_other_months].to_json},
  214 + shortYearCutoff: #{datepicker_options[:short_year_cutoff].to_json},
  215 + showButtonPanel: #{datepicker_options[:show_button_panel].to_json},
  216 + showCurrentAtPos: #{datepicker_options[:show_current_at_pos].to_json},
  217 + showMonthAfterYear: #{datepicker_options[:show_month_after_year].to_json},
  218 + showOn: #{datepicker_options[:show_on].to_json},
  219 + showOptions: #{datepicker_options[:show_options].to_json},
  220 + showOtherMonths: #{datepicker_options[:show_other_months].to_json},
  221 + showWeek: #{datepicker_options[:show_week].to_json},
  222 + stepMonths: #{datepicker_options[:step_months].to_json},
  223 + weekHeader: #{datepicker_options[:week_header].to_json},
  224 + yearRange: #{datepicker_options[:year_range].to_json},
  225 + yearSuffix: #{datepicker_options[:year_suffix].to_json}
  226 + })
  227 + </script>
  228 + "
  229 + result
  230 + end
  231 +
  232 + def date_range_field(from_name, to_name, from_value, to_value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {})
  233 + from_id = html_options[:from_id] || 'datepicker-from-date'
  234 + to_id = html_options[:to_id] || 'datepicker-to-date'
  235 + return _('From') +' '+ date_field(from_name, from_value, format, datepicker_options, html_options.merge({:id => from_id})) +
  236 + ' ' + _('until') +' '+ date_field(to_name, to_value, format, datepicker_options, html_options.merge({:id => to_id}))
  237 + end
  238 +
126 protected 239 protected
127 def self.next_id_number 240 def self.next_id_number
128 if defined? @@id_num 241 if defined? @@id_num
app/helpers/search_helper.rb
@@ -45,6 +45,14 @@ module SearchHelper @@ -45,6 +45,14 @@ module SearchHelper
45 # FIXME remove it after search_controler refactored 45 # FIXME remove it after search_controler refactored
46 include EventsHelper 46 include EventsHelper
47 47
  48 + def multiple_search?
  49 + ['index', 'category_index'].include?(params[:action]) or @results.size > 1
  50 + end
  51 +
  52 + def map_search?
  53 + !@empty_query and !multiple_search? and params[:display] == 'map'
  54 + end
  55 +
48 def search_page_title(title, category = nil) 56 def search_page_title(title, category = nil)
49 title = "<h1>" + title 57 title = "<h1>" + title
50 title += '<small>' + category.name + '</small>' if category 58 title += '<small>' + category.name + '</small>' if category
@@ -58,8 +66,8 @@ module SearchHelper @@ -58,8 +66,8 @@ module SearchHelper
58 :align => 'center', :class => 'search-category-context') if category 66 :align => 'center', :class => 'search-category-context') if category
59 end 67 end
60 68
61 - def display_results(use_map = false)  
62 - if params[:display] == 'map' && use_map 69 + def display_results(map_capable = false)
  70 + if map_capable and map_search?
63 partial = 'google_maps' 71 partial = 'google_maps'
64 klass = 'map' 72 klass = 'map'
65 else 73 else
@@ -99,7 +107,7 @@ module SearchHelper @@ -99,7 +107,7 @@ module SearchHelper
99 @asset_class = asset_class(asset) 107 @asset_class = asset_class(asset)
100 render(:partial => 'facets_unselect_menu') 108 render(:partial => 'facets_unselect_menu')
101 end 109 end
102 - 110 +
103 def facet_javascript(input_id, facet, array) 111 def facet_javascript(input_id, facet, array)
104 array = [] if array.nil? 112 array = [] if array.nil?
105 hintText = _('Type in an option') 113 hintText = _('Type in an option')
@@ -148,6 +156,7 @@ module SearchHelper @@ -148,6 +156,7 @@ module SearchHelper
148 params = params.dup 156 params = params.dup
149 params[:facet].each do |id, value| 157 params[:facet].each do |id, value|
150 facet = klass.facet_by_id(id.to_sym) 158 facet = klass.facet_by_id(id.to_sym)
  159 + next unless facet
151 if value.kind_of?(Hash) 160 if value.kind_of?(Hash)
152 label_hash = facet[:label].call(environment) 161 label_hash = facet[:label].call(environment)
153 value.each do |label_id, value| 162 value.each do |label_id, value|
app/models/article.rb
@@ -179,37 +179,23 @@ class Article &lt; ActiveRecord::Base @@ -179,37 +179,23 @@ class Article &lt; ActiveRecord::Base
179 end 179 end
180 180
181 named_scope :more_popular, :order => 'hits DESC' 181 named_scope :more_popular, :order => 'hits DESC'
182 -  
183 - # retrieves the latest +limit+ articles, sorted from the most recent to the  
184 - # oldest.  
185 - #  
186 - # Only includes articles where advertise == true  
187 - def self.recent(limit = nil, extra_conditions = {})  
188 - # FIXME this method is a horrible hack  
189 - options = { :page => 1, :per_page => limit,  
190 - :conditions => [  
191 - "advertise = ? AND  
192 - published = ? AND  
193 - profiles.visible = ? AND  
194 - profiles.public_profile = ? AND  
195 - ((articles.type != ? and articles.type != ? and articles.type != ?) OR articles.type is NULL)", true, true, true, true, 'UploadedFile', 'RssFeed', 'Blog'  
196 - ],  
197 - :include => 'profile',  
198 - :order => 'articles.published_at desc, articles.id desc'  
199 - }  
200 - if ( scoped_methods && scoped_methods.last &&  
201 - scoped_methods.last[:find] &&  
202 - scoped_methods.last[:find][:joins] &&  
203 - scoped_methods.last[:find][:joins].index('profiles') )  
204 - options.delete(:include)  
205 - end  
206 - if extra_conditions == {}  
207 - self.paginate(options)  
208 - else  
209 - with_scope :find => {:conditions => extra_conditions} do  
210 - self.paginate(options)  
211 - end 182 + named_scope :relevant_as_recent, :conditions => ["(articles.type != 'UploadedFile' and articles.type != 'RssFeed' and articles.type != 'Blog') OR articles.type is NULL"]
  183 +
  184 + def self.recent(limit = nil, extra_conditions = {}, pagination = true)
  185 + result = scoped({:conditions => extra_conditions}).
  186 + public.
  187 + relevant_as_recent.
  188 + limit(limit).
  189 + order(['articles.published_at desc', 'articles.id desc'])
  190 +
  191 + if !( scoped_methods && scoped_methods.last &&
  192 + scoped_methods.last[:find] &&
  193 + scoped_methods.last[:find][:joins] &&
  194 + scoped_methods.last[:find][:joins].index('profiles') )
  195 + result = result.includes(:profile)
212 end 196 end
  197 +
  198 + pagination ? result.paginate({:page => 1, :per_page => limit}) : result
213 end 199 end
214 200
215 # produces the HTML code that is to be displayed as this article's contents. 201 # produces the HTML code that is to be displayed as this article's contents.
app/models/box.rb
@@ -2,4 +2,76 @@ class Box &lt; ActiveRecord::Base @@ -2,4 +2,76 @@ class Box &lt; ActiveRecord::Base
2 belongs_to :owner, :polymorphic => true 2 belongs_to :owner, :polymorphic => true
3 acts_as_list :scope => 'owner_id = #{owner_id} and owner_type = \'#{owner_type}\'' 3 acts_as_list :scope => 'owner_id = #{owner_id} and owner_type = \'#{owner_type}\''
4 has_many :blocks, :dependent => :destroy, :order => 'position' 4 has_many :blocks, :dependent => :destroy, :order => 'position'
  5 +
  6 + def acceptable_blocks
  7 + to_css_class_name central? ? Box.acceptable_center_blocks : Box.acceptable_side_blocks
  8 + end
  9 +
  10 + def central?
  11 + position == 1
  12 + end
  13 +
  14 + def self.acceptable_center_blocks
  15 + [ ArticleBlock,
  16 + BlogArchivesBlock,
  17 + CategoriesBlock,
  18 + CommunitiesBlock,
  19 + EnterprisesBlock,
  20 + EnvironmentStatisticsBlock,
  21 + FansBlock,
  22 + FavoriteEnterprisesBlock,
  23 + FeedReaderBlock,
  24 + FriendsBlock,
  25 + HighlightsBlock,
  26 + LinkListBlock,
  27 + LoginBlock,
  28 + MainBlock,
  29 + MembersBlock,
  30 + MyNetworkBlock,
  31 + PeopleBlock,
  32 + ProfileImageBlock,
  33 + RawHTMLBlock,
  34 + RecentDocumentsBlock,
  35 + SellersSearchBlock,
  36 + TagsBlock ]
  37 + end
  38 +
  39 + def self.acceptable_side_blocks
  40 + [ ArticleBlock,
  41 + BlogArchivesBlock,
  42 + CategoriesBlock,
  43 + CommunitiesBlock,
  44 + DisabledEnterpriseMessageBlock,
  45 + EnterprisesBlock,
  46 + EnvironmentStatisticsBlock,
  47 + FansBlock,
  48 + FavoriteEnterprisesBlock,
  49 + FeaturedProductsBlock,
  50 + FeedReaderBlock,
  51 + FriendsBlock,
  52 + HighlightsBlock,
  53 + LinkListBlock,
  54 + LocationBlock,
  55 + LoginBlock,
  56 + MembersBlock,
  57 + MyNetworkBlock,
  58 + PeopleBlock,
  59 + ProductsBlock,
  60 + ProfileImageBlock,
  61 + ProfileInfoBlock,
  62 + ProfileSearchBlock,
  63 + RawHTMLBlock,
  64 + RecentDocumentsBlock,
  65 + SellersSearchBlock,
  66 + SlideshowBlock,
  67 + TagsBlock
  68 + ]
  69 + end
  70 +
  71 + private
  72 +
  73 + def to_css_class_name(blocks)
  74 + blocks.map{ |block| block.to_s.underscore.tr('_', '-') }
  75 + end
  76 +
5 end 77 end
app/models/change_password.rb
@@ -7,7 +7,7 @@ class ChangePassword &lt; Task @@ -7,7 +7,7 @@ class ChangePassword &lt; Task
7 when :login: 7 when :login:
8 _('Username') 8 _('Username')
9 when :email 9 when :email
10 - _('e-Mail') 10 + _('e-mail')
11 when :password 11 when :password
12 _('Password') 12 _('Password')
13 when :password_confirmation 13 when :password_confirmation
@@ -20,9 +20,7 @@ class ChangePassword &lt; Task @@ -20,9 +20,7 @@ class ChangePassword &lt; Task
20 ################################################### 20 ###################################################
21 # validations for creating a ChangePassword task 21 # validations for creating a ChangePassword task
22 22
23 - validates_presence_of :login, :email, :environment_id, :on => :create  
24 -  
25 - validates_presence_of :requestor_id 23 + validates_presence_of :login, :email, :environment_id, :on => :create, :message => _('must be filled in')
26 24
27 validates_format_of :email, :on => :create, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |obj| !obj.email.blank? }) 25 validates_format_of :email, :on => :create, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |obj| !obj.email.blank? })
28 26
@@ -30,10 +28,10 @@ class ChangePassword &lt; Task @@ -30,10 +28,10 @@ class ChangePassword &lt; Task
30 unless data.login.blank? || data.email.blank? 28 unless data.login.blank? || data.email.blank?
31 user = User.find_by_login_and_environment_id(data.login, data.environment_id) 29 user = User.find_by_login_and_environment_id(data.login, data.environment_id)
32 if user.nil? 30 if user.nil?
33 - data.errors.add(:login, _('%{fn} is not a valid username.').fix_i18n) 31 + data.errors.add(:login, _('is invalid or user does not exists.'))
34 else 32 else
35 if user.email != data.email 33 if user.email != data.email
36 - data.errors.add(:email) 34 + data.errors.add(:email, _('does not match the username you filled in'))
37 end 35 end
38 end 36 end
39 end 37 end
app/models/comment.rb
@@ -10,6 +10,9 @@ class Comment &lt; ActiveRecord::Base @@ -10,6 +10,9 @@ class Comment &lt; ActiveRecord::Base
10 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy 10 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
11 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id' 11 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id'
12 12
  13 + named_scope :without_spam, :conditions => ['spam IS NULL OR spam = ?', false]
  14 + named_scope :spam, :conditions => ['spam = ?', true]
  15 +
13 # unauthenticated authors: 16 # unauthenticated authors:
14 validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) 17 validates_presence_of :name, :if => (lambda { |record| !record.email.blank? })
15 validates_presence_of :email, :if => (lambda { |record| !record.name.blank? }) 18 validates_presence_of :email, :if => (lambda { |record| !record.name.blank? })
@@ -25,6 +28,8 @@ class Comment &lt; ActiveRecord::Base @@ -25,6 +28,8 @@ class Comment &lt; ActiveRecord::Base
25 28
26 xss_terminate :only => [ :body, :title, :name ], :on => 'validation' 29 xss_terminate :only => [ :body, :title, :name ], :on => 'validation'
27 30
  31 + delegate :environment, :to => :source
  32 +
28 def action_tracker_target 33 def action_tracker_target
29 self.article.profile 34 self.article.profile
30 end 35 end
@@ -85,7 +90,28 @@ class Comment &lt; ActiveRecord::Base @@ -85,7 +90,28 @@ class Comment &lt; ActiveRecord::Base
85 end 90 end
86 end 91 end
87 92
88 - after_create :notify_by_mail 93 + after_create :schedule_notification
  94 +
  95 + def schedule_notification
  96 + Delayed::Job.enqueue CommentHandler.new(self.id, :verify_and_notify)
  97 + end
  98 +
  99 + delegate :environment, :to => :profile
  100 + delegate :profile, :to => :source
  101 +
  102 + include Noosfero::Plugin::HotSpot
  103 +
  104 + def verify_and_notify
  105 + check_for_spam
  106 + unless spam?
  107 + notify_by_mail
  108 + end
  109 + end
  110 +
  111 + def check_for_spam
  112 + plugins.dispatch(:check_comment_for_spam, self)
  113 + end
  114 +
89 def notify_by_mail 115 def notify_by_mail
90 if source.kind_of?(Article) && article.notify_comments? 116 if source.kind_of?(Article) && article.notify_comments?
91 if !article.profile.notification_emails.empty? 117 if !article.profile.notification_emails.empty?
@@ -123,10 +149,14 @@ class Comment &lt; ActiveRecord::Base @@ -123,10 +149,14 @@ class Comment &lt; ActiveRecord::Base
123 def self.as_thread 149 def self.as_thread
124 result = {} 150 result = {}
125 root = [] 151 root = []
126 - all.each do |c| 152 + order(:id).each do |c|
127 c.replies = [] 153 c.replies = []
128 result[c.id] ||= c 154 result[c.id] ||= c
129 - c.reply_of_id.nil? ? root << c : result[c.reply_of_id].replies << c 155 + if result[c.reply_of_id]
  156 + result[c.reply_of_id].replies << c
  157 + else
  158 + root << c
  159 + end
130 end 160 end
131 root 161 root
132 end 162 end
@@ -183,4 +213,34 @@ class Comment &lt; ActiveRecord::Base @@ -183,4 +213,34 @@ class Comment &lt; ActiveRecord::Base
183 @rejected = true 213 @rejected = true
184 end 214 end
185 215
  216 + def spam?
  217 + !spam.nil? && spam
  218 + end
  219 +
  220 + def ham?
  221 + !spam.nil? && !spam
  222 + end
  223 +
  224 + def spam!
  225 + self.spam = true
  226 + self.save!
  227 + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam))
  228 + self
  229 + end
  230 +
  231 + def ham!
  232 + self.spam = false
  233 + self.save!
  234 + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham))
  235 + self
  236 + end
  237 +
  238 + def marked_as_spam
  239 + plugins.dispatch(:comment_marked_as_spam, self)
  240 + end
  241 +
  242 + def marked_as_ham
  243 + plugins.dispatch(:comment_marked_as_ham, self)
  244 + end
  245 +
186 end 246 end
app/models/comment_handler.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class CommentHandler < Struct.new(:comment_id, :method)
  2 +
  3 + def perform
  4 + comment = Comment.find(comment_id)
  5 + comment.send(method)
  6 + rescue ActiveRecord::RecordNotFound
  7 + # just ignore non-existing comments
  8 + end
  9 +
  10 +end
app/models/community.rb
@@ -88,7 +88,7 @@ class Community &lt; Organization @@ -88,7 +88,7 @@ class Community &lt; Organization
88 end 88 end
89 89
90 def activities 90 def activities
91 - Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.target_id = #{self.id} UNION SELECT at.id, at.updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} at INNER JOIN articles a ON at.target_id = a.id WHERE a.profile_id = #{self.id} AND at.target_type = 'Article' ORDER BY updated_at DESC") 91 + Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.target_id = #{self.id} and action_tracker.verb != 'join_community' and action_tracker.verb != 'leave_scrap' UNION SELECT at.id, at.updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} at INNER JOIN articles a ON at.target_id = a.id WHERE a.profile_id = #{self.id} AND at.target_type = 'Article' ORDER BY updated_at DESC")
92 end 92 end
93 93
94 end 94 end
app/models/enterprise.rb
@@ -17,7 +17,7 @@ class Enterprise &lt; Organization @@ -17,7 +17,7 @@ class Enterprise &lt; Organization
17 after_save_reindex [:products], :with => :delayed_job 17 after_save_reindex [:products], :with => :delayed_job
18 extra_data_for_index :product_categories 18 extra_data_for_index :product_categories
19 def product_categories 19 def product_categories
20 - products.map{|p| p.category_full_name}.compact 20 + products.includes(:product_category).map{|p| p.category_full_name}.compact
21 end 21 end
22 22
23 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code') 23 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code')
app/models/environment.rb
@@ -123,10 +123,23 @@ class Environment &lt; ActiveRecord::Base @@ -123,10 +123,23 @@ class Environment &lt; ActiveRecord::Base
123 'xmpp_chat' => _('XMPP/Jabber based chat'), 123 'xmpp_chat' => _('XMPP/Jabber based chat'),
124 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'), 124 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'),
125 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'), 125 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'),
126 - 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users') 126 + 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'),
  127 + 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'),
  128 + 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login')
127 } 129 }
128 end 130 end
129 131
  132 + def self.login_redirection_options
  133 + {
  134 + 'keep_on_same_page' => _('Stays on the same page the user was before login.'),
  135 + 'site_homepage' => _('Redirects the user to the environment homepage.'),
  136 + 'user_profile_page' => _('Redirects the user to his profile page.'),
  137 + 'user_homepage' => _('Redirects the user to his homepage.'),
  138 + 'user_control_panel' => _('Redirects the user to his control panel.')
  139 + }
  140 + end
  141 + validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true
  142 +
130 # ################################################# 143 # #################################################
131 # Relationships and applied behaviour 144 # Relationships and applied behaviour
132 # ################################################# 145 # #################################################
@@ -530,6 +543,31 @@ class Environment &lt; ActiveRecord::Base @@ -530,6 +543,31 @@ class Environment &lt; ActiveRecord::Base
530 signup_fields 543 signup_fields
531 end 544 end
532 545
  546 + serialize :signup_welcome_text, Hash
  547 + def signup_welcome_text
  548 + self[:signup_welcome_text] ||= {}
  549 + end
  550 +
  551 + def signup_welcome_text_subject
  552 + self.signup_welcome_text[:subject]
  553 + end
  554 +
  555 + def signup_welcome_text_subject=(subject)
  556 + self.signup_welcome_text[:subject] = subject
  557 + end
  558 +
  559 + def signup_welcome_text_body
  560 + self.signup_welcome_text[:body]
  561 + end
  562 +
  563 + def signup_welcome_text_body=(body)
  564 + self.signup_welcome_text[:body] = body
  565 + end
  566 +
  567 + def has_signup_welcome_text?
  568 + signup_welcome_text && !signup_welcome_text_body.blank?
  569 + end
  570 +
533 # ################################################# 571 # #################################################
534 # Validations 572 # Validations
535 # ################################################# 573 # #################################################
@@ -591,8 +629,8 @@ class Environment &lt; ActiveRecord::Base @@ -591,8 +629,8 @@ class Environment &lt; ActiveRecord::Base
591 end 629 end
592 630
593 has_many :articles, :through => :profiles 631 has_many :articles, :through => :profiles
594 - def recent_documents(limit = 10)  
595 - self.articles.recent(limit) 632 + def recent_documents(limit = 10, options = {}, pagination = true)
  633 + self.articles.recent(limit, options, pagination)
596 end 634 end
597 635
598 has_many :events, :through => :profiles, :source => :articles, :class_name => 'Event' 636 has_many :events, :through => :profiles, :source => :articles, :class_name => 'Event'
app/models/external_feed.rb
@@ -19,9 +19,15 @@ class ExternalFeed &lt; ActiveRecord::Base @@ -19,9 +19,15 @@ class ExternalFeed &lt; ActiveRecord::Base
19 article.valid? 19 article.valid?
20 end 20 end
21 21
  22 + def address=(new_address)
  23 + self.fetched_at = nil unless address == new_address
  24 + super(new_address)
  25 + end
  26 +
22 def clear 27 def clear
23 # do nothing 28 # do nothing
24 end 29 end
  30 +
25 def finish_fetch 31 def finish_fetch
26 if self.only_once && self.update_errors.zero? 32 if self.only_once && self.update_errors.zero?
27 self.enabled = false 33 self.enabled = false
app/models/person.rb
@@ -22,8 +22,6 @@ class Person &lt; Profile @@ -22,8 +22,6 @@ class Person &lt; Profile
22 super 22 super
23 end 23 end
24 24
25 - acts_as_having_hotspots  
26 -  
27 named_scope :members_of, lambda { |resources| 25 named_scope :members_of, lambda { |resources|
28 resources = [resources] if !resources.kind_of?(Array) 26 resources = [resources] if !resources.kind_of?(Array)
29 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') 27 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ')
@@ -32,7 +30,7 @@ class Person &lt; Profile @@ -32,7 +30,7 @@ class Person &lt; Profile
32 30
33 def has_permission_with_plugins?(permission, profile) 31 def has_permission_with_plugins?(permission, profile)
34 permissions = [has_permission_without_plugins?(permission, profile)] 32 permissions = [has_permission_without_plugins?(permission, profile)]
35 - permissions += enabled_plugins.map do |plugin| 33 + permissions += plugins.map do |plugin|
36 plugin.has_permission?(self, permission, profile) 34 plugin.has_permission?(self, permission, profile)
37 end 35 end
38 permissions.include?(true) 36 permissions.include?(true)
@@ -73,10 +71,7 @@ class Person &lt; Profile @@ -73,10 +71,7 @@ class Person &lt; Profile
73 Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy } 71 Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy }
74 end 72 end
75 73
76 - after_destroy :destroy_user  
77 - def destroy_user  
78 - self.user.destroy if self.user  
79 - end 74 + belongs_to :user, :dependent => :delete
80 75
81 def can_control_scrap?(scrap) 76 def can_control_scrap?(scrap)
82 begin 77 begin
@@ -253,7 +248,7 @@ class Person &lt; Profile @@ -253,7 +248,7 @@ class Person &lt; Profile
253 248
254 def is_admin?(environment = nil) 249 def is_admin?(environment = nil)
255 environment ||= self.environment 250 environment ||= self.environment
256 - role_assignments.select { |ra| ra.resource == environment }.map{|ra|ra.role.permissions}.any? do |ps| 251 + role_assignments.includes([:role, :resource]).select { |ra| ra.resource == environment }.map{|ra|ra.role.permissions}.any? do |ps|
257 ps.any? do |p| 252 ps.any? do |p|
258 ActiveRecord::Base::PERMISSIONS['Environment'].keys.include?(p) 253 ActiveRecord::Base::PERMISSIONS['Environment'].keys.include?(p)
259 end 254 end
@@ -458,7 +453,7 @@ class Person &lt; Profile @@ -458,7 +453,7 @@ class Person &lt; Profile
458 end 453 end
459 454
460 def activities 455 def activities
461 - Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} ORDER BY updated_at DESC") 456 + Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} and action_tracker.verb != 'leave_scrap_to_self' and action_tracker.verb != 'add_member_in_community' ORDER BY updated_at DESC")
462 end 457 end
463 458
464 protected 459 protected
app/models/product.rb
1 class Product < ActiveRecord::Base 1 class Product < ActiveRecord::Base
  2 +
2 belongs_to :enterprise 3 belongs_to :enterprise
3 has_one :region, :through => :enterprise 4 has_one :region, :through => :enterprise
4 validates_presence_of :enterprise 5 validates_presence_of :enterprise
@@ -163,7 +164,7 @@ class Product &lt; ActiveRecord::Base @@ -163,7 +164,7 @@ class Product &lt; ActiveRecord::Base
163 164
164 def total_production_cost 165 def total_production_cost
165 return inputs_cost if price_details.empty? 166 return inputs_cost if price_details.empty?
166 - inputs_cost + price_details.map(&:price).inject { |sum,price| sum + price } 167 + inputs_cost + price_details.map(&:price).inject(0){ |sum,price| sum + price }
167 end 168 end
168 169
169 def price_described? 170 def price_described?
app/models/profile.rb
@@ -57,10 +57,12 @@ class Profile &lt; ActiveRecord::Base @@ -57,10 +57,12 @@ class Profile &lt; ActiveRecord::Base
57 'view_private_content' => N_('View private content'), 57 'view_private_content' => N_('View private content'),
58 'publish_content' => N_('Publish content'), 58 'publish_content' => N_('Publish content'),
59 'invite_members' => N_('Invite members'), 59 'invite_members' => N_('Invite members'),
  60 + 'send_mail_to_members' => N_('Send e-Mail to members'),
60 } 61 }
61 62
62 acts_as_accessible 63 acts_as_accessible
63 - acts_as_having_hotspots 64 +
  65 + include Noosfero::Plugin::HotSpot
64 66
65 named_scope :memberships_of, lambda { |person| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id ] } } 67 named_scope :memberships_of, lambda { |person| { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id ] } }
66 #FIXME: these will work only if the subclass is already loaded 68 #FIXME: these will work only if the subclass is already loaded
@@ -69,7 +71,7 @@ class Profile &lt; ActiveRecord::Base @@ -69,7 +71,7 @@ class Profile &lt; ActiveRecord::Base
69 named_scope :templates, :conditions => {:is_template => true} 71 named_scope :templates, :conditions => {:is_template => true}
70 72
71 def members 73 def members
72 - scopes = dispatch_scopes(:organization_members, self) 74 + scopes = plugins.dispatch_scopes(:organization_members, self)
73 scopes << Person.members_of(self) 75 scopes << Person.members_of(self)
74 scopes.size == 1 ? scopes.first : Person.or_scope(scopes) 76 scopes.size == 1 ? scopes.first : Person.or_scope(scopes)
75 end 77 end
@@ -113,6 +115,8 @@ class Profile &lt; ActiveRecord::Base @@ -113,6 +115,8 @@ class Profile &lt; ActiveRecord::Base
113 has_many :scraps_received, :class_name => 'Scrap', :foreign_key => :receiver_id, :order => "updated_at DESC", :dependent => :destroy 115 has_many :scraps_received, :class_name => 'Scrap', :foreign_key => :receiver_id, :order => "updated_at DESC", :dependent => :destroy
114 belongs_to :template, :class_name => 'Profile', :foreign_key => 'template_id' 116 belongs_to :template, :class_name => 'Profile', :foreign_key => 'template_id'
115 117
  118 + has_many :comments_received, :class_name => 'Comment', :through => :articles, :source => :comments
  119 +
116 # FIXME ugly workaround 120 # FIXME ugly workaround
117 def self.human_attribute_name(attrib) 121 def self.human_attribute_name(attrib)
118 _(self.superclass.human_attribute_name(attrib)) 122 _(self.superclass.human_attribute_name(attrib))
@@ -255,7 +259,7 @@ class Profile &lt; ActiveRecord::Base @@ -255,7 +259,7 @@ class Profile &lt; ActiveRecord::Base
255 self.categories(true) 259 self.categories(true)
256 self.solr_save 260 self.solr_save
257 end 261 end
258 - self.categories(reload) 262 + self.categories(reload)
259 end 263 end
260 264
261 def category_ids=(ids) 265 def category_ids=(ids)
@@ -395,8 +399,8 @@ class Profile &lt; ActiveRecord::Base @@ -395,8 +399,8 @@ class Profile &lt; ActiveRecord::Base
395 # 399 #
396 # +limit+ is the maximum number of documents to be returned. It defaults to 400 # +limit+ is the maximum number of documents to be returned. It defaults to
397 # 10. 401 # 10.
398 - def recent_documents(limit = 10, options = {})  
399 - self.articles.recent(limit, options) 402 + def recent_documents(limit = 10, options = {}, pagination = true)
  403 + self.articles.recent(limit, options, pagination)
400 end 404 end
401 405
402 def last_articles(limit = 10, options = {}) 406 def last_articles(limit = 10, options = {})
@@ -968,4 +972,8 @@ private :generate_url, :url_options @@ -968,4 +972,8 @@ private :generate_url, :url_options
968 end 972 end
969 end 973 end
970 974
  975 + validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true
  976 + def preferred_login_redirection
  977 + redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login
  978 + end
971 end 979 end
app/models/profile_list_block.rb
@@ -14,12 +14,13 @@ class ProfileListBlock &lt; Block @@ -14,12 +14,13 @@ class ProfileListBlock &lt; Block
14 14
15 def profile_list 15 def profile_list
16 result = nil 16 result = nil
  17 + visible_profiles = profiles.visible.includes([:image,:domains,:preferred_domain,:environment])
17 if !prioritize_profiles_with_image 18 if !prioritize_profiles_with_image
18 - result = profiles.visible.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand }  
19 - elsif profiles.visible.with_image.count >= limit  
20 - result = profiles.visible.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } 19 + result = visible_profiles.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand }
  20 + elsif visible_profiles.with_image.count >= limit
  21 + result = visible_profiles.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand }
21 else 22 else
22 - result = profiles.visible.with_image.sort_by{ rand } + profiles.visible.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } 23 + result = visible_profiles.with_image.sort_by{ rand } + visible_profiles.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand }
23 end 24 end
24 result.slice(0..limit-1) 25 result.slice(0..limit-1)
25 end 26 end
app/models/recent_documents_block.rb
@@ -16,11 +16,9 @@ class RecentDocumentsBlock &lt; Block @@ -16,11 +16,9 @@ class RecentDocumentsBlock &lt; Block
16 16
17 include ActionController::UrlWriter 17 include ActionController::UrlWriter
18 def content(args={}) 18 def content(args={})
19 - docs = self.limit.nil? ? owner.recent_documents : owner.recent_documents(self.limit)  
20 - 19 + docs = self.limit.nil? ? owner.recent_documents(nil, {}, false) : owner.recent_documents(self.limit, {}, false)
21 block_title(title) + 20 block_title(title) +
22 content_tag('ul', docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) 21 content_tag('ul', docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n"))
23 -  
24 end 22 end
25 23
26 def footer 24 def footer
app/models/task.rb
@@ -31,7 +31,7 @@ class Task &lt; ActiveRecord::Base @@ -31,7 +31,7 @@ class Task &lt; ActiveRecord::Base
31 end 31 end
32 end 32 end
33 33
34 - belongs_to :requestor, :class_name => 'Person', :foreign_key => :requestor_id 34 + belongs_to :requestor, :class_name => 'Profile', :foreign_key => :requestor_id
35 belongs_to :target, :foreign_key => :target_id, :polymorphic => true 35 belongs_to :target, :foreign_key => :target_id, :polymorphic => true
36 36
37 validates_uniqueness_of :code, :on => :create 37 validates_uniqueness_of :code, :on => :create
app/models/uploaded_file.rb
@@ -67,7 +67,7 @@ class UploadedFile &lt; Article @@ -67,7 +67,7 @@ class UploadedFile &lt; Article
67 'upload-file' 67 'upload-file'
68 end 68 end
69 end 69 end
70 - 70 +
71 def mime_type 71 def mime_type
72 content_type 72 content_type
73 end 73 end
@@ -129,6 +129,12 @@ class UploadedFile &lt; Article @@ -129,6 +129,12 @@ class UploadedFile &lt; Article
129 end 129 end
130 end 130 end
131 131
  132 + def extension
  133 + dotindex = self.filename.rindex('.')
  134 + return nil unless dotindex
  135 + self.filename[(dotindex+1)..-1].downcase
  136 + end
  137 +
132 def allow_children? 138 def allow_children?
133 false 139 false
134 end 140 end
@@ -144,4 +150,5 @@ class UploadedFile &lt; Article @@ -144,4 +150,5 @@ class UploadedFile &lt; Article
144 def uploaded_file? 150 def uploaded_file?
145 true 151 true
146 end 152 end
  153 +
147 end 154 end
app/models/user.rb
@@ -30,7 +30,7 @@ class User &lt; ActiveRecord::Base @@ -30,7 +30,7 @@ class User &lt; ActiveRecord::Base
30 30
31 after_create do |user| 31 after_create do |user|
32 user.person ||= Person.new 32 user.person ||= Person.new
33 - user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id) 33 + user.person.attributes = user.person_data.merge(:identifier => user.login, :user => user, :environment_id => user.environment_id)
34 user.person.name ||= user.login 34 user.person.name ||= user.login
35 user.person.visible = false unless user.activated? 35 user.person.visible = false unless user.activated?
36 user.person.save! 36 user.person.save!
@@ -73,6 +73,18 @@ class User &lt; ActiveRecord::Base @@ -73,6 +73,18 @@ class User &lt; ActiveRecord::Base
73 :environment => user.environment.name, 73 :environment => user.environment.name,
74 :url => user.environment.top_url 74 :url => user.environment.top_url
75 end 75 end
  76 +
  77 + def signup_welcome_email(user)
  78 + email_body = user.environment.signup_welcome_text_body.gsub('{user_name}', user.name)
  79 + email_subject = user.environment.signup_welcome_text_subject
  80 +
  81 + content_type 'text/html'
  82 + recipients user.email
  83 +
  84 + from "#{user.environment.name} <#{user.environment.contact_email}>"
  85 + subject email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject
  86 + body email_body
  87 + end
76 end 88 end
77 89
78 def signup! 90 def signup!
@@ -88,13 +100,13 @@ class User &lt; ActiveRecord::Base @@ -88,13 +100,13 @@ class User &lt; ActiveRecord::Base
88 attr_protected :activated_at 100 attr_protected :activated_at
89 101
90 # Virtual attribute for the unencrypted password 102 # Virtual attribute for the unencrypted password
91 - attr_accessor :password 103 + attr_accessor :password, :name
92 104
93 validates_presence_of :login, :email 105 validates_presence_of :login, :email
94 validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?}) 106 validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?})
95 validates_presence_of :password, :if => :password_required? 107 validates_presence_of :password, :if => :password_required?
96 - validates_presence_of :password_confirmation, :if => :password_required?, :if => (lambda {|user| !user.password.blank?})  
97 - validates_length_of :password, :within => 4..40, :if => :password_required?, :if => (lambda {|user| !user.password.blank?}) 108 + validates_presence_of :password_confirmation, :if => :password_required?
  109 + validates_length_of :password, :within => 4..40, :if => :password_required?
98 validates_confirmation_of :password, :if => :password_required? 110 validates_confirmation_of :password, :if => :password_required?
99 validates_length_of :login, :within => 2..40, :if => (lambda {|user| !user.login.blank?}) 111 validates_length_of :login, :within => 2..40, :if => (lambda {|user| !user.login.blank?})
100 validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?}) 112 validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?})
@@ -117,7 +129,17 @@ class User &lt; ActiveRecord::Base @@ -117,7 +129,17 @@ class User &lt; ActiveRecord::Base
117 self.activated_at = Time.now.utc 129 self.activated_at = Time.now.utc
118 self.activation_code = nil 130 self.activation_code = nil
119 self.person.visible = true 131 self.person.visible = true
120 - self.person.save! && self.save! 132 + begin
  133 + self.person.save! && self.save!
  134 + rescue Exception => exception
  135 + logger.error(exception.to_s)
  136 + false
  137 + else
  138 + if environment.enabled?('send_welcome_email_to_new_users') && environment.has_signup_welcome_text?
  139 + User::Mailer.delay.deliver_signup_welcome_email(self)
  140 + end
  141 + true
  142 + end
121 end 143 end
122 144
123 def activated? 145 def activated?
@@ -228,7 +250,12 @@ class User &lt; ActiveRecord::Base @@ -228,7 +250,12 @@ class User &lt; ActiveRecord::Base
228 end 250 end
229 251
230 def name 252 def name
231 - person ? person.name : login 253 + name = (self[:name] || login)
  254 + person.nil? ? name : (person.name || name)
  255 + end
  256 +
  257 + def name= name
  258 + self[:name] = name
232 end 259 end
233 260
234 def enable_email! 261 def enable_email!
@@ -274,6 +301,11 @@ class User &lt; ActiveRecord::Base @@ -274,6 +301,11 @@ class User &lt; ActiveRecord::Base
274 15 # in minutes 301 15 # in minutes
275 end 302 end
276 303
  304 +
  305 + def not_require_password!
  306 + @is_password_required = false
  307 + end
  308 +
277 protected 309 protected
278 # before filter 310 # before filter
279 def encrypt_password 311 def encrypt_password
@@ -282,9 +314,13 @@ class User &lt; ActiveRecord::Base @@ -282,9 +314,13 @@ class User &lt; ActiveRecord::Base
282 self.password_type ||= User.system_encryption_method.to_s 314 self.password_type ||= User.system_encryption_method.to_s
283 self.crypted_password = encrypt(password) 315 self.crypted_password = encrypt(password)
284 end 316 end
285 - 317 +
286 def password_required? 318 def password_required?
287 - crypted_password.blank? || !password.blank? 319 + (crypted_password.blank? || !password.blank?) && is_password_required?
  320 + end
  321 +
  322 + def is_password_required?
  323 + @is_password_required.nil? ? true : @is_password_required
288 end 324 end
289 325
290 def make_activation_code 326 def make_activation_code
@@ -292,6 +328,7 @@ class User &lt; ActiveRecord::Base @@ -292,6 +328,7 @@ class User &lt; ActiveRecord::Base
292 end 328 end
293 329
294 def deliver_activation_code 330 def deliver_activation_code
  331 + return if person.is_template?
295 User::Mailer.deliver_activation_code(self) unless self.activation_code.blank? 332 User::Mailer.deliver_activation_code(self) unless self.activation_code.blank?
296 end 333 end
297 334
app/views/account/forgot_password.rhtml
1 <h1><%= _('Forgot your password?') %></h1> 1 <h1><%= _('Forgot your password?') %></h1>
2 2
3 -<%= error_messages_for :change_password %> 3 +<%= error_messages_for :change_password, :header_message => _('Instructions to password recovery could not be sent'), :message => nil %>
4 4
5 <% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %> 5 <% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %>
6 6
app/views/account/login.rhtml
@@ -13,6 +13,8 @@ @@ -13,6 +13,8 @@
13 13
14 <%= f.password_field :password %> 14 <%= f.password_field :password %>
15 15
  16 + <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
  17 +
16 <% button_bar do %> 18 <% button_bar do %>
17 <%= submit_button( 'login', _('Log in') )%> 19 <%= submit_button( 'login', _('Log in') )%>
18 <% if is_thickbox %> 20 <% if is_thickbox %>
@@ -23,8 +25,13 @@ @@ -23,8 +25,13 @@
23 <% end %> 25 <% end %>
24 26
25 <% button_bar do %> 27 <% button_bar do %>
26 - <%= button :add, _("New user"), :controller => 'account', :action => 'signup' %>  
27 - <%= button :help, _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> 28 + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
  29 + <%= button :add, _("New user"), :controller => 'account', :action => 'signup' %>
  30 + <% end %>
  31 +
  32 + <% unless @plugins.dispatch(:allow_password_recovery).include?(false) %>
  33 + <%= button :help, _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %>
  34 + <% end %>
28 <% end %> 35 <% end %>
29 36
30 </div><!-- end class="login-box" --> 37 </div><!-- end class="login-box" -->
app/views/account/login_block.rhtml
@@ -9,25 +9,30 @@ @@ -9,25 +9,30 @@
9 @user ||= User.new 9 @user ||= User.new
10 %> 10 %>
11 11
12 - <% labelled_form_for :user, @user,  
13 - :url => login_url do |f| %> 12 + <% labelled_form_for :user, @user, :url => login_url do |f| %>
14 13
15 - <%= f.text_field :login, :onchange => 'this.value = convToValidLogin( this.value )' %> 14 + <%= f.text_field :login, :onchange => 'this.value = convToValidLogin( this.value )' %>
16 15
17 - <%= f.password_field :password %> 16 + <%= f.password_field :password %>
  17 +
  18 + <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
18 19
19 <% button_bar do %> 20 <% button_bar do %>
20 <%= submit_button( 'login', _('Log in') )%> 21 <%= submit_button( 'login', _('Log in') )%>
21 - <%= link_to content_tag( 'span', _('New user') ),  
22 - { :controller => 'account', :action => 'signup' },  
23 - :class => 'button with-text icon-add' %> 22 + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
  23 + <%= link_to content_tag( 'span', _('New user') ),
  24 + { :controller => 'account', :action => 'signup' },
  25 + :class => 'button with-text icon-add' %>
  26 + <% end %>
24 <% end %> 27 <% end %>
25 28
26 <% end %> 29 <% end %>
27 30
28 - <p class="forgot-passwd">  
29 - <%= link_to _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %>  
30 - </p> 31 + <% unless @plugins.dispatch(:allow_password_recovery).include?(false) %>
  32 + <p class="forgot-passwd">
  33 + <%= link_to _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %>
  34 + </p>
  35 + <% end %>
31 36
32 </div> 37 </div>
33 38
app/views/admin_panel/_signup_welcome_text.rhtml 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +<div class='description'>
  2 + <%= _('This text will be sent to new users if the feature "Send welcome e-mail to new users" is enabled on environment.') %><br/><br/>
  3 + <%= _('Including %s on body, it will be replaced by the real name of the e-mail recipient.') % content_tag('code', '{user_name}') %>
  4 +</div>
  5 +
  6 +<%= labelled_form_field(_('Subject'), text_field(:environment, :signup_welcome_text_subject, :style => 'width:100%')) %>
  7 +<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_text_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %>
app/views/admin_panel/index.rhtml
1 <h1><%= _('Administrator Panel') %></h1> 1 <h1><%= _('Administrator Panel') %></h1>
2 2
3 -<p><%= _('You, as an environment administrator, has the following options:')%></p> 3 +<h2><%= _('System settings') %></h2>
4 4
5 <table> 5 <table>
6 - <tr><td><%= link_to _('Edit environment settings'), :action => 'site_info' %></td></tr>  
7 - <tr><td><%= link_to __('Edit message for disabled enterprises'), :action => 'message_for_disabled_enterprise' %></td></tr>  
8 - <tr><td><%= link_to _('Enable/disable features'), :controller => 'features' %></td></tr>  
9 - <tr><td><%= link_to _('Enable/disable plugins'), :controller => 'plugins' %></td></tr>  
10 - <tr><td><%= link_to _('Edit sideboxes'), :controller => 'environment_design'%></td></tr>  
11 - <tr><td><%= link_to _('Manage Categories'), :controller => 'categories'%></td></tr>  
12 - <tr><td><%= link_to _('Manage User roles'), :controller => 'role' %></td></tr>  
13 - <tr><td><%= link_to _('Manage users'), :controller => 'users' %></td></tr>  
14 - <tr><td><%= link_to _('Manage Validators by region'), :controller => 'region_validators' %></td></tr>  
15 - <tr><td><%= link_to _('Edit Templates'), :controller => 'templates' %></td></tr>  
16 - <tr><td><%= link_to _('Manage Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr>  
17 - <tr><td><%= link_to _('Set Portal'), :action => 'set_portal_community' %></td></tr>  
18 - <tr><td><%= link_to _('Manage Licenses'), :controller =>'licenses' %></td></tr>  
19 - <% @plugins.dispatch(:admin_panel_links).each do |link| %> 6 + <tr><td><%= link_to _('Environment settings'), :action => 'site_info' %></td></tr>
  7 + <tr><td><%= link_to _('Features'), :controller => 'features' %></td></tr>
  8 + <tr><td><%= link_to _('Plugins'), :controller => 'plugins' %></td></tr>
  9 + <tr><td><%= link_to _('Sideboxes'), :controller => 'environment_design'%></td></tr>
  10 + <tr><td><%= link_to _('Homepage'), :action => 'set_portal_community' %></td></tr>
  11 + <tr><td><%= link_to _('Licenses'), :controller =>'licenses' %></td></tr>
  12 +</table>
  13 +
  14 +<h2><%= _('Profiles') %></h2>
  15 +
  16 +<table>
  17 + <tr><td><%= link_to _('User roles'), :controller => 'role' %></td></tr>
  18 + <tr><td><%= link_to _('Users'), :controller => 'users' %></td></tr>
  19 + <tr><td><%= link_to _('Profile templates'), :controller => 'templates' %></td></tr>
  20 + <tr><td><%= link_to _('Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr>
  21 +</table>
  22 +
  23 +
  24 +<%
  25 + plugin_links = @plugins.dispatch(:admin_panel_links)
  26 +%>
  27 +<% unless plugin_links.empty? %>
  28 + <h2><%= _('Plugins') %></h2>
  29 + <table>
  30 + <% plugin_links.each do |link| %>
20 <tr><td><%= link_to link[:title], link[:url] %></td></tr> 31 <tr><td><%= link_to link[:title], link[:url] %></td></tr>
21 <% end %> 32 <% end %>
  33 + </table>
  34 +<% end %>
  35 +
  36 +<h2><%= _('Enterprise-related settings') %></h2>
  37 +
  38 +<table>
  39 + <tr><td><%= link_to __('Message for disabled enterprises'), :action => 'message_for_disabled_enterprise' %></td></tr>
  40 + <tr><td><%= link_to _('Validators by region'), :controller => 'region_validators' %></td></tr>
  41 + <tr><td><%= link_to _('Categories'), :controller => 'categories'%></td></tr>
22 </table> 42 </table>
app/views/admin_panel/site_info.rhtml
@@ -10,6 +10,8 @@ @@ -10,6 +10,8 @@
10 :content => (render :partial => 'site_info', :locals => {:f => f})} %> 10 :content => (render :partial => 'site_info', :locals => {:f => f})} %>
11 <% tabs << {:title => _('Terms of use'), :id => 'terms-of-use', 11 <% tabs << {:title => _('Terms of use'), :id => 'terms-of-use',
12 :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %> 12 :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %>
  13 + <% tabs << {:title => _('Signup welcome text'), :id => 'signup-welcome-text',
  14 + :content => (render :partial => 'signup_welcome_text', :locals => {:f => f})} %>
13 <%= render_tabs(tabs) %> 15 <%= render_tabs(tabs) %>
14 <% button_bar do %> 16 <% button_bar do %>
15 <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %> 17 <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
app/views/blocks/profile_info_actions/community.rhtml
@@ -32,7 +32,7 @@ @@ -32,7 +32,7 @@
32 { :profile => profile.identifier, 32 { :profile => profile.identifier,
33 :controller => 'contact', 33 :controller => 'contact',
34 :action => 'new' }, 34 :action => 'new' },
35 - :class => 'button with-text icon-menu-mail' %> 35 + {:class => 'button with-text icon-menu-mail', :title => _('Send an e-mail to the administrators')} %>
36 </li> 36 </li>
37 <% end %> 37 <% end %>
38 38
app/views/box_organizer/_block_types.rhtml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +<% block_types.in_groups_of(2) do |block1, block2| %>
  2 + <div style='float: left; width: 48%; padding-top: 2px;'>
  3 + <%= labelled_radio_button(block1.description, :type, block1.name) %>
  4 + </div>
  5 + <% if block2 %>
  6 + <div style='float: left; width: 48%; padding-top: 2px;'>
  7 + <%= labelled_radio_button(block2.description, :type, block2.name) %>
  8 + </div>
  9 + <% end %>
  10 +<% end %>
app/views/box_organizer/_highlights_block.rhtml
1 <strong><%= _('Highlights') %></strong> 1 <strong><%= _('Highlights') %></strong>
2 -<div id='edit-highlights-block'> 2 +<div id='edit-highlights-block' style='width:450px'>
3 <table id='highlights' class='noborder'> 3 <table id='highlights' class='noborder'>
4 <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th><th><%= _('Title') %></th></tr> 4 <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th><th><%= _('Title') %></th></tr>
5 <% for image in @block.images do %> 5 <% for image in @block.images do %>
app/views/box_organizer/_link_list_block.rhtml
1 <strong><%= _('Links') %></strong> 1 <strong><%= _('Links') %></strong>
2 -<div id='edit-link-list-block'> 2 +<div id='edit-link-list-block' style='width:450px'>
3 <table id='links' class='noborder'> 3 <table id='links' class='noborder'>
4 <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th></tr> 4 <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th></tr>
5 <% for link in @block.links do %> 5 <% for link in @block.links do %>
app/views/box_organizer/_raw_html_block.rhtml
1 -<%= labelled_form_field(_('HTML code'), text_area(:block, :html, :style => 'width: 100%', :rows => 15)) %> 1 +<%= labelled_form_field(_('HTML code'), text_area(:block, :html, :style => 'width: 90%', :rows => 15)) %>
app/views/box_organizer/add_block.rhtml
1 -<% form_tag do %>  
2 -  
3 - <p><%= _('In what area do you want to put your new block?') %></p>  
4 -  
5 - <%# FIXME hardcoded stuff %>  
6 - <%= select_tag('box_id', options_for_select(@boxes.select { |item| item.position != 1 }.map {|item| [ _("Area %d") % item.position, item.id]})) %>  
7 -  
8 - <p><%= _('Select the type of block you want to add to your page.') %></p>  
9 -  
10 - <% @block_types.in_groups_of(2) do |block1, block2| %>  
11 - <div style='float: left; width: 48%; padding-top: 2px;'>  
12 - <%= radio_button_tag('type', block1.name) %>  
13 - <%= label_tag "type_#{block1.name.downcase}", block1.description %> 1 +<div style='height:350px'>
  2 + <% form_tag do %>
  3 +
  4 + <p><%= _('In what area do you want to put your new block?') %></p>
  5 +
  6 + <% @boxes.each do |box| %>
  7 + <%= labelled_radio_button(_("Area %d") % box.position, :box_id, box.id, box.central?, { :class => 'box-position', 'data-position' => box.position }) %>
  8 + <% end %>
  9 +
  10 + <script type="text/javascript">
  11 + (function ($) {
  12 + $(document).ready(function () {
  13 + $(".box-position").live('change', function () {
  14 + if ($(this).attr('data-position') == '1') {
  15 + $('#center-block-types').show();
  16 + $('#side-block-types').hide();
  17 + } else {
  18 + $('#center-block-types').hide();
  19 + $('#side-block-types').show();
  20 + };
  21 + });
  22 + })})(jQuery);
  23 + </script>
  24 +
  25 + <p><%= _('Select the type of block you want to add to your page.') %></p>
  26 +
  27 + <div id='center-block-types'>
  28 + <%= render :partial => 'block_types', :locals => { :block_types => @center_block_types } %>
14 </div> 29 </div>
15 - <% if block2 %>  
16 - <div style='float: left; width: 48%; padding-top: 2px;'>  
17 - <%= radio_button_tag('type', block2.name) %>  
18 - <%= label_tag "type_#{block2.name.downcase}", block2.description %>  
19 - </div> 30 +
  31 + <div id='side-block-types' style='display:none'>
  32 + <%= render :partial => 'block_types', :locals => { :block_types => @side_block_types } %>
  33 + </div>
  34 +
  35 + <br style='clear: both'/>
  36 +
  37 + <% button_bar do %>
  38 + <%= submit_button(:add, _("Add")) %>
  39 + <%= colorbox_close_button(_('Close')) %>
20 <% end %> 40 <% end %>
21 - <% end %>  
22 - <br style='clear: both'/>  
23 -  
24 - <% button_bar do %>  
25 - <%= submit_button(:add, _("Add")) %>  
26 - <%= lightbox_close_button(_('Close')) %>  
27 - <% end %>  
28 41
29 -<% end %> 42 + <% end %>
  43 +</div>
app/views/box_organizer/edit.rhtml
1 -<h2><%= _('Editing block') %></h2> 1 +<div style='width: 500px;'>
  2 + <h2><%= _('Editing block') %></h2>
2 3
3 -<% form_tag(:action => 'save', :id => @block.id) do %> 4 + <% form_tag(:action => 'save', :id => @block.id) do %>
4 5
5 - <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %> 6 + <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %>
6 7
7 - <%= render :partial => partial_for_class(@block.class) %> 8 + <%= render :partial => partial_for_class(@block.class) %>
8 9
9 - <%= labelled_form_field _('Display this block:'), '' %>  
10 - <div style='margin-left: 10px'>  
11 - <%= radio_button(:block, :display, 'always') %>  
12 - <%= label_tag('block_display_always', _('In all pages')) %>  
13 - <br/>  
14 - <%= radio_button(:block, :display, 'home_page_only') %>  
15 - <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %>  
16 - <br/>  
17 - <%= radio_button(:block, :display, 'except_home_page') %>  
18 - <%= label_tag('block_display_except_home_page', _('In all pages, except in the homepage')) %>  
19 - <br/>  
20 - <%= radio_button(:block, :display, 'never') %>  
21 - <%= label_tag('block_display_never', _("Don't display")) %>  
22 - </div> 10 + <%= labelled_form_field _('Display this block:'), '' %>
  11 + <div style='margin-left: 10px'>
  12 + <%= radio_button(:block, :display, 'always') %>
  13 + <%= label_tag('block_display_always', _('In all pages')) %>
  14 + <br/>
  15 + <%= radio_button(:block, :display, 'home_page_only') %>
  16 + <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %>
  17 + <br/>
  18 + <%= radio_button(:block, :display, 'except_home_page') %>
  19 + <%= label_tag('block_display_except_home_page', _('In all pages, except in the homepage')) %>
  20 + <br/>
  21 + <%= radio_button(:block, :display, 'never') %>
  22 + <%= label_tag('block_display_never', _("Don't display")) %>
  23 + </div>
23 24
24 - <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + Noosfero.locales.map {|key, value| [value, key]} )) %> 25 + <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + Noosfero.locales.map {|key, value| [value, key]} )) %>
25 26
26 - <% button_bar do %>  
27 - <%= submit_button(:save, _('Save')) %>  
28 - <%= lightbox_close_button(_('Cancel')) %>  
29 - <% end %> 27 + <% button_bar do %>
  28 + <%= submit_button(:save, _('Save')) %>
  29 + <%= colorbox_close_button(_('Cancel')) %>
  30 + <% end %>
30 31
31 -<% end %> 32 + <% end %>
  33 +</div>
app/views/box_organizer/index.rhtml
1 <h1><%= _('Editing sideboxes')%></h1> 1 <h1><%= _('Editing sideboxes')%></h1>
2 2
3 <% button_bar do %> 3 <% button_bar do %>
4 - <%= lightbox_button('add', _('Add a block'), { :action => 'add_block' }) %> 4 + <%= colorbox_button('add', _('Add a block'), { :action => 'add_block' }) %>
5 <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %> 5 <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %>
6 <% end %> 6 <% end %>
app/views/cms/view.rhtml
@@ -49,13 +49,13 @@ @@ -49,13 +49,13 @@
49 <%= article.class.short_description %> 49 <%= article.class.short_description %>
50 </td> 50 </td>
51 <td class="article-controls"> 51 <td class="article-controls">
52 - <%= button_without_text :edit, _('Edit'), :action => 'edit', :id => article.id %> 52 + <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %>
53 <%= button_without_text :eyes, _('Public view'), article.view_url %> 53 <%= button_without_text :eyes, _('Public view'), article.view_url %>
54 - <%= display_spread_button(profile, article) unless article.folder? %>  
55 - <% if !environment.enabled?('cant_change_homepage') %>  
56 - <%= button_without_text :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %> 54 + <%= display_spread_button(profile, article) unless article.folder? || remove_content_button(:spread)%>
  55 + <% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %>
  56 + <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
57 <% end %> 57 <% end %>
58 - <%= display_delete_button(article) %> 58 + <%= display_delete_button(article) if !remove_content_button(:delete) %>
59 </td> 59 </td>
60 </tr> 60 </tr>
61 <% end %> 61 <% end %>
app/views/contact/new.rhtml
1 -<h1><%= _('Send an e-mail to %s') % profile.name %></h1> 1 +<% if profile.person? %>
  2 + <h1><%= _('Send an e-mail to %s') % profile.name %></h1>
  3 +<% else %>
  4 + <h1><%= _('Send an e-mail to administrators') %></h1>
2 5
3 -<%= error_messages_for 'contact' %> 6 + <div class='tooltip'><%= _("The e-mail will be sent to the administrators of '%s'") % profile.name %></div>
  7 +<% end %>
4 8
  9 +<%= error_messages_for 'contact' %>
5 10
6 <% labelled_form_for :contact, @contact do |f| %> 11 <% labelled_form_for :contact, @contact do |f| %>
7 <%= hidden_field_tag(:confirm, 'false') %> 12 <%= hidden_field_tag(:confirm, 'false') %>
app/views/content_viewer/_article_toolbar.rhtml
1 <div<%= user && " class='logged-in'" %>> 1 <div<%= user && " class='logged-in'" %>>
2 <div id="article-actions"> 2 <div id="article-actions">
3 3
4 - <% if @page.allow_edit?(user) %>  
5 - <%= link_to content_tag( 'span', label_for_edit_article(@page) ),  
6 - profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }),  
7 - :class => 'button with-text icon-edit' %> 4 +
  5 + <% if @page.allow_edit?(user) && !remove_content_button(:edit) %>
  6 + <% content = content_tag('span', label_for_edit_article(@page)) %>
  7 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id }) %>
  8 + <%= expirable_button @page, :edit, content, url %>
8 <% end %> 9 <% end %>
9 10
10 - <% if @page != profile.home_page && !@page.has_posts? && @page.allow_delete?(user) %>  
11 - <%= link_to content_tag( 'span', _('Delete') ),  
12 - profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page}),  
13 - :method => :post,  
14 - :class => 'button with-text icon-delete',  
15 - :confirm => delete_article_message(@page) %> 11 + <% if @page != profile.home_page && !@page.has_posts? && @page.allow_delete?(user) && !remove_content_button(:delete)%>
  12 + <% content = content_tag( 'span', _('Delete') ) %>
  13 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'destroy', :id => @page}) %>
  14 + <% options = {:method => :post, :confirm => delete_article_message(@page)} %>
  15 + <%= expirable_button @page, :delete, content, url, options %>
16 <% end %> 16 <% end %>
17 17
18 - <% if !@page.folder? && @page.allow_spread?(user) %> 18 + <% if !@page.folder? && @page.allow_spread?(user) && !remove_content_button(:spread) %>
  19 + <% content = content_tag( 'span', _('Spread this') ) %>
  20 + <% url = nil %>
19 <% if profile.kind_of?(Person) %> 21 <% if profile.kind_of?(Person) %>
20 - <%= link_to content_tag( 'span', _('Spread this') ),  
21 - profile.admin_url.merge({ :controller => 'cms', :action => 'publish', :id => @page }),  
22 - :class => 'button with-text icon-spread' %> 22 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish', :id => @page }) %>
23 <% elsif profile.kind_of?(Community) && environment.portal_community %> 23 <% elsif profile.kind_of?(Community) && environment.portal_community %>
24 - <%= link_to content_tag( 'span', _('Spread this') ),  
25 - profile.admin_url.merge({ :controller => 'cms', :action => 'publish_on_portal_community', :id => @page }),  
26 - :class => 'button with-text icon-spread' %> 24 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'publish_on_portal_community', :id => @page }) %>
27 <% end %> 25 <% end %>
  26 + <%= expirable_button @page, :spread, content, url if url %>
28 <% end %> 27 <% end %>
29 28
30 <% if !@page.gallery? && @page.allow_create?(user) %> 29 <% if !@page.gallery? && @page.allow_create?(user) %>
31 - <%= link_to _('Add translation'),  
32 - profile.admin_url.merge(:controller => 'cms', :action => 'new',  
33 - :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)),  
34 - :type => @page.type, :article => { :translation_of_id => @page.native_translation.id }),  
35 - :class => 'button with-text icon-locale' if @page.translatable? && !@page.native_translation.language.blank? %> 30 + <% if @page.translatable? && !@page.native_translation.language.blank? && !remove_content_button(:locale) %>
  31 + <% content = _('Add translation') %>
  32 + <% parent_id = (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)) %>
  33 + <% url = profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => parent_id, :type => @page.type, :article => { :translation_of_id => @page.native_translation.id })%>
  34 + <%= expirable_button @page, :locale, content, url %>
  35 + <% end %>
  36 +
36 <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %> 37 <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %>
37 <% end %> 38 <% end %>
38 39
@@ -40,8 +41,11 @@ @@ -40,8 +41,11 @@
40 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %> 41 <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %>
41 <% end %> 42 <% end %>
42 43
43 - <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) %>  
44 - <%= link_to content_tag( 'span', _('Suggest an article') ), profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}), :id => 'suggest-article-link', :class => 'button with-text icon-new' %> 44 + <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest) %>
  45 + <% content = content_tag( 'span', _('Suggest an article') ) %>
  46 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'suggest_an_article'}) %>
  47 + <% options = {:id => 'suggest-article-link'} %>
  48 + <%= expirable_button @page, :suggest, content, url, options %>
45 <% end %> 49 <% end %>
46 50
47 <%= report_abuse(profile, :link, @page) %> 51 <%= report_abuse(profile, :link, @page) %>
app/views/content_viewer/_comment.rhtml
1 <li id="<%= comment.anchor %>" class="article-comment"> 1 <li id="<%= comment.anchor %>" class="article-comment">
2 <div class="article-comment-inner"> 2 <div class="article-comment-inner">
3 3
4 - <div class="comment-content comment-logged-<%= comment.author ? 'in' : 'out' %> <%= 'comment-from-owner' if ( comment.author && (@page.profile.name == comment.author.name) ) %>"> 4 + <div class="comment-content comment-logged-<%= comment.author ? 'in' : 'out' %> <%= 'comment-from-owner' if ( comment.author && (profile == comment.author) ) %>">
5 5
6 <% if comment.author %> 6 <% if comment.author %>
7 <%= link_to image_tag(profile_icon(comment.author, :minor)) + 7 <%= link_to image_tag(profile_icon(comment.author, :minor)) +
@@ -29,17 +29,12 @@ @@ -29,17 +29,12 @@
29 <% end %> 29 <% end %>
30 30
31 <% comment_balloon do %> 31 <% comment_balloon do %>
32 - <% if logged_in? && (user == @page.profile || user == comment.author || user.has_permission?(:moderate_comments, @page.profile)) %>  
33 - <% button_bar(:style => 'float: right; margin-top: 0px;') do %>  
34 - <%= icon_button(:delete, _('Remove this comment and all its replies'), { :profile => params[:profile], :remove_comment => comment.id, :view => params[:view] }, :method => :post, :confirm => _('Are you sure you want to remove this comment and all its replies?')) %>  
35 - <% end %>  
36 - <% end %>  
37 32
38 <div class="comment-details"> 33 <div class="comment-details">
39 <div class="comment-created-at"> 34 <div class="comment-created-at">
40 <%= show_time(comment.created_at) %> 35 <%= show_time(comment.created_at) %>
41 </div> 36 </div>
42 - <h4><%= comment.title %></h4> 37 + <h4><%= comment.title.blank? && '&nbsp;' || comment.title %></h4>
43 <div class="comment-text"> 38 <div class="comment-text">
44 <p/> 39 <p/>
45 <%= txt2html comment.body %> 40 <%= txt2html comment.body %>
@@ -57,18 +52,42 @@ @@ -57,18 +52,42 @@
57 </script> 52 </script>
58 <% end %> 53 <% end %>
59 <%= report_abuse(comment.author, :comment_link, comment) if comment.author %> 54 <%= report_abuse(comment.author, :comment_link, comment) if comment.author %>
60 - <%= link_to_function _('Reply'),  
61 - "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id, 55 +
  56 + <% if comment.spam? %>
  57 + &nbsp;
  58 + <%= link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, %s); return false;' % url_for(:mark_comment_as_ham => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide') %>
  59 + <% else %>
  60 + <% if (logged_in? && (user == profile || user.has_permission?(:moderate_comments, profile))) %>
  61 + &nbsp;
  62 + <%= link_to_function(_('Mark as SPAM'), 'remove_comment(this, %s, %s); return false;' % [url_for(:mark_comment_as_spam => comment.id).to_json, _('Are you sure you want to mark this comment as SPAM?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide') %>
  63 + <% end %>
  64 + <% end %>
  65 +
  66 + <% if comment.author && comment.author == user %>
  67 + &nbsp;
  68 + <%= expirable_comment_link comment, :edit, _('Edit'), {:action => 'edit_comment', :id => comment.id, :profile => profile.identifier} %>
  69 + <% end %>
  70 +
  71 + <% if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %>
  72 + &nbsp;
  73 + <%= link_to_function(_('Remove'), 'remove_comment(this, %s, %s); return false ;' % [url_for(:profile => params[:profile], :remove_comment => comment.id, :view => params[:view]).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children') %>
  74 + <% end %>
  75 +
  76 + <% unless comment.spam? %>
  77 + &nbsp;
  78 + <%= link_to_function _('Reply'),
  79 + "var f = add_comment_reply_form(this, %s); f.find('comment_title, textarea').val(''); return false" % comment.id,
62 :class => 'comment-footer comment-footer-link comment-footer-hide', 80 :class => 'comment-footer comment-footer-link comment-footer-hide',
63 :id => 'comment-reply-to-' + comment.id.to_s 81 :id => 'comment-reply-to-' + comment.id.to_s
64 - %> 82 + %>
  83 + <% end %>
65 </div> 84 </div>
66 85
67 <% end %> 86 <% end %>
68 87
69 </div> 88 </div>
70 89
71 - <% unless comment.replies.blank? %> 90 + <% unless comment.replies.blank? || comment.spam? %>
72 <ul class="comment-replies"> 91 <ul class="comment-replies">
73 <% comment.replies.each do |reply| %> 92 <% comment.replies.each do |reply| %>
74 <%= render :partial => 'comment', :locals => { :comment => reply } %> 93 <%= render :partial => 'comment', :locals => { :comment => reply } %>
app/views/content_viewer/_comment_form.rhtml
@@ -32,15 +32,17 @@ function submit_comment_form(button) { @@ -32,15 +32,17 @@ function submit_comment_form(button) {
32 32
33 <div class="post_comment_box <%= @form_div %>"> 33 <div class="post_comment_box <%= @form_div %>">
34 34
35 -<h4 onclick="var d = jQuery(this).parent('.post_comment_box');  
36 - if (d.hasClass('closed')) {  
37 - d.removeClass('closed');  
38 - d.addClass('opened');  
39 - d.find('input[name=comment[title]], textarea').val('');  
40 - d.find('.comment_form input[name=comment[<%= focus_on %>]]').focus();  
41 - }">  
42 - <%= content_tag('a', '', :name => 'comment_form') + _('Post a comment') %>  
43 -</h4> 35 +<% if display_link %>
  36 + <h4 onclick="var d = jQuery(this).parent('.post_comment_box');
  37 + if (d.hasClass('closed')) {
  38 + d.removeClass('closed');
  39 + d.addClass('opened');
  40 + d.find('input[name=comment[title]], textarea').val('');
  41 + d.find('.comment_form input[name=comment[<%= focus_on %>]]').focus();
  42 + }">
  43 + <%= content_tag('a', '', :name => 'comment_form') + _('Post a comment') %>
  44 + </h4>
  45 +<% end %>
44 46
45 <% unless pass_without_comment_captcha? %> 47 <% unless pass_without_comment_captcha? %>
46 <div id="recaptcha-container" style="display: none"> 48 <div id="recaptcha-container" style="display: none">
@@ -59,7 +61,7 @@ function submit_comment_form(button) { @@ -59,7 +61,7 @@ function submit_comment_form(button) {
59 </script> 61 </script>
60 <% end %> 62 <% end %>
61 63
62 -<% form_tag( url_for(@page.view_url.merge({:only_path => true})), { :class => 'comment_form' } ) do %> 64 +<% form_tag( url, { :class => 'comment_form' } ) do %>
63 <%= hidden_field_tag(:confirm, 'false') %> 65 <%= hidden_field_tag(:confirm, 'false') %>
64 66
65 <%= required_fields_message %> 67 <%= required_fields_message %>
@@ -84,7 +86,11 @@ function submit_comment_form(button) { @@ -84,7 +86,11 @@ function submit_comment_form(button) {
84 86
85 <% button_bar do %> 87 <% button_bar do %>
86 <%= submit_button('add', _('Post comment'), :onclick => "submit_comment_form(this); return false") %> 88 <%= submit_button('add', _('Post comment'), :onclick => "submit_comment_form(this); return false") %>
87 - <%= button_to_function :cancel, _('Cancel'), "f=jQuery(this).parents('.post_comment_box'); f.removeClass('opened'); f.addClass('closed'); return false" %> 89 + <% if cancel_triggers_hide %>
  90 + <%= button_to_function :cancel, _('Cancel'), "f=jQuery(this).parents('.post_comment_box'); f.removeClass('opened'); f.addClass('closed'); return false" %>
  91 + <% else %>
  92 + <%= button('cancel', _('Cancel'), {:action => 'view_page', :profile => profile.identifier, :page => @comment.article.explode_path})%>
  93 + <% end %>
88 <% end %> 94 <% end %>
89 <% end %> 95 <% end %>
90 96
app/views/content_viewer/edit_comment.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1><%= _('Edit comment') %></h1>
  2 +
  3 +<%= render :partial => 'comment_form', :locals => {:url => {:action => 'edit_comment', :profile => profile.identifier}, :display_link => false, :cancel_triggers_hide => false} %>
app/views/content_viewer/view_page.rhtml
@@ -98,13 +98,7 @@ @@ -98,13 +98,7 @@
98 </ul> 98 </ul>
99 99
100 <% if @page.accept_comments? %> 100 <% if @page.accept_comments? %>
101 - <div id="page-comment-form"><%= render :partial => 'comment_form' %></div>  
102 - <script type="text/javascript">  
103 - jQuery( function() {  
104 - jQuery('.article-comment').live('mouseover', function() { jQuery(this).find('.icon-delete:first').show(); });  
105 - jQuery('.article-comment').live('mouseout', function() { jQuery(this).find('.icon-delete').hide(); });  
106 - });  
107 - </script> 101 + <div id="page-comment-form"><%= render :partial => 'comment_form', :locals => {:url => url_for(@page.view_url.merge({:only_path => true})), :display_link => true, :cancel_triggers_hide => true}%></div>
108 <% end %> 102 <% end %>
109 </div><!-- end class="comments" --> 103 </div><!-- end class="comments" -->
110 104
app/views/features/index.rhtml
@@ -26,17 +26,12 @@ Check all the features you want to enable for your environment, uncheck all the @@ -26,17 +26,12 @@ Check all the features you want to enable for your environment, uncheck all the
26 26
27 <h2><%= _('Configure features') %></h2> 27 <h2><%= _('Configure features') %></h2>
28 28
29 -<table>  
30 - <tr>  
31 - <th><%= _('Option') %></th>  
32 - <th><%= _('Choice') %></th>  
33 - </tr>  
34 - <tr>  
35 - <td><%= _('Organization Approval Method') %></td>  
36 - <td><%= select_organization_approval_method('environment', 'organization_approval_method') %></td>  
37 - </tr>  
38 -</table>  
39 - 29 +<h3><%= _('Page to redirect after login') %></h3>
  30 + <%= select 'environment', 'redirection_after_login', Environment.login_redirection_options.map{|key,value|[value,key]} %>
  31 +<hr/>
  32 +<h3><%= _('Organization Approval Method') %></h3>
  33 + <%= select_organization_approval_method('environment', 'organization_approval_method') %>
  34 +<hr/>
40 35
41 <div> 36 <div>
42 <% button_bar do %> 37 <% button_bar do %>
app/views/friends/index.rhtml
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 :class => 'button icon-remove', 31 :class => 'button icon-remove',
32 :title => _('remove') %> 32 :title => _('remove') %>
33 <%= link_to content_tag('span',_('contact')), 33 <%= link_to content_tag('span',_('contact')),
34 - friend.url.merge(:controller => 'contact', :action => 'new'), 34 + friend.url.merge(:controller => 'contact', :action => 'new', :profile => friend.identifier),
35 :class => 'button icon-menu-mail', 35 :class => 'button icon-menu-mail',
36 :title => _('contact') %> 36 :title => _('contact') %>
37 </div><!-- end class="controll" --> 37 </div><!-- end class="controll" -->
app/views/layouts/_javascript.rhtml
@@ -2,7 +2,8 @@ @@ -2,7 +2,8 @@
2 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', 2 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox',
3 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', 3 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate',
4 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', 4 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput',
5 -'add-and-join', 'report-abuse', 'catalog', 'manage-products', :cache => 'cache-general' %> 5 +'add-and-join', 'report-abuse', 'catalog', 'manage-products',
  6 +'jquery-ui-timepicker-addon', :cache => 'cache-general' %>
6 7
7 <% language = FastGettext.locale %> 8 <% language = FastGettext.locale %>
8 <% %w{messages methods}.each do |type| %> 9 <% %w{messages methods}.each do |type| %>
app/views/layouts/application-ng.rhtml
@@ -56,10 +56,18 @@ @@ -56,10 +56,18 @@
56 <%= usermenu_logged_in %> 56 <%= usermenu_logged_in %>
57 </span> 57 </span>
58 <span class='not-logged-in' style='display: none'> 58 <span class='not-logged-in' style='display: none'>
59 - <%= _("<span class='login'>%s</span> <span class='or'>or</span> <span class='signup'>%s</span>") % [thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login'), link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup') ] %> 59 +
  60 + <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>
  61 + <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_eval(&content) }.join("") %>
  62 +
60 <div id='inlineLoginBox' style='display: none;'> 63 <div id='inlineLoginBox' style='display: none;'>
61 <%= render :file => 'account/login', :locals => { :is_thickbox => true } %> 64 <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
62 </div> 65 </div>
  66 +
  67 + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
  68 + <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%>
  69 + <% end %>
  70 +
63 </span> 71 </span>
64 <form action="/search" class="search_form" method="get" class="clean"> 72 <form action="/search" class="search_form" method="get" class="clean">
65 <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" /> 73 <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" />
app/views/plugins/index.rhtml
1 <h1><%= _('Manage plugins') %></h1> 1 <h1><%= _('Manage plugins') %></h1>
2 -<%= _('Here you can enable or disable any plugin of your environment.')%> 2 +
  3 +<p>
  4 +<%= _('Select which plugins you want to enable in your environment') %>
  5 +</p>
3 6
4 <% labelled_form_for(:environment, @environment, :url => {:action => 'update'}) do |f| %> 7 <% labelled_form_for(:environment, @environment, :url => {:action => 'update'}) do |f| %>
5 8
6 -<table>  
7 - <tr>  
8 - <th><%= _('Plugin') %></th>  
9 - <th><%= _('Description') %></th>  
10 - <th><%= _('Enabled?') %></th>  
11 - </tr>  
12 - <%= hidden_field_tag('environment[enabled_plugins][]', '') %>  
13 - <% @active_plugins.each do |plugin| %>  
14 - <tr>  
15 - <td><%= plugin.has_admin_url? ? link_to(plugin.plugin_name, plugin.admin_url) : plugin.plugin_name %></td>  
16 - <td><%= plugin.plugin_description %></td>  
17 - <td><%= check_box_tag "environment[enabled_plugins][]", plugin, @environment.enabled_plugins.include?(plugin.to_s), :id => plugin.plugin_name %></td>  
18 - </tr>  
19 - <% end %>  
20 -</table> 9 + <table>
  10 + <% @active_plugins.sort_by(&:plugin_name).each do |plugin| %>
  11 + <tr>
  12 + <td style='vertical-align: top'><%= check_box_tag "environment[enabled_plugins][]", plugin, @environment.enabled_plugins.include?(plugin.to_s), :id => plugin.plugin_name %></td>
  13 + <td>
  14 + <%= hidden_field_tag('environment[enabled_plugins][]', '') %>
  15 + <strong><%= plugin.plugin_name %></strong>
  16 + <br/>
  17 + <%= plugin.plugin_description %>
  18 + <% if plugin.has_admin_url? %>
  19 + <br/>
  20 + <br/>
  21 + <%= link_to(_('Configuration'), plugin.admin_url) %>
  22 + <% end %>
  23 + </td>
  24 + </tr>
  25 + <% end %>
  26 + </table>
21 27
22 <div> 28 <div>
23 <% button_bar do %> 29 <% button_bar do %>
app/views/profile/_comment.rhtml
@@ -5,19 +5,35 @@ @@ -5,19 +5,35 @@
5 <li class="article-comment" style='border-bottom:none;'> 5 <li class="article-comment" style='border-bottom:none;'>
6 <div class="article-comment-inner"> 6 <div class="article-comment-inner">
7 7
8 - <div class="comment-content comment-logged-in"> 8 + <div class="comment-content comment-logged-<%= comment.author ? 'in' : 'out' %>">
9 9
10 <% if comment.author %> 10 <% if comment.author %>
11 <%= link_to image_tag(profile_icon(comment.author, :minor)), 11 <%= link_to image_tag(profile_icon(comment.author, :minor)),
12 - Person.find(comment.author_id).url, 12 + comment.author_url,
13 :class => 'comment-picture', 13 :class => 'comment-picture',
14 :title => comment.author_name 14 :title => comment.author_name
15 %> 15 %>
  16 + <% else %>
  17 + <% url_image, status_class = comment.author_id ?
  18 + [comment.removed_user_image, 'icon-user-removed'] :
  19 + [str_gravatar_url_for( comment.email ), 'icon-user-unknown'] %>
  20 +
  21 + <%= link_to(
  22 + image_tag(url_image, :onerror=>'gravatarCommentFailback(this)',
  23 + 'data-gravatar'=>str_gravatar_url_for(comment.email)) +
  24 + content_tag('span', comment.author_name, :class => 'comment-info') +
  25 + content_tag('span', comment.message,
  26 + :class => 'comment-user-status comment-user-status-wall ' + status_class),
  27 + gravatar_profile_url(comment.email),
  28 + :target => '_blank',
  29 + :class => 'comment-picture',
  30 + :title => '%s %s' % [comment.author_name, comment.message]
  31 + )%>
16 <% end %> 32 <% end %>
17 33
18 <div class="comment-details"> 34 <div class="comment-details">
19 <div class="comment-text"> 35 <div class="comment-text">
20 - <%= link_to(comment.author_name, comment.author.url) %> 36 + <%= comment.author.present? ? link_to(comment.author_name, comment.author.url) : content_tag('strong', comment.author_name) %>
21 <% unless comment.title.blank? %> 37 <% unless comment.title.blank? %>
22 <span class="comment-title"><%= comment.title %></span><br/> 38 <span class="comment-title"><%= comment.title %></span><br/>
23 <% end %> 39 <% end %>
@@ -30,7 +46,7 @@ @@ -30,7 +46,7 @@
30 46
31 <% if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %> 47 <% if logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %>
32 <% button_bar(:style => 'float: right; margin-top: 0px;') do %> 48 <% button_bar(:style => 'float: right; margin-top: 0px;') do %>
33 - <%= icon_button(:delete, _('Remove'), { :action => :remove_comment, :comment_id => comment.id }, :method => :get, :confirm => _('Are you sure you want to remove this comment and all its replies?')) %> 49 + <%= link_to_function(_('Remove'), 'remove_item_wall(this, %s, %s, %s); return false ;' % ["'.article-comment'", url_for(:profile => params[:profile], :action => :remove_comment, :comment_id => comment.id, :view => params[:view]).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'button icon-button icon-delete') %>
34 <% end %> 50 <% end %>
35 <% end %> 51 <% end %>
36 <br style="clear: both;" /> 52 <br style="clear: both;" />
@@ -46,6 +62,10 @@ @@ -46,6 +62,10 @@
46 </script> 62 </script>
47 <% end %> 63 <% end %>
48 <%= report_abuse(comment.author, :comment_link, comment) if comment.author %> 64 <%= report_abuse(comment.author, :comment_link, comment) if comment.author %>
  65 + <% if comment.author && comment.author == user %>
  66 + <%= expirable_comment_link comment, :edit, _('Edit'), {:action => 'edit_comment', :id => comment.id, :profile => profile.identifier} %>
  67 + <%= content_tag('span', ' | ', :class => 'comment-footer comment-footer-hide') %>
  68 + <% end %>
49 <%= link_to_function _('Reply'), 69 <%= link_to_function _('Reply'),
50 "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id, 70 "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id,
51 :class => 'comment-footer comment-footer-link comment-footer-hide', 71 :class => 'comment-footer comment-footer-link comment-footer-hide',
app/views/profile/_common.rhtml
1 -  
2 -<script type="text/javascript">  
3 - jQuery( function() {  
4 - var parent_selector = '.profile-wall-description, .profile-activity-description, .profile-network-description';  
5 - var child_selector = '.icon-delete, .icon-reply';  
6 - jQuery(parent_selector).live('mouseover', function () { jQuery(this).find(child_selector).css('visibility', 'visible'); });  
7 - jQuery(parent_selector).live('mouseout', function () { jQuery(this).find(child_selector).css('visibility', 'hidden'); });  
8 - });  
9 -</script>  
10 -  
11 <% unless @action %> 1 <% unless @action %>
12 <% cache_timeout(profile.cache_key + '-profile-general-info', 4.hours) do %> 2 <% cache_timeout(profile.cache_key + '-profile-general-info', 4.hours) do %>
13 <tr> 3 <tr>
app/views/profile/_create_article.rhtml
@@ -15,7 +15,7 @@ @@ -15,7 +15,7 @@
15 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p> 15 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
16 <div class='profile-wall-actions'> 16 <div class='profile-wall-actions'>
17 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %> 17 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
18 - <%= link_to_remote(content_tag(:span, _('Remove')), :url =>{:action => 'remove_activity', :activity_id => activity.id, :only_hide => true}, :confirm => _('Are you sure?'), :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %> 18 + <%= link_to_function(_('Remove'), 'remove_item_wall(this, %s, %s, %s); return false ;' % ["'.profile-activity-item'", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :only_hide => true, :view => params[:view]).to_json, _('Are you sure you want to remove this activity and all its replies?').to_json]) if logged_in? && current_person == @profile %>
19 </div> 19 </div>
20 </div> 20 </div>
21 21
app/views/profile/_default_activity.rhtml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p> 6 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
7 <div class='profile-wall-actions'> 7 <div class='profile-wall-actions'>
8 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %> 8 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
9 - <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %> 9 + <%= link_to_function(_('Remove'), 'remove_item_wall(this, %s, %s, %s); return false ;' % ["'.profile-activity-item'", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]).to_json, _('Are you sure you want to remove this activity and all its replies?').to_json]) if logged_in? && current_person == @profile %>
10 </div> 10 </div>
11 </div> 11 </div>
12 12
app/views/profile/_leave_scrap.rhtml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p> 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p> 6 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
7 <div class='profile-wall-actions'> 7 <div class='profile-wall-actions'>
8 - <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %> 8 + <%= link_to_function(_('Remove'), 'remove_item_wall(this, %s, %s, %s); return false ;' % ["'.profile-activity-item'", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]).to_json, _('Are you sure you want to remove this activity and all its replies?').to_json]) if logged_in? && current_person == @profile %>
9 </div> 9 </div>
10 </div> 10 </div>
11 11
app/views/profile/_person_profile.rhtml
@@ -37,7 +37,7 @@ @@ -37,7 +37,7 @@
37 <tr> 37 <tr>
38 <th colspan='2'><%= __('Enterprises') %></th> 38 <th colspan='2'><%= __('Enterprises') %></th>
39 </tr> 39 </tr>
40 - <% profile.enterprises.each do |item| %> 40 + <% profile.enterprises.includes(:environment,:domains, :preferred_domain).each do |item| %>
41 <tr> 41 <tr>
42 <td></td> 42 <td></td>
43 <td><%= button 'menu-enterprise', item.name, item.url %></td> 43 <td><%= button 'menu-enterprise', item.name, item.url %></td>
app/views/profile/_profile_scrap.rhtml
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %> 12 <%= link_to_function s_('profile|Comment'), "hide_and_show(['#profile-wall-message-response-#{scrap.id}'],['#profile-wall-reply-#{scrap.id}', '#profile-wall-reply-form-#{scrap.id}']);$('reply_content_#{scrap.id}').value='';$('reply_content_#{scrap.id}').focus();return false", :class => "profile-send-reply" %>
13 </span> 13 </span>
14 <% end %> 14 <% end %>
15 - <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_scrap', :scrap_id => scrap.id}, :update => "profile-activity-item-#{scrap.id}") if logged_in? && user.can_control_scrap?(scrap) %> 15 + <%= link_to_function(_('Remove'), 'remove_item_wall(this, %s, %s, %s); return false ;' % ["'.profile-activity-item'", url_for(:profile => params[:profile], :action => :remove_scrap, :scrap_id => scrap.id, :view => params[:view]).to_json, _('Are you sure you want to remove this scrap and all its replies?').to_json]) if logged_in? && user.can_control_scrap?(scrap) %>
16 </div> 16 </div>
17 </div> 17 </div>
18 18
app/views/profile/_upload_image.rhtml
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p> 6 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
7 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p> 7 <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
8 <div class='profile-wall-actions'> 8 <div class='profile-wall-actions'>
9 - <%= link_to_remote(content_tag(:span, _('Remove')), :confirm => _('Are you sure?'), :url =>{:action => 'remove_activity', :activity_id => activity.id}, :update => "profile-activity-item-#{activity.id}") if logged_in? && current_person == @profile %> 9 + <%= link_to_function(_('Remove'), 'remove_item_wall(this, %s, %s, %s); return false ;' % ["'.profile-activity-item'", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]).to_json, _('Are you sure you want to remove this activity and all its replies?').to_json]) if logged_in? && current_person == @profile %>
10 </div> 10 </div>
11 </div> 11 </div>
12 </div> 12 </div>
app/views/profile/members.rhtml
@@ -16,8 +16,13 @@ @@ -16,8 +16,13 @@
16 16
17 <% button_bar do %> 17 <% button_bar do %>
18 <%= button :back, _('Go back'), { :controller => 'profile' } %> 18 <%= button :back, _('Go back'), { :controller => 'profile' } %>
19 - <% if profile.community? and user and user.has_permission?(:invite_members, profile) %>  
20 - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %> 19 + <% if profile.community? and user %>
  20 + <% if user.has_permission?(:invite_members, profile) %>
  21 + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %>
  22 + <% end %>
  23 + <% if user.has_permission?(:send_mail_to_members, profile) %>
  24 + <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %>
  25 + <% end %>
21 <% end %> 26 <% end %>
22 <% end %> 27 <% end %>
23 28
app/views/profile/send_mail.rhtml 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +<h1><%= h profile.short_name(50) %></h1>
  2 +
  3 +<h2><%= _('Send e-mail to members') %></h2>
  4 +
  5 +<%= error_messages_for :mailing %>
  6 +
  7 +<%= render :file => 'shared/tiny_mce' %>
  8 +
  9 +<% form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %>
  10 + <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>
  11 + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %>
  12 + <%= submit_button(:send, _('Send')) %>
  13 + <%= button :cancel, _('Cancel e-mail'), :back %>
  14 +<% end %>
app/views/profile_editor/edit.rhtml
@@ -24,61 +24,24 @@ @@ -24,61 +24,24 @@
24 <h2><%= _('Privacy options') %></h2> 24 <h2><%= _('Privacy options') %></h2>
25 25
26 <% if profile.person? %> 26 <% if profile.person? %>
27 - <table>  
28 - <tr>  
29 - <th style='text-align: right;'>  
30 - <%= _('This profile is:') %>  
31 - </th>  
32 - <th>  
33 - <%= radio_button 'profile_data', 'public_profile', 'true' %>  
34 - <label for="profile_data_public_profile_true"><u><%= _('Public') %></u></label>  
35 - </th>  
36 - <th style='padding: 2px 10px 2px 2px;'>  
37 - <%= radio_button 'profile_data', 'public_profile', 'false' %>  
38 - <label for="profile_data_public_profile_false"><u><%= _('Private') %></u></label>  
39 - </th>  
40 - </tr>  
41 - <tr>  
42 - <td> <%= _('Activate Intranet access (restricted area only for me)') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td>  
43 - </tr>  
44 - <tr>  
45 - <td> <%= _('Include my contact in directory of people') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td>  
46 - </tr>  
47 - <tr>  
48 - <td> <%= _('Show my contents to all internet users') %> </td><td><%= _('Yes') %></td><td><%= _('No') %></td>  
49 - </tr>  
50 - <tr>  
51 - <td> <%= _('Show my contents to my friends (person)') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td>  
52 - </tr>  
53 - </table> 27 + <div>
  28 + <%= labelled_radio_button _('Public &mdash; show my contents to all internet users'), 'profile_data[public_profile]', true, @profile.public_profile? %>
  29 + </div>
  30 + <div>
  31 + <%= labelled_radio_button _('Private &mdash; show my contents only to friends'), 'profile_data[public_profile]', false, !@profile.public_profile? %>
  32 + </div>
54 <% else %> 33 <% else %>
55 - <table>  
56 - <tr>  
57 - <th style='text-align: right;'>  
58 - <%= _('This profile is:') %>  
59 - </th>  
60 - <th>  
61 - <%= radio_button 'profile_data', 'public_profile', 'true' %>  
62 - <label for="profile_data_public_profile_true"><u><%= _('Public') %></u></label>  
63 - </th>  
64 - <th style='padding: 2px 10px 2px 2px;'>  
65 - <%= radio_button 'profile_data', 'public_profile', 'false' %>  
66 - <label for="profile_data_public_profile_false"><u><%= _('Private') %></u></label>  
67 - </th>  
68 - </tr>  
69 - <tr>  
70 - <td> <%= _('Activate Intranet access (restricted area only for members)') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td>  
71 - </tr>  
72 - <tr>  
73 - <td> <%= _('Include this group directory of groups') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td>  
74 - </tr>  
75 - <tr>  
76 - <td> <%= _('Show content of this group to all internet users') %> </td><td><%= _('Yes') %></td><td><%= _('No') %></td>  
77 - </tr>  
78 - <tr>  
79 - <td> <%= _('Show content of this group to members') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td>  
80 - </tr>  
81 - </table> 34 + <div>
  35 + <%= labelled_radio_button _('Public &mdash; show content of this group to all internet users'), 'profile_data[public_profile]', true, @profile.public_profile? %>
  36 + </div>
  37 + <div>
  38 + <%= labelled_radio_button _('Private &mdash; show content of this group only to members'), 'profile_data[public_profile]', false, !@profile.public_profile? %>
  39 + </div>
  40 + <% end %>
  41 +
  42 + <% if environment.enabled?('allow_change_of_redirection_after_login') %>
  43 + <h2><%= _('Page to redirect after login') %></h2>
  44 + <%= select 'profile_data', 'redirection_after_login', Environment.login_redirection_options.map{|key,value|[value,key]}, { :selected => @profile.preferred_login_redirection} %>
82 <% end %> 45 <% end %>
83 46
84 <h2><%= _('Translations') %></h2> 47 <h2><%= _('Translations') %></h2>
app/views/profile_editor/index.rhtml
@@ -66,6 +66,8 @@ @@ -66,6 +66,8 @@
66 66
67 <%= control_panel_button(_('Manage my groups'), 'groups', :controller => 'memberships') if profile.person? %> 67 <%= control_panel_button(_('Manage my groups'), 'groups', :controller => 'memberships') if profile.person? %>
68 68
  69 + <%= control_panel_button(_('Manage SPAM'), 'manage-spam', :controller => 'spam', :action => 'index') %>
  70 +
69 <% @plugins.dispatch(:control_panel_buttons).each do |button| %> 71 <% @plugins.dispatch(:control_panel_buttons).each do |button| %>
70 <%= control_panel_button(button[:title], button[:icon], button[:url]) %> 72 <%= control_panel_button(button[:title], button[:icon], button[:url]) %>
71 <% end %> 73 <% end %>
app/views/profile_members/_index_buttons.rhtml
@@ -4,7 +4,9 @@ @@ -4,7 +4,9 @@
4 <% if profile.community? and user.has_permission?(:invite_members, profile) %> 4 <% if profile.community? and user.has_permission?(:invite_members, profile) %>
5 <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'select_address_book' %> 5 <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'select_address_book' %>
6 <% end %> 6 <% end %>
7 - <%= button :send, _('Send e-mail to members'), :action => 'send_mail' %> 7 + <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %>
  8 + <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %>
  9 + <% end %>
8 <% @plugins.dispatch(:manage_members_extra_buttons).each do |plugin_button| %> 10 <% @plugins.dispatch(:manage_members_extra_buttons).each do |plugin_button| %>
9 <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %> 11 <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %>
10 <% end %> 12 <% end %>
app/views/profile_members/send_mail.rhtml
@@ -1,14 +0,0 @@ @@ -1,14 +0,0 @@
1 -<h1><%= h profile.short_name(50) %></h1>  
2 -  
3 -<h2><%= _('Send e-mail to members') %></h2>  
4 -  
5 -<%= error_messages_for :mailing %>  
6 -  
7 -<%= render :file => 'shared/tiny_mce' %>  
8 -  
9 -<% form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %>  
10 - <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>  
11 - <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %>  
12 - <%= submit_button(:send, _('Send')) %>  
13 - <%= button :cancel, _('Cancel e-mail'), :action => 'index' %>  
14 -<% end %>  
app/views/search/_display_results.rhtml
1 -<div id="search-results" class="<%= @results.size == 1 ? 'only-one-result-box' : 'multiple-results-boxes' %>"> 1 +<div id="search-results" class="<%= !multiple_search? ? 'only-one-result-box' : 'multiple-results-boxes' %>">
2 <% @order.each do |name| %> 2 <% @order.each do |name| %>
3 <% results = @results[name] %> 3 <% results = @results[name] %>
4 <% empty = results.nil? || results.empty? %> 4 <% empty = results.nil? || results.empty? %>
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 <% if not empty %> 7 <% if not empty %>
8 <% partial = partial_for_class(results.first.class.class_name.constantize) %> 8 <% partial = partial_for_class(results.first.class.class_name.constantize) %>
9 9
10 - <% if @results.size > 1 %> 10 + <% if multiple_search? %>
11 <h3><%= @names[name] %></h3> 11 <h3><%= @names[name] %></h3>
12 <% if results.total_entries > SearchController::MULTIPLE_SEARCH_LIMIT %> 12 <% if results.total_entries > SearchController::MULTIPLE_SEARCH_LIMIT %>
13 <%= link_to(_('see all (%d)') % results.total_entries, params.merge(:action => name), :class => 'see-more' ) %> 13 <%= link_to(_('see all (%d)') % results.total_entries, params.merge(:action => name), :class => 'see-more' ) %>
@@ -22,9 +22,10 @@ @@ -22,9 +22,10 @@
22 </ul> 22 </ul>
23 </div> 23 </div>
24 <% else %> 24 <% else %>
25 - <% if @results.size > 1 %> 25 + <% if multiple_search? %>
26 <h3><%= @names[name] %></h3> 26 <h3><%= @names[name] %></h3>
27 <% end %> 27 <% end %>
  28 +
28 <div class="search-results-innerbox search-results-type-empty"> 29 <div class="search-results-innerbox search-results-type-empty">
29 <div> <%= _('None') %> </div> 30 <div> <%= _('None') %> </div>
30 </div> 31 </div>
app/views/search/_image.rhtml
1 <div class="search-image-container"> 1 <div class="search-image-container">
2 2
3 <% if image.is_a? UploadedFile and image.filename %> 3 <% if image.is_a? UploadedFile and image.filename %>
4 - <% extension = image.filename[(image.filename.rindex('.')+1)..-1].downcase %> 4 + <% extension = image.extension %>
5 <% if ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'svg'].include? extension %> 5 <% if ['jpg', 'jpeg', 'gif', 'png', 'tiff', 'svg'].include? extension %>
6 <%= link_to '', image.view_url, :class => "search-image-pic", :style => 'background-image: url(%s)'% image.public_filename(:thumb) %> 6 <%= link_to '', image.view_url, :class => "search-image-pic", :style => 'background-image: url(%s)'% image.public_filename(:thumb) %>
7 <% if image.width && image.height %> 7 <% if image.width && image.height %>
app/views/search/_profile.rhtml
1 <li class="search-profile-item"> 1 <li class="search-profile-item">
2 -<% if @empty_query or @results.size > 1 or !profile.enterprise? %> 2 +<% if @empty_query or multiple_search? or !profile.enterprise? %>
3 <%= profile_image_link profile, :portrait, 'div', 3 <%= profile_image_link profile, :portrait, 'div',
4 @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %> 4 @filter == 'more_recent' ? profile.send(@filter + '_label') + show_date(profile.created_at) : profile.send(@filter + '_label') %>
5 <% else %> 5 <% else %>
app/views/search/communities.rhtml
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 <% if logged_in? %> 4 <% if logged_in? %>
5 <% button_bar do %> 5 <% button_bar do %>
6 <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %> 6 <%# FIXME shouldn't the user create the community in the current environment instead of going to its home environment? %>
7 - <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community')) %> 7 + <%= button(:add, __('New community'), user.url.merge(:controller => 'memberships', :action => 'new_community', :profile => user.identifier)) %>
8 <% end %> 8 <% end %>
9 <% end %> 9 <% end %>
10 10
app/views/spam/index.rhtml 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +<h1><%= _('Manage SPAM') %></h1>
  2 +
  3 +<% button_bar do %>
  4 + <%= button :back, _('Back to control panel'), :controller => :profile_editor %>
  5 +<% end %>
  6 +
  7 +<%# FIXME should not need to replicate the article structure like this to be able to use the same formatting as the comments listing %>
  8 +<div id='article'>
  9 + <div class="comments" id="comments_list">
  10 + <ul class="article-comments-list">
  11 + <%= render :partial => 'content_viewer/comment', :collection => @spam %>
  12 + </ul>
  13 + </div>
  14 +</div>
  15 +
  16 +<%= pagination_links @spam %>
  17 +
  18 +<% button_bar do %>
  19 + <%= button :back, _('Back to control panel'), :controller => :profile_editor %>
  20 +<% end %>
app/views/tasks/_task.rhtml
@@ -50,13 +50,13 @@ @@ -50,13 +50,13 @@
50 <% fields_for "tasks[#{task.id}][task]", task do |f| %> 50 <% fields_for "tasks[#{task.id}][task]", task do |f| %>
51 <% if task.accept_details %> 51 <% if task.accept_details %>
52 <div id="on-accept-information-<%=task.id%>" style="display: none"> 52 <div id="on-accept-information-<%=task.id%>" style="display: none">
53 - <%= render :partial => partial_for_task_class(task.class, :accept_details), :locals => {:task => task, :f => f} %> 53 + <%= render :partial => partial_for_class(task.class, :accept_details), :locals => {:task => task, :f => f} %>
54 </div> 54 </div>
55 <% end %> 55 <% end %>
56 56
57 <% if task.reject_details %> 57 <% if task.reject_details %>
58 <div id="on-reject-information-<%=task.id%>" style="display: none"> 58 <div id="on-reject-information-<%=task.id%>" style="display: none">
59 - <%= render :partial => partial_for_task_class(task.class, :reject_details), :locals => {:task => task, :f => f} %> 59 + <%= render :partial => partial_for_class(task.class, :reject_details), :locals => {:task => task, :f => f} %>
60 </div> 60 </div>
61 <% end %> 61 <% end %>
62 <% end %> 62 <% end %>
app/views/tasks/processed.rhtml
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 <ul> 7 <ul>
8 <% @tasks.each do |item| %> 8 <% @tasks.each do |item| %>
9 <li> 9 <li>
10 - <strong><%= item.information %></strong> <br/> 10 + <strong><%= task_information(item) %></strong> <br/>
11 <small> 11 <small>
12 <%= _('Created:') +' '+ show_date(item.created_at) %> 12 <%= _('Created:') +' '+ show_date(item.created_at) %>
13 &nbsp; &#151; &nbsp; 13 &nbsp; &#151; &nbsp;
app/views/user/mailer/signup_welcome_email.rhtml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 + <head>
  4 + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  5 + </head>
  6 + <body>
  7 + <p><%= word_wrap @body %></p>
  8 + </body>
  9 +</html>
config/initializers/action_tracker.rb
@@ -23,7 +23,28 @@ ActionTrackerConfig.verbs = { @@ -23,7 +23,28 @@ ActionTrackerConfig.verbs = {
23 }, 23 },
24 24
25 :upload_image => { 25 :upload_image => {
26 - :description => lambda { n_('uploaded 1 image<br />%{thumbnails}<br style="clear: both;" />', 'uploaded %{num} images<br />%{thumbnails}<br style="clear: both;" />', get_view_url.size) % { :num => get_view_url.size, :thumbnails => '{{ta.collect_group_with_index(:thumbnail_path){ |t,i| content_tag(:span, link_to(image_tag(t), ta.get_view_url[i]))}.last(3).join}}' } }, 26 + :description => lambda do
  27 + total = get_view_url.size
  28 + n_('uploaded 1 image', 'uploaded %d images', total) % total +
  29 + '<br />{{'+
  30 + 'ta.collect_group_with_index(:thumbnail_path) { |t,i|' +
  31 + " if ( #{total} == 1 );" +
  32 + ' link_to( image_tag(t), ta.get_view_url[i], :class => \'upimg\' );' +
  33 + ' else;' +
  34 + " pos = #{total}-i;" +
  35 + ' morethen2 = pos>2 ? \'morethen2\' : \'\';' +
  36 + ' morethen5 = pos>5 ? \'morethen5\' : \'\';' +
  37 + ' t = t.gsub(/(.*)(display)(.*)/, \'\\1thumb\\3\');' +
  38 + ' link_to( \'&nbsp;\', ta.get_view_url[i],' +
  39 + ' :style => "background-image:url(#{t})",' +
  40 + ' :class => "upimg pos#{pos} #{morethen2} #{morethen5}" );' +
  41 + ' end' +
  42 + '}.reverse.join}}' +
  43 + ( total > 5 ?
  44 + '<span class="more" onclick="this.parentNode.className+=\' show-all\'">' +
  45 + '&hellip;</span>' : '' ) +
  46 + '<br style="clear: both;" />'
  47 + end,
27 :type => :groupable 48 :type => :groupable
28 }, 49 },
29 50
config/initializers/plugins.rb
1 require 'noosfero/plugin' 1 require 'noosfero/plugin'
2 -require 'noosfero/plugin/acts_as_having_hotspots' 2 +require 'noosfero/plugin/hot_spot'
3 require 'noosfero/plugin/manager' 3 require 'noosfero/plugin/manager'
4 -require 'noosfero/plugin/context'  
5 require 'noosfero/plugin/active_record' 4 require 'noosfero/plugin/active_record'
6 require 'noosfero/plugin/mailer_base' 5 require 'noosfero/plugin/mailer_base'
7 Noosfero::Plugin.init_system if $NOOSFERO_LOAD_PLUGINS 6 Noosfero::Plugin.init_system if $NOOSFERO_LOAD_PLUGINS
config/routes.rb
@@ -19,16 +19,17 @@ ActionController::Routing::Routes.draw do |map| @@ -19,16 +19,17 @@ ActionController::Routing::Routes.draw do |map|
19 19
20 # -- just remember to delete public/index.html. 20 # -- just remember to delete public/index.html.
21 # You can have the root of your site routed by hooking up '' 21 # You can have the root of your site routed by hooking up ''
  22 + map.root :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
22 map.connect '', :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } 23 map.connect '', :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
23 map.home 'site/:action', :controller => 'home' 24 map.home 'site/:action', :controller => 'home'
24 25
25 - map.connect 'images/*stuff', :controller => 'not_found', :action => 'index'  
26 - map.connect 'stylesheets/*stuff', :controller => 'not_found', :action => 'index'  
27 - map.connect 'designs/*stuff', :controller => 'not_found', :action => 'index'  
28 - map.connect 'articles/*stuff', :controller => 'not_found', :action => 'index'  
29 - map.connect 'javascripts/*stuff', :controller => 'not_found', :action => 'index'  
30 - map.connect 'thumbnails/*stuff', :controller => 'not_found', :action => 'index'  
31 - map.connect 'user_themes/*stuff', :controller => 'not_found', :action => 'index' 26 + map.connect 'images/*stuff', :controller => 'not_found', :action => 'nothing'
  27 + map.connect 'stylesheets/*stuff', :controller => 'not_found', :action => 'nothing'
  28 + map.connect 'designs/*stuff', :controller => 'not_found', :action => 'nothing'
  29 + map.connect 'articles/*stuff', :controller => 'not_found', :action => 'nothing'
  30 + map.connect 'javascripts/*stuff', :controller => 'not_found', :action => 'nothing'
  31 + map.connect 'thumbnails/*stuff', :controller => 'not_found', :action => 'nothing'
  32 + map.connect 'user_themes/*stuff', :controller => 'not_found', :action => 'nothing'
32 33
33 # online documentation 34 # online documentation
34 map.doc 'doc', :controller => 'doc', :action => 'index' 35 map.doc 'doc', :controller => 'doc', :action => 'index'
@@ -121,9 +122,12 @@ ActionController::Routing::Routes.draw do |map| @@ -121,9 +122,12 @@ ActionController::Routing::Routes.draw do |map|
121 # cache stuff - hack 122 # cache stuff - hack
122 map.cache 'public/:action/:id', :controller => 'public' 123 map.cache 'public/:action/:id', :controller => 'public'
123 124
  125 + map.connect ':profile/edit_comment/:id/*page', :controller => 'content_viewer', :action => 'edit_comment', :profile => /#{Noosfero.identifier_format}/
  126 +
124 # match requests for profiles that don't have a custom domain 127 # match requests for profiles that don't have a custom domain
125 map.homepage ':profile/*page', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } 128 map.homepage ':profile/*page', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } }
126 129
  130 +
127 # match requests for content in domains hosted for profiles 131 # match requests for content in domains hosted for profiles
128 map.connect '*page', :controller => 'content_viewer', :action => 'view_page' 132 map.connect '*page', :controller => 'content_viewer', :action => 'view_page'
129 133
db/migrate/20120824165019_add_permission_for_send_mail_to_members_to_admin_and_moderator_roles.rb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +class AddPermissionForSendMailToMembersToAdminAndModeratorRoles < ActiveRecord::Migration
  2 + def self.up
  3 + Environment.all.map(&:id).each do |id|
  4 + role = Profile::Roles.admin(id)
  5 + role.permissions += ['send_mail_to_members']
  6 + role.save!
  7 + role = Profile::Roles.moderator(id)
  8 + role.permissions += ['send_mail_to_members']
  9 + role.save!
  10 + end
  11 + end
  12 +
  13 + def self.down
  14 + Environment.all.map(&:id).each do |id|
  15 + role = Profile::Roles.admin(id)
  16 + role.permissions -= ['send_mail_to_members']
  17 + role.save!
  18 + role = Profile::Roles.moderator(id)
  19 + role.permissions -= ['send_mail_to_members']
  20 + role.save!
  21 + end
  22 + end
  23 +end
db/migrate/20120824183534_add_redirection_after_login_to_environment.rb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +class AddRedirectionAfterLoginToEnvironment < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :environments, :redirection_after_login, :string, :default => 'keep_on_same_page'
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :environments, :redirection_after_login
  8 + end
  9 +end
db/migrate/20120824184046_add_redirection_after_login_to_profiles.rb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +class AddRedirectionAfterLoginToProfiles < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :profiles, :redirection_after_login, :string
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :profiles, :redirection_after_login
  8 + end
  9 +end
db/migrate/20120825185219_add_user_agent_and_referrer_to_comments.rb 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +class AddUserAgentAndReferrerToComments < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :comments, :user_agent, :string
  4 + add_column :comments, :referrer, :string
  5 + end
  6 +
  7 + def self.down
  8 + remove_column :comments, :user_agent
  9 + remove_column :comments, :referrer
  10 + end
  11 +end
db/migrate/20121008185303_add_signup_welcome_text.rb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +class AddSignupWelcomeText < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :environments, :signup_welcome_text, :text
  4 + end
  5 +
  6 + def self.down
  7 + remove_column :environments, :signup_welcome_text
  8 + end
  9 +end
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # 9 #
10 # It's strongly recommended to check this file into your version control system. 10 # It's strongly recommended to check this file into your version control system.
11 11
12 -ActiveRecord::Schema.define(:version => 20120818030329) do 12 +ActiveRecord::Schema.define(:version => 20121008185303) do
13 13
14 create_table "abuse_reports", :force => true do |t| 14 create_table "abuse_reports", :force => true do |t|
15 t.integer "reporter_id" 15 t.integer "reporter_id"
@@ -213,6 +213,8 @@ ActiveRecord::Schema.define(:version =&gt; 20120818030329) do @@ -213,6 +213,8 @@ ActiveRecord::Schema.define(:version =&gt; 20120818030329) do
213 t.string "ip_address" 213 t.string "ip_address"
214 t.boolean "spam" 214 t.boolean "spam"
215 t.string "source_type" 215 t.string "source_type"
  216 + t.string "user_agent"
  217 + t.string "referrer"
216 end 218 end
217 219
218 create_table "contact_lists", :force => true do |t| 220 create_table "contact_lists", :force => true do |t|
@@ -259,6 +261,8 @@ ActiveRecord::Schema.define(:version =&gt; 20120818030329) do @@ -259,6 +261,8 @@ ActiveRecord::Schema.define(:version =&gt; 20120818030329) do
259 t.datetime "created_at" 261 t.datetime "created_at"
260 t.datetime "updated_at" 262 t.datetime "updated_at"
261 t.integer "reports_lower_bound", :default => 0, :null => false 263 t.integer "reports_lower_bound", :default => 0, :null => false
  264 + t.string "redirection_after_login", :default => "keep_on_same_page"
  265 + t.text "signup_welcome_text"
262 end 266 end
263 267
264 create_table "external_feeds", :force => true do |t| 268 create_table "external_feeds", :force => true do |t|
@@ -436,6 +440,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120818030329) do @@ -436,6 +440,7 @@ ActiveRecord::Schema.define(:version =&gt; 20120818030329) do
436 t.string "national_region_code" 440 t.string "national_region_code"
437 t.boolean "is_template", :default => false 441 t.boolean "is_template", :default => false
438 t.integer "template_id" 442 t.integer "template_id"
  443 + t.string "redirection_after_login"
439 end 444 end
440 445
441 add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id" 446 add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id"
debian/changelog
  1 +noosfero (0.39.0~1) UNRELEASED; urgency=low
  2 +
  3 + * Pre-release to test the antispam mechanism.
  4 +
  5 + -- Antonio Terceiro <terceiro@debian.org> Thu, 30 Aug 2012 14:55:10 -0300
  6 +
  7 +noosfero (0.38.2) unstable; urgency=low
  8 +
  9 + * Bugfixes release
  10 +
  11 + -- Antonio Terceiro <terceiro@colivre.coop.br> Wed, 05 Sep 2012 10:07:58 -0300
  12 +
1 noosfero (0.38.1) unstable; urgency=low 13 noosfero (0.38.1) unstable; urgency=low
2 14
3 * Bugfixes release 15 * Bugfixes release
debian/control
@@ -62,8 +62,7 @@ Description: free web-based platform for social networks @@ -62,8 +62,7 @@ Description: free web-based platform for social networks
62 62
63 Package: noosfero-apache 63 Package: noosfero-apache
64 Architecture: all 64 Architecture: all
65 -Depends: apache2, debconf  
66 -Suggests: noosfero 65 +Depends: apache2, debconf, noosfero
67 Description: free web-based platform for social networks (apache frontend) 66 Description: free web-based platform for social networks (apache frontend)
68 Noosfero is a web platform for social and solidarity economy networks with 67 Noosfero is a web platform for social and solidarity economy networks with
69 blog, e-Porfolios, CMS, RSS, thematic discussion, events agenda and collective 68 blog, e-Porfolios, CMS, RSS, thematic discussion, events agenda and collective
debian/noosfero-console
@@ -2,4 +2,7 @@ @@ -2,4 +2,7 @@
2 2
3 set -e 3 set -e
4 4
5 -cd /usr/share/noosfero && su noosfero -c "./script/console production" 5 +environment="$1"
  6 +test -z "$environment" && environment=production
  7 +
  8 +cd /usr/share/noosfero && su noosfero -c "./script/console $environment"
etc/noosfero/varnish-noosfero.vcl
1 sub vcl_recv { 1 sub vcl_recv {
  2 + if (req.request == "GET" || req.request == "HEAD") {
2 if (req.http.Cookie) { 3 if (req.http.Cookie) {
3 - # We only care about the "_noosfero_session.*" cookie, used for  
4 - # authentication.  
5 - if (req.http.Cookie ~ "_noosfero_session.*" ) {  
6 - return (pass);  
7 - }  
8 - # Else strip all cookies 4 + # We only care about the "_noosfero_session.*" cookie, used for
  5 + # authentication.
  6 + if (req.http.Cookie !~ "_noosfero_session.*" ) {
  7 + # strip all cookies
9 unset req.http.Cookie; 8 unset req.http.Cookie;
  9 + }
10 } 10 }
  11 + }
11 } 12 }
12 13
13 sub vcl_error { 14 sub vcl_error {
features/edit_environment_templates.feature
@@ -8,7 +8,7 @@ Feature: edit environment templates @@ -8,7 +8,7 @@ Feature: edit environment templates
8 Scenario: See links to edit all templates 8 Scenario: See links to edit all templates
9 Given I am logged in as admin 9 Given I am logged in as admin
10 When I follow "Administration" 10 When I follow "Administration"
11 - And I follow "Edit Templates" 11 + And I follow "Profile templates"
12 Then I should see "Person template" link 12 Then I should see "Person template" link
13 And I should see "Community template" link 13 And I should see "Community template" link
14 And I should see "Enterprise template" link 14 And I should see "Enterprise template" link
@@ -17,28 +17,28 @@ Feature: edit environment templates @@ -17,28 +17,28 @@ Feature: edit environment templates
17 Scenario: Go to control panel of person template 17 Scenario: Go to control panel of person template
18 Given I am logged in as admin 18 Given I am logged in as admin
19 When I follow "Administration" 19 When I follow "Administration"
20 - And I follow "Edit Templates" 20 + And I follow "Profile templates"
21 And I follow "Person template" 21 And I follow "Person template"
22 Then I should be on Person template's control panel 22 Then I should be on Person template's control panel
23 23
24 Scenario: Go to control panel of enterprise template 24 Scenario: Go to control panel of enterprise template
25 Given I am logged in as admin 25 Given I am logged in as admin
26 When I follow "Administration" 26 When I follow "Administration"
27 - And I follow "Edit Templates" 27 + And I follow "Profile templates"
28 And I follow "Enterprise template" 28 And I follow "Enterprise template"
29 Then I should be on Enterprise template's control panel 29 Then I should be on Enterprise template's control panel
30 30
31 Scenario: Go to control panel of inactive enterprise template 31 Scenario: Go to control panel of inactive enterprise template
32 Given I am logged in as admin 32 Given I am logged in as admin
33 When I follow "Administration" 33 When I follow "Administration"
34 - And I follow "Edit Templates" 34 + And I follow "Profile templates"
35 And I follow "Inactive enterprise template" 35 And I follow "Inactive enterprise template"
36 Then I should be on Inactive Enterprise template's control panel 36 Then I should be on Inactive Enterprise template's control panel
37 37
38 Scenario: Go to control panel of community template 38 Scenario: Go to control panel of community template
39 Given I am logged in as admin 39 Given I am logged in as admin
40 When I follow "Administration" 40 When I follow "Administration"
41 - And I follow "Edit Templates" 41 + And I follow "Profile templates"
42 And I follow "Community template" 42 And I follow "Community template"
43 Then I should be on Community template's control panel 43 Then I should be on Community template's control panel
44 44
@@ -46,7 +46,7 @@ Feature: edit environment templates @@ -46,7 +46,7 @@ Feature: edit environment templates
46 Given that the default environment have no Inactive Enterprise template 46 Given that the default environment have no Inactive Enterprise template
47 And I am logged in as admin 47 And I am logged in as admin
48 When I follow "Administration" 48 When I follow "Administration"
49 - And I follow "Edit Templates" 49 + And I follow "Profile templates"
50 Then I should see "Person template" link 50 Then I should see "Person template" link
51 And I should see "Community template" link 51 And I should see "Community template" link
52 And I should see "Enterprise template" link 52 And I should see "Enterprise template" link