Commit 9508041164c47c02745ffce877414b9cb58495f9
Exists in
master
and in
29 other branches
Merge branch 'master' into language-selection
Conflicts: app/helpers/forms_helper.rb app/models/box.rb app/views/box_organizer/edit.rhtml db/schema.rb test/unit/box_test.rb
Showing
273 changed files
with
8742 additions
and
1192 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 273 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? |
@@ -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 < ApplicationController | @@ -25,11 +25,13 @@ class AccountController < 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 < ApplicationController | @@ -41,7 +43,6 @@ class AccountController < 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 < ApplicationController | @@ -56,6 +57,11 @@ class AccountController < 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 < ApplicationController | @@ -125,6 +131,10 @@ class AccountController < 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? |
@@ -316,4 +326,13 @@ class AccountController < ApplicationController | @@ -316,4 +326,13 @@ class AccountController < ApplicationController | ||
316 | end | 326 | end |
317 | end | 327 | end |
318 | 328 | ||
329 | + def plugins_alternative_authentication | ||
330 | + user = nil | ||
331 | + @plugins.each do |plugin| | ||
332 | + user = plugin.alternative_authentication | ||
333 | + break unless user.nil? | ||
334 | + end | ||
335 | + user | ||
336 | + end | ||
337 | + | ||
319 | end | 338 | end |
app/controllers/public/content_viewer_controller.rb
@@ -2,6 +2,8 @@ class ContentViewerController < ApplicationController | @@ -2,6 +2,8 @@ class ContentViewerController < 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 < ApplicationController | @@ -19,7 +21,7 @@ class ContentViewerController < 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 < ApplicationController | @@ -75,8 +77,14 @@ class ContentViewerController < 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 < ApplicationController | @@ -107,23 +115,46 @@ class ContentViewerController < 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 < ApplicationController | @@ -138,12 +169,6 @@ class ContentViewerController < 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 < ApplicationController | @@ -153,9 +178,24 @@ class ContentViewerController < 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 < ApplicationController | @@ -181,4 +221,13 @@ class ContentViewerController < 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/profile_controller.rb
@@ -212,9 +212,9 @@ class ProfileController < PublicController | @@ -212,9 +212,9 @@ class ProfileController < PublicController | ||
212 | begin | 212 | begin |
213 | scrap = current_user.person.scraps(params[:scrap_id]) | 213 | scrap = current_user.person.scraps(params[:scrap_id]) |
214 | scrap.destroy | 214 | scrap.destroy |
215 | - render :text => _('Scrap successfully removed.') | 215 | + finish_successful_removal 'Scrap successfully removed.' |
216 | rescue | 216 | rescue |
217 | - render :text => _('You could not remove this scrap') | 217 | + finish_unsuccessful_removal 'You could not remove this scrap.' |
218 | end | 218 | end |
219 | end | 219 | end |
220 | 220 | ||
@@ -227,9 +227,9 @@ class ProfileController < PublicController | @@ -227,9 +227,9 @@ class ProfileController < PublicController | ||
227 | else | 227 | else |
228 | activity.destroy | 228 | activity.destroy |
229 | end | 229 | end |
230 | - render :text => _('Activity successfully removed.') | 230 | + finish_successful_removal 'Activity successfully removed.' |
231 | rescue | 231 | rescue |
232 | - render :text => _('You could not remove this activity') | 232 | + finish_unsuccessful_removal 'You could not remove this activity.' |
233 | end | 233 | end |
234 | end | 234 | end |
235 | 235 | ||
@@ -244,6 +244,24 @@ class ProfileController < PublicController | @@ -244,6 +244,24 @@ class ProfileController < PublicController | ||
244 | end | 244 | end |
245 | end | 245 | end |
246 | 246 | ||
247 | + def finish_successful_removal(msg) | ||
248 | + if request.xhr? | ||
249 | + render :text => {'ok' => true}.to_json, :content_type => 'application/json' | ||
250 | + else | ||
251 | + session[:notice] = _(msg) | ||
252 | + redirect_to :action => :index | ||
253 | + end | ||
254 | + end | ||
255 | + | ||
256 | + def finish_unsuccessful_removal(msg) | ||
257 | + session[:notice] = _(msg) | ||
258 | + if request.xhr? | ||
259 | + render :text => {'redirect' => url_for(:action => :index)}.to_json, :content_type => 'application/json' | ||
260 | + else | ||
261 | + redirect_to :action => :index | ||
262 | + end | ||
263 | + end | ||
264 | + | ||
247 | def profile_info | 265 | def profile_info |
248 | begin | 266 | begin |
249 | @block = profile.blocks.find(params[:block_id]) | 267 | @block = profile.blocks.find(params[:block_id]) |
@@ -303,9 +321,10 @@ class ProfileController < PublicController | @@ -303,9 +321,10 @@ class ProfileController < PublicController | ||
303 | @comment = Comment.find(params[:comment_id]) | 321 | @comment = Comment.find(params[:comment_id]) |
304 | if (user == @comment.author || user == profile || user.has_permission?(:moderate_comments, profile)) | 322 | if (user == @comment.author || user == profile || user.has_permission?(:moderate_comments, profile)) |
305 | @comment.destroy | 323 | @comment.destroy |
306 | - session[:notice] = _('Comment successfully deleted') | 324 | + finish_successful_removal 'Comment successfully removed.' |
325 | + else | ||
326 | + finish_unsuccessful_removal 'You could not remove this comment.' | ||
307 | end | 327 | end |
308 | - redirect_to :action => :index | ||
309 | end | 328 | end |
310 | 329 | ||
311 | protected | 330 | protected |
app/controllers/public/search_controller.rb
@@ -4,10 +4,17 @@ class SearchController < PublicController | @@ -4,10 +4,17 @@ class SearchController < 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 |
@@ -250,10 +257,9 @@ class SearchController < PublicController | @@ -250,10 +257,9 @@ class SearchController < 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 < PublicController | @@ -267,31 +273,34 @@ class SearchController < 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 |
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?("/") |
@@ -285,28 +285,17 @@ module ApplicationHelper | @@ -285,28 +285,17 @@ module ApplicationHelper | ||
285 | partial_for_class_in_view_path(klass.superclass, view_path) | 285 | partial_for_class_in_view_path(klass.superclass, view_path) |
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', ' '+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/boxes_helper.rb
@@ -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', ' ', :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', ' ', :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/forms_helper.rb
@@ -142,6 +142,119 @@ module FormsHelper | @@ -142,6 +142,119 @@ module FormsHelper | ||
142 | content_tag('table',rows.join("\n")) | 142 | content_tag('table',rows.join("\n")) |
143 | end | 143 | end |
144 | 144 | ||
145 | + def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) | ||
146 | + datepicker_options[:disabled] ||= false | ||
147 | + datepicker_options[:alt_field] ||= '' | ||
148 | + datepicker_options[:alt_format] ||= '' | ||
149 | + datepicker_options[:append_text] ||= '' | ||
150 | + datepicker_options[:auto_size] ||= false | ||
151 | + datepicker_options[:button_image] ||= '' | ||
152 | + datepicker_options[:button_image_only] ||= false | ||
153 | + datepicker_options[:button_text] ||= '...' | ||
154 | + datepicker_options[:calculate_week] ||= 'jQuery.datepicker.iso8601Week' | ||
155 | + datepicker_options[:change_month] ||= false | ||
156 | + datepicker_options[:change_year] ||= false | ||
157 | + datepicker_options[:close_text] ||= _('Done') | ||
158 | + datepicker_options[:constrain_input] ||= true | ||
159 | + datepicker_options[:current_text] ||= _('Today') | ||
160 | + datepicker_options[:date_format] ||= 'mm/dd/yy' | ||
161 | + datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')] | ||
162 | + datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')] | ||
163 | + datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')] | ||
164 | + datepicker_options[:default_date] ||= nil | ||
165 | + datepicker_options[:duration] ||= 'normal' | ||
166 | + datepicker_options[:first_day] ||= 0 | ||
167 | + datepicker_options[:goto_current] ||= false | ||
168 | + datepicker_options[:hide_if_no_prev_next] ||= false | ||
169 | + datepicker_options[:is_rtl] ||= false | ||
170 | + datepicker_options[:max_date] ||= nil | ||
171 | + datepicker_options[:min_date] ||= nil | ||
172 | + datepicker_options[:month_names] ||= [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), _('September'), _('October'), _('November'), _('December')] | ||
173 | + datepicker_options[:month_names_short] ||= [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')] | ||
174 | + datepicker_options[:navigation_as_date_format] ||= false | ||
175 | + datepicker_options[:next_text] ||= _('Next') | ||
176 | + datepicker_options[:number_of_months] ||= 1 | ||
177 | + datepicker_options[:prev_text] ||= _('Prev') | ||
178 | + datepicker_options[:select_other_months] ||= false | ||
179 | + datepicker_options[:short_year_cutoff] ||= '+10' | ||
180 | + datepicker_options[:show_button_panel] ||= false | ||
181 | + datepicker_options[:show_current_at_pos] ||= 0 | ||
182 | + datepicker_options[:show_month_after_year] ||= false | ||
183 | + datepicker_options[:show_on] ||= 'focus' | ||
184 | + datepicker_options[:show_options] ||= {} | ||
185 | + datepicker_options[:show_other_months] ||= false | ||
186 | + datepicker_options[:show_week] ||= false | ||
187 | + datepicker_options[:step_months] ||= 1 | ||
188 | + datepicker_options[:week_header] ||= _('Wk') | ||
189 | + datepicker_options[:year_range] ||= 'c-10:c+10' | ||
190 | + datepicker_options[:year_suffix] ||= '' | ||
191 | + | ||
192 | + element_id = html_options[:id] || 'datepicker-date' | ||
193 | + value = value.strftime(format) if value.present? | ||
194 | + method = datepicker_options[:time] ? 'datetimepicker' : 'datepicker' | ||
195 | + result = text_field_tag(name, value, html_options) | ||
196 | + result += | ||
197 | + " | ||
198 | + <script type='text/javascript'> | ||
199 | + jQuery('##{element_id}').#{method}({ | ||
200 | + disabled: #{datepicker_options[:disabled].to_json}, | ||
201 | + altField: #{datepicker_options[:alt_field].to_json}, | ||
202 | + altFormat: #{datepicker_options[:alt_format].to_json}, | ||
203 | + appendText: #{datepicker_options[:append_text].to_json}, | ||
204 | + autoSize: #{datepicker_options[:auto_size].to_json}, | ||
205 | + buttonImage: #{datepicker_options[:button_image].to_json}, | ||
206 | + buttonImageOnly: #{datepicker_options[:button_image_only].to_json}, | ||
207 | + buttonText: #{datepicker_options[:button_text].to_json}, | ||
208 | + calculateWeek: #{datepicker_options[:calculate_week].to_json}, | ||
209 | + changeMonth: #{datepicker_options[:change_month].to_json}, | ||
210 | + changeYear: #{datepicker_options[:change_year].to_json}, | ||
211 | + closeText: #{datepicker_options[:close_text].to_json}, | ||
212 | + constrainInput: #{datepicker_options[:constrain_input].to_json}, | ||
213 | + currentText: #{datepicker_options[:current_text].to_json}, | ||
214 | + dateFormat: #{datepicker_options[:date_format].to_json}, | ||
215 | + dayNames: #{datepicker_options[:day_names].to_json}, | ||
216 | + dayNamesMin: #{datepicker_options[:day_names_min].to_json}, | ||
217 | + dayNamesShort: #{datepicker_options[:day_names_short].to_json}, | ||
218 | + defaultDate: #{datepicker_options[:default_date].to_json}, | ||
219 | + duration: #{datepicker_options[:duration].to_json}, | ||
220 | + firstDay: #{datepicker_options[:first_day].to_json}, | ||
221 | + gotoCurrent: #{datepicker_options[:goto_current].to_json}, | ||
222 | + hideIfNoPrevNext: #{datepicker_options[:hide_if_no_prev_next].to_json}, | ||
223 | + isRTL: #{datepicker_options[:is_rtl].to_json}, | ||
224 | + maxDate: #{datepicker_options[:max_date].to_json}, | ||
225 | + minDate: #{datepicker_options[:min_date].to_json}, | ||
226 | + monthNames: #{datepicker_options[:month_names].to_json}, | ||
227 | + monthNamesShort: #{datepicker_options[:month_names_short].to_json}, | ||
228 | + navigationAsDateFormat: #{datepicker_options[:navigation_as_date_format].to_json}, | ||
229 | + nextText: #{datepicker_options[:next_text].to_json}, | ||
230 | + numberOfMonths: #{datepicker_options[:number_of_months].to_json}, | ||
231 | + prevText: #{datepicker_options[:prev_text].to_json}, | ||
232 | + selectOtherMonths: #{datepicker_options[:select_other_months].to_json}, | ||
233 | + shortYearCutoff: #{datepicker_options[:short_year_cutoff].to_json}, | ||
234 | + showButtonPanel: #{datepicker_options[:show_button_panel].to_json}, | ||
235 | + showCurrentAtPos: #{datepicker_options[:show_current_at_pos].to_json}, | ||
236 | + showMonthAfterYear: #{datepicker_options[:show_month_after_year].to_json}, | ||
237 | + showOn: #{datepicker_options[:show_on].to_json}, | ||
238 | + showOptions: #{datepicker_options[:show_options].to_json}, | ||
239 | + showOtherMonths: #{datepicker_options[:show_other_months].to_json}, | ||
240 | + showWeek: #{datepicker_options[:show_week].to_json}, | ||
241 | + stepMonths: #{datepicker_options[:step_months].to_json}, | ||
242 | + weekHeader: #{datepicker_options[:week_header].to_json}, | ||
243 | + yearRange: #{datepicker_options[:year_range].to_json}, | ||
244 | + yearSuffix: #{datepicker_options[:year_suffix].to_json} | ||
245 | + }) | ||
246 | + </script> | ||
247 | + " | ||
248 | + result | ||
249 | + end | ||
250 | + | ||
251 | + def date_range_field(from_name, to_name, from_value, to_value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) | ||
252 | + from_id = html_options[:from_id] || 'datepicker-from-date' | ||
253 | + to_id = html_options[:to_id] || 'datepicker-to-date' | ||
254 | + return _('From') +' '+ date_field(from_name, from_value, format, datepicker_options, html_options.merge({:id => from_id})) + | ||
255 | + ' ' + _('until') +' '+ date_field(to_name, to_value, format, datepicker_options, html_options.merge({:id => to_id})) | ||
256 | + end | ||
257 | + | ||
145 | protected | 258 | protected |
146 | def self.next_id_number | 259 | def self.next_id_number |
147 | if defined? @@id_num | 260 | 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/box.rb
@@ -6,4 +6,76 @@ class Box < ActiveRecord::Base | @@ -6,4 +6,76 @@ class Box < ActiveRecord::Base | ||
6 | def environment | 6 | def environment |
7 | owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil | 7 | owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil |
8 | end | 8 | end |
9 | + | ||
10 | + def acceptable_blocks | ||
11 | + to_css_class_name central? ? Box.acceptable_center_blocks : Box.acceptable_side_blocks | ||
12 | + end | ||
13 | + | ||
14 | + def central? | ||
15 | + position == 1 | ||
16 | + end | ||
17 | + | ||
18 | + def self.acceptable_center_blocks | ||
19 | + [ ArticleBlock, | ||
20 | + BlogArchivesBlock, | ||
21 | + CategoriesBlock, | ||
22 | + CommunitiesBlock, | ||
23 | + EnterprisesBlock, | ||
24 | + EnvironmentStatisticsBlock, | ||
25 | + FansBlock, | ||
26 | + FavoriteEnterprisesBlock, | ||
27 | + FeedReaderBlock, | ||
28 | + FriendsBlock, | ||
29 | + HighlightsBlock, | ||
30 | + LinkListBlock, | ||
31 | + LoginBlock, | ||
32 | + MainBlock, | ||
33 | + MembersBlock, | ||
34 | + MyNetworkBlock, | ||
35 | + PeopleBlock, | ||
36 | + ProfileImageBlock, | ||
37 | + RawHTMLBlock, | ||
38 | + RecentDocumentsBlock, | ||
39 | + SellersSearchBlock, | ||
40 | + TagsBlock ] | ||
41 | + end | ||
42 | + | ||
43 | + def self.acceptable_side_blocks | ||
44 | + [ ArticleBlock, | ||
45 | + BlogArchivesBlock, | ||
46 | + CategoriesBlock, | ||
47 | + CommunitiesBlock, | ||
48 | + DisabledEnterpriseMessageBlock, | ||
49 | + EnterprisesBlock, | ||
50 | + EnvironmentStatisticsBlock, | ||
51 | + FansBlock, | ||
52 | + FavoriteEnterprisesBlock, | ||
53 | + FeaturedProductsBlock, | ||
54 | + FeedReaderBlock, | ||
55 | + FriendsBlock, | ||
56 | + HighlightsBlock, | ||
57 | + LinkListBlock, | ||
58 | + LocationBlock, | ||
59 | + LoginBlock, | ||
60 | + MembersBlock, | ||
61 | + MyNetworkBlock, | ||
62 | + PeopleBlock, | ||
63 | + ProductsBlock, | ||
64 | + ProfileImageBlock, | ||
65 | + ProfileInfoBlock, | ||
66 | + ProfileSearchBlock, | ||
67 | + RawHTMLBlock, | ||
68 | + RecentDocumentsBlock, | ||
69 | + SellersSearchBlock, | ||
70 | + SlideshowBlock, | ||
71 | + TagsBlock | ||
72 | + ] | ||
73 | + end | ||
74 | + | ||
75 | + private | ||
76 | + | ||
77 | + def to_css_class_name(blocks) | ||
78 | + blocks.map{ |block| block.to_s.underscore.tr('_', '-') } | ||
79 | + end | ||
80 | + | ||
9 | end | 81 | end |
app/models/comment.rb
@@ -10,6 +10,9 @@ class Comment < ActiveRecord::Base | @@ -10,6 +10,9 @@ class Comment < 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 < ActiveRecord::Base | @@ -25,6 +28,8 @@ class Comment < 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 < ActiveRecord::Base | @@ -85,7 +90,28 @@ class Comment < 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 < ActiveRecord::Base | @@ -123,10 +149,14 @@ class Comment < 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 < ActiveRecord::Base | @@ -183,4 +213,34 @@ class Comment < 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/community.rb
@@ -88,7 +88,7 @@ class Community < Organization | @@ -88,7 +88,7 @@ class Community < 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/person.rb
@@ -22,8 +22,6 @@ class Person < Profile | @@ -22,8 +22,6 @@ class Person < 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 < Profile | @@ -32,7 +30,7 @@ class Person < 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 < Profile | @@ -73,10 +71,7 @@ class Person < 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 |
@@ -458,7 +453,7 @@ class Person < Profile | @@ -458,7 +453,7 @@ class Person < 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 < ActiveRecord::Base | @@ -163,7 +164,7 @@ class Product < 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
@@ -60,7 +60,8 @@ class Profile < ActiveRecord::Base | @@ -60,7 +60,8 @@ class Profile < ActiveRecord::Base | ||
60 | } | 60 | } |
61 | 61 | ||
62 | acts_as_accessible | 62 | acts_as_accessible |
63 | - acts_as_having_hotspots | 63 | + |
64 | + include Noosfero::Plugin::HotSpot | ||
64 | 65 | ||
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 ] } } | 66 | 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 | 67 | #FIXME: these will work only if the subclass is already loaded |
@@ -69,7 +70,7 @@ class Profile < ActiveRecord::Base | @@ -69,7 +70,7 @@ class Profile < ActiveRecord::Base | ||
69 | named_scope :templates, :conditions => {:is_template => true} | 70 | named_scope :templates, :conditions => {:is_template => true} |
70 | 71 | ||
71 | def members | 72 | def members |
72 | - scopes = dispatch_scopes(:organization_members, self) | 73 | + scopes = plugins.dispatch_scopes(:organization_members, self) |
73 | scopes << Person.members_of(self) | 74 | scopes << Person.members_of(self) |
74 | scopes.size == 1 ? scopes.first : Person.or_scope(scopes) | 75 | scopes.size == 1 ? scopes.first : Person.or_scope(scopes) |
75 | end | 76 | end |
@@ -113,6 +114,8 @@ class Profile < ActiveRecord::Base | @@ -113,6 +114,8 @@ class Profile < ActiveRecord::Base | ||
113 | has_many :scraps_received, :class_name => 'Scrap', :foreign_key => :receiver_id, :order => "updated_at DESC", :dependent => :destroy | 114 | 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' | 115 | belongs_to :template, :class_name => 'Profile', :foreign_key => 'template_id' |
115 | 116 | ||
117 | + has_many :comments_received, :class_name => 'Comment', :through => :articles, :source => :comments | ||
118 | + | ||
116 | # FIXME ugly workaround | 119 | # FIXME ugly workaround |
117 | def self.human_attribute_name(attrib) | 120 | def self.human_attribute_name(attrib) |
118 | _(self.superclass.human_attribute_name(attrib)) | 121 | _(self.superclass.human_attribute_name(attrib)) |
@@ -255,7 +258,7 @@ class Profile < ActiveRecord::Base | @@ -255,7 +258,7 @@ class Profile < ActiveRecord::Base | ||
255 | self.categories(true) | 258 | self.categories(true) |
256 | self.solr_save | 259 | self.solr_save |
257 | end | 260 | end |
258 | - self.categories(reload) | 261 | + self.categories(reload) |
259 | end | 262 | end |
260 | 263 | ||
261 | def category_ids=(ids) | 264 | def category_ids=(ids) |
app/models/task.rb
@@ -31,7 +31,7 @@ class Task < ActiveRecord::Base | @@ -31,7 +31,7 @@ class Task < 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 < Article | @@ -67,7 +67,7 @@ class UploadedFile < 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 < Article | @@ -129,6 +129,12 @@ class UploadedFile < 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 < Article | @@ -144,4 +150,5 @@ class UploadedFile < 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 < ActiveRecord::Base | @@ -30,7 +30,7 @@ class User < 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! |
@@ -88,13 +88,13 @@ class User < ActiveRecord::Base | @@ -88,13 +88,13 @@ class User < ActiveRecord::Base | ||
88 | attr_protected :activated_at | 88 | attr_protected :activated_at |
89 | 89 | ||
90 | # Virtual attribute for the unencrypted password | 90 | # Virtual attribute for the unencrypted password |
91 | - attr_accessor :password | 91 | + attr_accessor :password, :name |
92 | 92 | ||
93 | validates_presence_of :login, :email | 93 | validates_presence_of :login, :email |
94 | validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?}) | 94 | validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?}) |
95 | validates_presence_of :password, :if => :password_required? | 95 | 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?}) | 96 | + validates_presence_of :password_confirmation, :if => :password_required? |
97 | + validates_length_of :password, :within => 4..40, :if => :password_required? | ||
98 | validates_confirmation_of :password, :if => :password_required? | 98 | validates_confirmation_of :password, :if => :password_required? |
99 | validates_length_of :login, :within => 2..40, :if => (lambda {|user| !user.login.blank?}) | 99 | 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?}) | 100 | validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?}) |
@@ -228,7 +228,12 @@ class User < ActiveRecord::Base | @@ -228,7 +228,12 @@ class User < ActiveRecord::Base | ||
228 | end | 228 | end |
229 | 229 | ||
230 | def name | 230 | def name |
231 | - person ? person.name : login | 231 | + name = (self[:name] || login) |
232 | + person.nil? ? name : (person.name || name) | ||
233 | + end | ||
234 | + | ||
235 | + def name= name | ||
236 | + self[:name] = name | ||
232 | end | 237 | end |
233 | 238 | ||
234 | def enable_email! | 239 | def enable_email! |
@@ -274,6 +279,11 @@ class User < ActiveRecord::Base | @@ -274,6 +279,11 @@ class User < ActiveRecord::Base | ||
274 | 15 # in minutes | 279 | 15 # in minutes |
275 | end | 280 | end |
276 | 281 | ||
282 | + | ||
283 | + def not_require_password! | ||
284 | + @is_password_required = false | ||
285 | + end | ||
286 | + | ||
277 | protected | 287 | protected |
278 | # before filter | 288 | # before filter |
279 | def encrypt_password | 289 | def encrypt_password |
@@ -282,9 +292,13 @@ class User < ActiveRecord::Base | @@ -282,9 +292,13 @@ class User < ActiveRecord::Base | ||
282 | self.password_type ||= User.system_encryption_method.to_s | 292 | self.password_type ||= User.system_encryption_method.to_s |
283 | self.crypted_password = encrypt(password) | 293 | self.crypted_password = encrypt(password) |
284 | end | 294 | end |
285 | - | 295 | + |
286 | def password_required? | 296 | def password_required? |
287 | - crypted_password.blank? || !password.blank? | 297 | + (crypted_password.blank? || !password.blank?) && is_password_required? |
298 | + end | ||
299 | + | ||
300 | + def is_password_required? | ||
301 | + @is_password_required.nil? ? true : @is_password_required | ||
288 | end | 302 | end |
289 | 303 | ||
290 | def make_activation_code | 304 | def make_activation_code |
@@ -292,6 +306,7 @@ class User < ActiveRecord::Base | @@ -292,6 +306,7 @@ class User < ActiveRecord::Base | ||
292 | end | 306 | end |
293 | 307 | ||
294 | def deliver_activation_code | 308 | def deliver_activation_code |
309 | + return if person.is_template? | ||
295 | User::Mailer.deliver_activation_code(self) unless self.activation_code.blank? | 310 | User::Mailer.deliver_activation_code(self) unless self.activation_code.blank? |
296 | end | 311 | end |
297 | 312 |
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/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> |
@@ -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
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']] + environment.locales.map {|key, value| [value, key]} )) %> | 25 | <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + environment.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/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? && ' ' || 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 | + | ||
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 | + | ||
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 | + | ||
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 | + | ||
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 | + | ||
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/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/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/_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/_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_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/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 |
@@ -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 | — | 13 | — |
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( \' \', 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 | + '…</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,6 +19,7 @@ ActionController::Routing::Routes.draw do |map| | @@ -19,6 +19,7 @@ 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 | ||
@@ -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/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/schema.rb
@@ -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 => 20120823215007) do | 12 | +ActiveRecord::Schema.define(:version => 20120825185219) 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 => 20120823215007) do | @@ -213,6 +213,8 @@ ActiveRecord::Schema.define(:version => 20120823215007) 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| |
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
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 |
features/environment_name.feature
@@ -6,7 +6,7 @@ Feature: setting environment name | @@ -6,7 +6,7 @@ Feature: setting environment name | ||
6 | Scenario: setting environment name through administration panel | 6 | Scenario: setting environment name through administration panel |
7 | Given I am logged in as admin | 7 | Given I am logged in as admin |
8 | When I follow "Administration" | 8 | When I follow "Administration" |
9 | - And I follow "Edit environment settings" | 9 | + And I follow "Environment settings" |
10 | And I fill in "Site name" with "My environment" | 10 | And I fill in "Site name" with "My environment" |
11 | And I press "Save" | 11 | And I press "Save" |
12 | Then I should see "My environment" within "title" | 12 | Then I should see "My environment" within "title" |
features/export_users.feature
@@ -10,14 +10,14 @@ Feature: export users | @@ -10,14 +10,14 @@ Feature: export users | ||
10 | Scenario: Export users as XML | 10 | Scenario: Export users as XML |
11 | Given I am logged in as admin | 11 | Given I am logged in as admin |
12 | When I follow "Administration" | 12 | When I follow "Administration" |
13 | - And I follow "Manage users" | 13 | + And I follow "Users" |
14 | And I follow "[XML]" | 14 | And I follow "[XML]" |
15 | Then I should see "ultraje" | 15 | Then I should see "ultraje" |
16 | 16 | ||
17 | Scenario: Export users as CSV | 17 | Scenario: Export users as CSV |
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 "Manage users" | 20 | + And I follow "Users" |
21 | And I follow "[CSV]" | 21 | And I follow "[CSV]" |
22 | Then I should see "name;email" | 22 | Then I should see "name;email" |
23 | And I should see "ultraje" | 23 | And I should see "ultraje" |
features/manage_categories.feature
@@ -14,7 +14,7 @@ Feature: manage categories | @@ -14,7 +14,7 @@ Feature: manage categories | ||
14 | | Development | services | | 14 | | Development | services | |
15 | And I am logged in as admin | 15 | And I am logged in as admin |
16 | And I am on the environment control panel | 16 | And I am on the environment control panel |
17 | - And I follow "Manage categories" | 17 | + And I follow "Categories" |
18 | 18 | ||
19 | Scenario: load only top level categories | 19 | Scenario: load only top level categories |
20 | Then I should see "Products" | 20 | Then I should see "Products" |
features/plugins.feature
@@ -49,7 +49,7 @@ Feature: plugins | @@ -49,7 +49,7 @@ Feature: plugins | ||
49 | When I go to the profile | 49 | When I go to the profile |
50 | Then I should see "Test plugin tab" | 50 | Then I should see "Test plugin tab" |
51 | And I go to the environment control panel | 51 | And I go to the environment control panel |
52 | - And I follow "Enable/disable plugins" | 52 | + And I follow "Plugins" |
53 | And I uncheck "Test plugin" | 53 | And I uncheck "Test plugin" |
54 | And I press "Save changes" | 54 | And I press "Save changes" |
55 | When I go to the Control panel | 55 | When I go to the Control panel |
features/roles.feature
@@ -5,26 +5,26 @@ Feature: manage roles | @@ -5,26 +5,26 @@ Feature: manage roles | ||
5 | Scenario: create new role | 5 | Scenario: create new role |
6 | Given I am logged in as admin | 6 | Given I am logged in as admin |
7 | And I go to the environment control panel | 7 | And I go to the environment control panel |
8 | - And I follow "Manage User roles" | 8 | + And I follow "User roles" |
9 | Then I should not see "My new role" | 9 | Then I should not see "My new role" |
10 | And I follow "Create a new role" | 10 | And I follow "Create a new role" |
11 | And I fill in "Name" with "My new role" | 11 | And I fill in "Name" with "My new role" |
12 | And I check "Publish content" | 12 | And I check "Publish content" |
13 | And I press "Create role" | 13 | And I press "Create role" |
14 | And I go to the environment control panel | 14 | And I go to the environment control panel |
15 | - And I follow "Manage User roles" | 15 | + And I follow "User roles" |
16 | Then I should see "My new role" | 16 | Then I should see "My new role" |
17 | 17 | ||
18 | Scenario: edit a role | 18 | Scenario: edit a role |
19 | Given I am logged in as admin | 19 | Given I am logged in as admin |
20 | And I go to the environment control panel | 20 | And I go to the environment control panel |
21 | - And I follow "Manage User roles" | 21 | + And I follow "User roles" |
22 | Then I should not see "My new role" | 22 | Then I should not see "My new role" |
23 | And I follow "Profile Administrator" | 23 | And I follow "Profile Administrator" |
24 | And I follow "Edit" | 24 | And I follow "Edit" |
25 | And I fill in "Name" with "My new role" | 25 | And I fill in "Name" with "My new role" |
26 | And I press "Save changes" | 26 | And I press "Save changes" |
27 | And I go to the environment control panel | 27 | And I go to the environment control panel |
28 | - And I follow "Manage User roles" | 28 | + And I follow "User roles" |
29 | Then I should see "My new role" | 29 | Then I should see "My new role" |
30 | And I should not see "Profile Administrator" | 30 | And I should not see "Profile Administrator" |
features/send_email_to_environment_members.feature
@@ -18,7 +18,7 @@ Feature: send emails to environment members users | @@ -18,7 +18,7 @@ Feature: send emails to environment members users | ||
18 | Scenario: Send e-mail to members | 18 | Scenario: Send e-mail to members |
19 | Given I am logged in as admin | 19 | Given I am logged in as admin |
20 | When I follow "Administration" | 20 | When I follow "Administration" |
21 | - And I follow "Manage users" | 21 | + And I follow "Users" |
22 | And I follow "Send e-mail to users" | 22 | And I follow "Send e-mail to users" |
23 | And I fill in "Subject" with "Hello, user!" | 23 | And I fill in "Subject" with "Hello, user!" |
24 | And I fill in "body" with "We have some news" | 24 | And I fill in "body" with "We have some news" |
@@ -28,7 +28,7 @@ Feature: send emails to environment members users | @@ -28,7 +28,7 @@ Feature: send emails to environment members users | ||
28 | Scenario: Not send e-mail to members if subject is blank | 28 | Scenario: Not send e-mail to members if subject is blank |
29 | Given I am logged in as admin | 29 | Given I am logged in as admin |
30 | When I follow "Administration" | 30 | When I follow "Administration" |
31 | - And I follow "Manage users" | 31 | + And I follow "Users" |
32 | And I follow "Send e-mail to users" | 32 | And I follow "Send e-mail to users" |
33 | And I fill in "body" with "We have some news" | 33 | And I fill in "body" with "We have some news" |
34 | When I press "Send" | 34 | When I press "Send" |
@@ -37,7 +37,7 @@ Feature: send emails to environment members users | @@ -37,7 +37,7 @@ Feature: send emails to environment members users | ||
37 | Scenario: Not send e-mail to members if body is blank | 37 | Scenario: Not send e-mail to members if body is blank |
38 | Given I am logged in as admin | 38 | Given I am logged in as admin |
39 | When I follow "Administration" | 39 | When I follow "Administration" |
40 | - And I follow "Manage users" | 40 | + And I follow "Users" |
41 | And I follow "Send e-mail to users" | 41 | And I follow "Send e-mail to users" |
42 | And I fill in "Subject" with "Hello, user!" | 42 | And I fill in "Subject" with "Hello, user!" |
43 | When I press "Send" | 43 | When I press "Send" |
@@ -46,7 +46,7 @@ Feature: send emails to environment members users | @@ -46,7 +46,7 @@ Feature: send emails to environment members users | ||
46 | Scenario: Cancel creation of mailing | 46 | Scenario: Cancel creation of mailing |
47 | Given I am logged in as admin | 47 | Given I am logged in as admin |
48 | When I follow "Administration" | 48 | When I follow "Administration" |
49 | - And I follow "Manage users" | 49 | + And I follow "Users" |
50 | And I follow "Send e-mail to users" | 50 | And I follow "Send e-mail to users" |
51 | Then I should be on /admin/users/send_mail | 51 | Then I should be on /admin/users/send_mail |
52 | When I follow "Cancel e-mail" | 52 | When I follow "Cancel e-mail" |
lib/acts_as_faceted.rb
@@ -8,7 +8,7 @@ module ActsAsFaceted | @@ -8,7 +8,7 @@ module ActsAsFaceted | ||
8 | # | 8 | # |
9 | #acts_as_faceted :fields => { | 9 | #acts_as_faceted :fields => { |
10 | # :f_type => {:label => _('Type'), :proc => proc{|klass| f_type_proc(klass)}}, | 10 | # :f_type => {:label => _('Type'), :proc => proc{|klass| f_type_proc(klass)}}, |
11 | - # :f_published_at => {:type => :date, :label => _('Published date'), :queries => {'[* TO NOW-1YEARS/DAY]' => _("Older than one year"), | 11 | + # :f_published_at => {:type => :date, :label => _('Published date'), :queries => {'[* TO NOW-1YEARS/DAY]' => _("Older than one year"), |
12 | # '[NOW-1YEARS TO NOW/DAY]' => _("Last year"), '[NOW-1MONTHS TO NOW/DAY]' => _("Last month"), '[NOW-7DAYS TO NOW/DAY]' => _("Last week"), '[NOW-1DAYS TO NOW/DAY]' => _("Last day")}}, | 12 | # '[NOW-1YEARS TO NOW/DAY]' => _("Last year"), '[NOW-1MONTHS TO NOW/DAY]' => _("Last month"), '[NOW-7DAYS TO NOW/DAY]' => _("Last week"), '[NOW-1DAYS TO NOW/DAY]' => _("Last day")}}, |
13 | # :f_profile_type => {:label => _('Author'), :proc => proc{|klass| f_profile_type_proc(klass)}}, | 13 | # :f_profile_type => {:label => _('Author'), :proc => proc{|klass| f_profile_type_proc(klass)}}, |
14 | # :f_category => {:label => _('Categories')}}, | 14 | # :f_category => {:label => _('Categories')}}, |
@@ -36,7 +36,7 @@ module ActsAsFaceted | @@ -36,7 +36,7 @@ module ActsAsFaceted | ||
36 | self.facets_order = options[:order] || self.facets.keys | 36 | self.facets_order = options[:order] || self.facets.keys |
37 | self.facets_results_containers = {:fields => 'facet_fields', :queries => 'facet_queries', :ranges => 'facet_ranges'} | 37 | self.facets_results_containers = {:fields => 'facet_fields', :queries => 'facet_queries', :ranges => 'facet_ranges'} |
38 | self.facets_option_for_solr = Hash[facets.select{ |id,data| ! data.has_key?(:queries) }].keys | 38 | self.facets_option_for_solr = Hash[facets.select{ |id,data| ! data.has_key?(:queries) }].keys |
39 | - self.facets_fields_for_solr = facets.map{ |id,data| {id => data[:type] || :facet} } | 39 | + self.facets_fields_for_solr = facets.map{ |id,data| {id => data[:type] || :facet} } |
40 | self.solr_fields_names = facets.map{ |id,data| id.to_s + '_' + get_solr_field_type(data[:type] || :facet) } | 40 | self.solr_fields_names = facets.map{ |id,data| id.to_s + '_' + get_solr_field_type(data[:type] || :facet) } |
41 | self.facet_category_query = options[:category_query] | 41 | self.facet_category_query = options[:category_query] |
42 | 42 | ||
@@ -67,6 +67,7 @@ module ActsAsFaceted | @@ -67,6 +67,7 @@ module ActsAsFaceted | ||
67 | raise 'Use map_facets_for before this method' if facet[:solr_field].nil? | 67 | raise 'Use map_facets_for before this method' if facet[:solr_field].nil? |
68 | facets_data = {} if facets_data.blank? # could be empty array | 68 | facets_data = {} if facets_data.blank? # could be empty array |
69 | solr_facet = to_solr_fields_names[facet[:solr_field]] | 69 | solr_facet = to_solr_fields_names[facet[:solr_field]] |
70 | + unfiltered_facets_data ||= {} | ||
70 | 71 | ||
71 | if facet[:queries] | 72 | if facet[:queries] |
72 | container = facets_data[facets_results_containers[:queries]] | 73 | container = facets_data[facets_results_containers[:queries]] |
@@ -158,13 +159,15 @@ module ActsAsFaceted | @@ -158,13 +159,15 @@ module ActsAsFaceted | ||
158 | end | 159 | end |
159 | 160 | ||
160 | def facet_label(facet) | 161 | def facet_label(facet) |
161 | - _ facet[:label] | 162 | + return nil unless facet |
163 | + _(facet[:label]) | ||
162 | end | 164 | end |
163 | 165 | ||
164 | def facets_find_options(facets_selected = {}, options = {}) | 166 | def facets_find_options(facets_selected = {}, options = {}) |
165 | browses = [] | 167 | browses = [] |
166 | facets_selected ||= {} | 168 | facets_selected ||= {} |
167 | facets_selected.map do |id, value| | 169 | facets_selected.map do |id, value| |
170 | + next unless facets[id.to_sym] | ||
168 | if value.kind_of?(Hash) | 171 | if value.kind_of?(Hash) |
169 | value.map do |label_id, value| | 172 | value.map do |label_id, value| |
170 | value.to_a.each do |value| | 173 | value.to_a.each do |value| |
lib/needs_profile.rb
@@ -14,12 +14,12 @@ module NeedsProfile | @@ -14,12 +14,12 @@ module NeedsProfile | ||
14 | profile || environment # prefers profile, but defaults to environment | 14 | profile || environment # prefers profile, but defaults to environment |
15 | end | 15 | end |
16 | 16 | ||
17 | - protected | ||
18 | - | ||
19 | def profile | 17 | def profile |
20 | @profile | 18 | @profile |
21 | end | 19 | end |
22 | 20 | ||
21 | + protected | ||
22 | + | ||
23 | def load_profile | 23 | def load_profile |
24 | @profile ||= environment.profiles.find_by_identifier(params[:profile]) | 24 | @profile ||= environment.profiles.find_by_identifier(params[:profile]) |
25 | if @profile | 25 | if @profile |
lib/noosfero.rb
@@ -2,7 +2,7 @@ require 'fast_gettext' | @@ -2,7 +2,7 @@ require 'fast_gettext' | ||
2 | 2 | ||
3 | module Noosfero | 3 | module Noosfero |
4 | PROJECT = 'noosfero' | 4 | PROJECT = 'noosfero' |
5 | - VERSION = '0.38.1' | 5 | + VERSION = '0.39.0~1' |
6 | 6 | ||
7 | def self.pattern_for_controllers_in_directory(dir) | 7 | def self.pattern_for_controllers_in_directory(dir) |
8 | disjunction = controllers_in_directory(dir).join('|') | 8 | disjunction = controllers_in_directory(dir).join('|') |
lib/noosfero/plugin.rb
@@ -12,17 +12,41 @@ class Noosfero::Plugin | @@ -12,17 +12,41 @@ class Noosfero::Plugin | ||
12 | end | 12 | end |
13 | 13 | ||
14 | def init_system | 14 | def init_system |
15 | - Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')).select do |entry| | 15 | + enabled_plugins = Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')) |
16 | + if Rails.env.test? && !enabled_plugins.include?(File.join(Rails.root, 'config', 'plugins', 'foo')) | ||
17 | + enabled_plugins << File.join(Rails.root, 'plugins', 'foo') | ||
18 | + end | ||
19 | + enabled_plugins.select do |entry| | ||
16 | File.directory?(entry) | 20 | File.directory?(entry) |
17 | end.each do |dir| | 21 | end.each do |dir| |
18 | - Rails.configuration.controller_paths << File.join(dir, 'controllers') | ||
19 | - ActiveSupport::Dependencies.load_paths << File.join(dir, 'controllers') | ||
20 | - [ ActiveSupport::Dependencies.load_paths, $:].each do |path| | ||
21 | - path << File.join(dir, 'models') | ||
22 | - path << File.join(dir, 'lib') | 22 | + plugin_name = File.basename(dir) |
23 | + | ||
24 | + plugin_dependencies_ok = true | ||
25 | + plugin_dependencies_file = File.join(dir, 'dependencies.rb') | ||
26 | + if File.exists?(plugin_dependencies_file) | ||
27 | + begin | ||
28 | + require plugin_dependencies_file | ||
29 | + rescue LoadError => ex | ||
30 | + plugin_dependencies_ok = false | ||
31 | + $stderr.puts "W: Noosfero plugin #{plugin_name} failed to load (#{ex})" | ||
32 | + end | ||
23 | end | 33 | end |
24 | 34 | ||
25 | - klass(File.basename(dir)) | 35 | + if plugin_dependencies_ok |
36 | + Rails.configuration.controller_paths << File.join(dir, 'controllers') | ||
37 | + ActiveSupport::Dependencies.load_paths << File.join(dir, 'controllers') | ||
38 | + controllers_folders = %w[public profile myprofile admin] | ||
39 | + controllers_folders.each do |folder| | ||
40 | + Rails.configuration.controller_paths << File.join(dir, 'controllers', folder) | ||
41 | + ActiveSupport::Dependencies.load_paths << File.join(dir, 'controllers', folder) | ||
42 | + end | ||
43 | + [ ActiveSupport::Dependencies.load_paths, $:].each do |path| | ||
44 | + path << File.join(dir, 'models') | ||
45 | + path << File.join(dir, 'lib') | ||
46 | + end | ||
47 | + | ||
48 | + klass(plugin_name) | ||
49 | + end | ||
26 | end | 50 | end |
27 | end | 51 | end |
28 | 52 | ||
@@ -196,28 +220,6 @@ class Noosfero::Plugin | @@ -196,28 +220,6 @@ class Noosfero::Plugin | ||
196 | nil | 220 | nil |
197 | end | 221 | end |
198 | 222 | ||
199 | - # This is a generic hotspot for all controllers on Noosfero. | ||
200 | - # If any plugin wants to define filters to run on any controller, the name of | ||
201 | - # the hotspot must be in the following form: <underscored_controller_name>_filters. | ||
202 | - # Example: for ProfileController the hotspot is profile_controller_filters | ||
203 | - # | ||
204 | - # -> Adds a filter to a controller | ||
205 | - # returns = { :type => type, | ||
206 | - # :method_name => method_name, | ||
207 | - # :options => {:opt1 => opt1, :opt2 => opt2}, | ||
208 | - # :block => Proc or lambda block} | ||
209 | - # type = 'before_filter' or 'after_filter' | ||
210 | - # method_name = The name of the filter | ||
211 | - # option = Filter options, like :only or :except | ||
212 | - # block = Block that the filter will call | ||
213 | - def method_missing(method, *args, &block) | ||
214 | - if method.to_s =~ /^(.+)_controller_filters$/ | ||
215 | - [] | ||
216 | - else | ||
217 | - super | ||
218 | - end | ||
219 | - end | ||
220 | - | ||
221 | # This method will be called just before a comment is saved to the database. | 223 | # This method will be called just before a comment is saved to the database. |
222 | # | 224 | # |
223 | # It can modify the comment in several ways. In special, a plugin can call | 225 | # It can modify the comment in several ways. In special, a plugin can call |
@@ -226,16 +228,53 @@ class Noosfero::Plugin | @@ -226,16 +228,53 @@ class Noosfero::Plugin | ||
226 | # example: | 228 | # example: |
227 | # | 229 | # |
228 | # def filter_comment(comment) | 230 | # def filter_comment(comment) |
229 | - # comment.reject! if anti_spam_service.is_spam?(comment) | 231 | + # if user_not_logged_in |
232 | + # comment.reject! | ||
233 | + # end | ||
230 | # end | 234 | # end |
231 | # | 235 | # |
232 | def filter_comment(comment) | 236 | def filter_comment(comment) |
233 | end | 237 | end |
234 | 238 | ||
235 | - # This method will be called just after a comment has been saved to the | ||
236 | - # database, so that a plugin can perform some action on it. | 239 | + # This method is called by the CommentHandler background job before sending |
240 | + # the notification email. If the comment is marked as spam (i.e. by calling | ||
241 | + # <tt>comment.spam!</tt>), then the notification email will *not* be sent. | ||
242 | + # | ||
243 | + # example: | ||
244 | + # | ||
245 | + # def check_comment_for_spam(comment) | ||
246 | + # if anti_spam_service.is_spam?(comment) | ||
247 | + # comment.spam! | ||
248 | + # end | ||
249 | + # end | ||
250 | + # | ||
251 | + def check_comment_for_spam(comment) | ||
252 | + end | ||
253 | + | ||
254 | + # This method is called when the user manually marks a comment as SPAM. A | ||
255 | + # plugin implementing this method should train its spam detection mechanism | ||
256 | + # by submitting this comment as a confirmed spam. | ||
257 | + # | ||
258 | + # example: | ||
259 | + # | ||
260 | + # def comment_marked_as_spam(comment) | ||
261 | + # anti_spam_service.train_with_spam(comment) | ||
262 | + # end | ||
263 | + # | ||
264 | + def comment_marked_as_spam(comment) | ||
265 | + end | ||
266 | + | ||
267 | + # This method is called when the user manually marks a comment a NOT SPAM. A | ||
268 | + # plugin implementing this method should train its spam detection mechanism | ||
269 | + # by submitting this coimment as a confirmed ham. | ||
270 | + # | ||
271 | + # example: | ||
272 | + # | ||
273 | + # def comment_marked_as_ham(comment) | ||
274 | + # anti_spam_service.train_with_ham(comment) | ||
275 | + # end | ||
237 | # | 276 | # |
238 | - def comment_saved(comment) | 277 | + def comment_marked_as_ham(comment) |
239 | end | 278 | end |
240 | 279 | ||
241 | # -> Adds fields to the signup form | 280 | # -> Adds fields to the signup form |
@@ -281,4 +320,71 @@ class Noosfero::Plugin | @@ -281,4 +320,71 @@ class Noosfero::Plugin | ||
281 | nil | 320 | nil |
282 | end | 321 | end |
283 | 322 | ||
323 | + # -> Add an alternative authentication method. | ||
324 | + # Your plugin have to make the access control and return the logged user. | ||
325 | + # returns = User | ||
326 | + def alternative_authentication | ||
327 | + nil | ||
328 | + end | ||
329 | + | ||
330 | + # -> Adds adicional link to make the user authentication | ||
331 | + # returns = lambda block that creates html code | ||
332 | + def alternative_authentication_link | ||
333 | + nil | ||
334 | + end | ||
335 | + | ||
336 | + # -> Allow or not user registration | ||
337 | + # returns = boolean | ||
338 | + def allow_user_registration | ||
339 | + true | ||
340 | + end | ||
341 | + | ||
342 | + # -> Allow or not password recovery by users | ||
343 | + # returns = boolean | ||
344 | + def allow_password_recovery | ||
345 | + true | ||
346 | + end | ||
347 | + | ||
348 | + # -> Adds fields to the login form | ||
349 | + # returns = lambda block that creates html code | ||
350 | + def login_extra_contents | ||
351 | + nil | ||
352 | + end | ||
353 | + | ||
354 | + def method_missing(method, *args, &block) | ||
355 | + # This is a generic hotspot for all controllers on Noosfero. | ||
356 | + # If any plugin wants to define filters to run on any controller, the name of | ||
357 | + # the hotspot must be in the following form: <underscored_controller_name>_filters. | ||
358 | + # Example: for ProfileController the hotspot is profile_controller_filters | ||
359 | + # | ||
360 | + # -> Adds a filter to a controller | ||
361 | + # returns = { :type => type, | ||
362 | + # :method_name => method_name, | ||
363 | + # :options => {:opt1 => opt1, :opt2 => opt2}, | ||
364 | + # :block => Proc or lambda block} | ||
365 | + # type = 'before_filter' or 'after_filter' | ||
366 | + # method_name = The name of the filter | ||
367 | + # option = Filter options, like :only or :except | ||
368 | + # block = Block that the filter will call | ||
369 | + if method.to_s =~ /^(.+)_controller_filters$/ | ||
370 | + [] | ||
371 | + # -> Removes the action button from the content | ||
372 | + # returns = boolean | ||
373 | + elsif method.to_s =~ /^content_remove_(#{content_actions.join('|')})$/ | ||
374 | + nil | ||
375 | + # -> Expire the action button from the content | ||
376 | + # returns = string with reason of expiration | ||
377 | + elsif method.to_s =~ /^content_expire_(#{content_actions.join('|')})$/ | ||
378 | + nil | ||
379 | + else | ||
380 | + super | ||
381 | + end | ||
382 | + end | ||
383 | + | ||
384 | + private | ||
385 | + | ||
386 | + def content_actions | ||
387 | + %w[edit delete spread locale suggest home] | ||
388 | + end | ||
389 | + | ||
284 | end | 390 | end |
lib/noosfero/plugin/acts_as_having_hotspots.rb
@@ -1,44 +0,0 @@ | @@ -1,44 +0,0 @@ | ||
1 | -module ActsAsHavingHotspots | ||
2 | - module ClassMethods | ||
3 | - # Adding this feature to a class demands that it defines an instance method | ||
4 | - # 'environment' that returns the environment associated with the instance. | ||
5 | - def acts_as_having_hotspots | ||
6 | - send :include, InstanceMethods | ||
7 | - end | ||
8 | - | ||
9 | - module InstanceMethods | ||
10 | - # Dispatches +event+ to each enabled plugin and collect the results. | ||
11 | - # | ||
12 | - # Returns an Array containing the objects returned by the event method in | ||
13 | - # each plugin. This array is compacted (i.e. nils are removed) and flattened | ||
14 | - # (i.e. elements of arrays are added to the resulting array). For example, if | ||
15 | - # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will | ||
16 | - # return [1,0,1,2,3] | ||
17 | - # | ||
18 | - def dispatch(event, *args) | ||
19 | - enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact.flatten | ||
20 | - end | ||
21 | - | ||
22 | - # Dispatch without flatten since scopes are executed if you run flatten on them | ||
23 | - def dispatch_scopes(event, *args) | ||
24 | - enabled_plugins.map { |plugin| plugin.send(event, *args) }.compact | ||
25 | - end | ||
26 | - | ||
27 | - def enabled_plugins | ||
28 | - Thread.current[:enabled_plugins] ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name| | ||
29 | - plugin = plugin_name.constantize.new | ||
30 | - plugin.context = context | ||
31 | - plugin | ||
32 | - end | ||
33 | - end | ||
34 | - | ||
35 | - if !method_defined?(:context) | ||
36 | - define_method(:context) do | ||
37 | - Noosfero::Plugin::Context.new | ||
38 | - end | ||
39 | - end | ||
40 | - end | ||
41 | - end | ||
42 | -end | ||
43 | - | ||
44 | -ActiveRecord::Base.send(:extend, ActsAsHavingHotspots::ClassMethods) |
lib/noosfero/plugin/context.rb
@@ -1,15 +0,0 @@ | @@ -1,15 +0,0 @@ | ||
1 | -# This class defines the interface to important context information from the | ||
2 | -# controller that can be accessed by plugins | ||
3 | -class Noosfero::Plugin::Context | ||
4 | - | ||
5 | - def initialize(controller = ApplicationController.new) | ||
6 | - @controller = controller | ||
7 | - end | ||
8 | - | ||
9 | - delegate :profile, :request, :response, :environment, :params, :session, :user, :logged_in?, :to => :controller | ||
10 | - | ||
11 | - protected | ||
12 | - | ||
13 | - attr_reader :controller | ||
14 | - | ||
15 | -end |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +# This module must be included by classes that contain Noosfero plugin | ||
2 | +# hotspots. | ||
3 | +# | ||
4 | +# Classes that include this module *must* provide a method called | ||
5 | +# <tt>environment</tt> which returns an intance of Environment. This | ||
6 | +# Environment will be used to determine which plugins are enabled and therefore | ||
7 | +# which plugins should be instantiated. | ||
8 | +module Noosfero::Plugin::HotSpot | ||
9 | + | ||
10 | + # Returns an instance of Noosfero::Plugin::Manager. | ||
11 | + # | ||
12 | + # This which is intantiated on the first call and just returned in subsequent | ||
13 | + # calls. | ||
14 | + def plugins | ||
15 | + @plugins ||= Noosfero::Plugin::Manager.new(environment, self) | ||
16 | + end | ||
17 | + | ||
18 | +end |
lib/noosfero/plugin/manager.rb
1 | class Noosfero::Plugin::Manager | 1 | class Noosfero::Plugin::Manager |
2 | 2 | ||
3 | - extend ActsAsHavingHotspots::ClassMethods | ||
4 | - acts_as_having_hotspots | ||
5 | - | 3 | + attr_reader :environment |
6 | attr_reader :context | 4 | attr_reader :context |
7 | 5 | ||
8 | - delegate :environment, :to => :context | 6 | + def initialize(environment, context) |
7 | + @environment = environment | ||
8 | + @context = context | ||
9 | + end | ||
10 | + | ||
9 | delegate :each, :to => :enabled_plugins | 11 | delegate :each, :to => :enabled_plugins |
10 | include Enumerable | 12 | include Enumerable |
11 | 13 | ||
12 | - def initialize(controller) | ||
13 | - @context = Noosfero::Plugin::Context.new(controller) | ||
14 | - Thread.current[:enabled_plugins] = (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin_name| | ||
15 | - plugin = plugin_name.constantize.new | ||
16 | - plugin.context = context | ||
17 | - plugin | 14 | + # Dispatches +event+ to each enabled plugin and collect the results. |
15 | + # | ||
16 | + # Returns an Array containing the objects returned by the event method in | ||
17 | + # each plugin. This array is compacted (i.e. nils are removed) and flattened | ||
18 | + # (i.e. elements of arrays are added to the resulting array). For example, if | ||
19 | + # the enabled plugins return 1, 0, nil, and [1,2,3], then this method will | ||
20 | + # return [1,0,1,2,3] | ||
21 | + # | ||
22 | + def dispatch(event, *args) | ||
23 | + dispatch_without_flatten(event, *args).flatten | ||
24 | + end | ||
25 | + | ||
26 | + def dispatch_without_flatten(event, *args) | ||
27 | + map { |plugin| plugin.send(event, *args) }.compact | ||
28 | + end | ||
29 | + | ||
30 | + alias :dispatch_scopes :dispatch_without_flatten | ||
31 | + | ||
32 | + def enabled_plugins | ||
33 | + @enabled_plugins ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin| | ||
34 | + p = plugin.constantize.new | ||
35 | + p.context = context | ||
36 | + p | ||
18 | end | 37 | end |
19 | end | 38 | end |
20 | 39 |
lib/noosfero/plugin/routes.rb
1 | -Dir.glob(File.join(Rails.root, 'config', 'plugins', '*', 'controllers')) do |dir| | ||
2 | - plugin_name = File.basename(File.dirname(dir)) | 1 | +plugins_root = Rails.env.test? ? 'plugins' : File.join('config', 'plugins') |
2 | + | ||
3 | +Dir.glob(File.join(Rails.root, plugins_root, '*', 'controllers')) do |controllers_dir| | ||
4 | + prefixes_by_folder = {'public' => 'plugin', | ||
5 | + 'profile' => 'profile/:profile/plugin', | ||
6 | + 'myprofile' => 'myprofile/:profile/plugin', | ||
7 | + 'admin' => 'admin/plugin'} | ||
8 | + | ||
9 | + controllers_by_folder = prefixes_by_folder.keys.inject({}) do |hash, folder| | ||
10 | + hash.merge!({folder => Dir.glob(File.join(controllers_dir, folder, '*')).map {|full_names| File.basename(full_names).gsub(/_controller.rb$/,'')}}) | ||
11 | + end | ||
12 | + | ||
13 | + plugin_name = File.basename(File.dirname(controllers_dir)) | ||
14 | + | ||
15 | + controllers_by_folder.each do |folder, controllers| | ||
16 | + controllers.each do |controller| | ||
17 | + controller_name = controller.gsub("#{plugin_name}_plugin_",'') | ||
18 | + map.connect "#{prefixes_by_folder[folder]}/#{plugin_name}/#{controller_name}/:action/:id", :controller => controller | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
3 | map.connect 'plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin' | 22 | map.connect 'plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin' |
4 | - map.connect 'profile/:profile/plugins/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_profile' | 23 | + map.connect 'profile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_profile' |
5 | map.connect 'myprofile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_myprofile' | 24 | map.connect 'myprofile/:profile/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_myprofile' |
6 | map.connect 'admin/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_admin' | 25 | map.connect 'admin/plugin/' + plugin_name + '/:action/:id', :controller => plugin_name + '_plugin_admin' |
7 | end | 26 | end |
8 | - |
lib/tasks/data.rake
@@ -3,7 +3,7 @@ namespace :db do | @@ -3,7 +3,7 @@ namespace :db do | ||
3 | task :minimal do | 3 | task :minimal do |
4 | sh './script/runner', "Environment.create!(:name => 'Noosfero', :is_default => true)" | 4 | sh './script/runner', "Environment.create!(:name => 'Noosfero', :is_default => true)" |
5 | unless ENV['NOOSFERO_DOMAIN'].blank? | 5 | unless ENV['NOOSFERO_DOMAIN'].blank? |
6 | - sh './script/runner', "environment.domains << Domain.new(:name => ENV['NOOSFERO_DOMAIN'])" | 6 | + sh './script/runner', "Environment.default.domains << Domain.new(:name => ENV['NOOSFERO_DOMAIN'])" |
7 | end | 7 | end |
8 | end | 8 | end |
9 | end | 9 | end |
lib/tasks/plugins_tests.rake
1 | -@disabled_plugins = Dir.glob(File.join(Rails.root, 'plugins', '*')).map { |file| File.basename(file)} - Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')).map { |file| File.basename(file)} | ||
2 | -@disabled_plugins.delete('template') | ||
3 | - | ||
4 | -def define_task(test, plugins_folder='plugins', plugin = '*') | ||
5 | - test_files = Dir.glob(File.join(Rails.root, plugins_folder, plugin, 'test', test[:folder], '**', '*_test.rb')) | ||
6 | - desc 'Runs ' + (plugin != '*' ? plugin : 'plugins') + ' ' + test[:name] + ' tests' | ||
7 | - Rake::TestTask.new(test[:name].to_sym => 'db:test:plugins:prepare') do |t| | ||
8 | - t.libs << 'test' | ||
9 | - t.test_files = test_files | ||
10 | - t.verbose = true | ||
11 | - end | 1 | +all_plugins = Dir.glob('plugins/*').map { |f| File.basename(f) } - ['template'] |
2 | +def enabled_plugins | ||
3 | + Dir.glob('config/plugins/*').map { |f| File.basename(f) } - ['README'] | ||
12 | end | 4 | end |
5 | +disabled_plugins = all_plugins - enabled_plugins | ||
13 | 6 | ||
14 | task 'db:test:plugins:prepare' do | 7 | task 'db:test:plugins:prepare' do |
15 | - Rake::Task['db:test:prepare'].invoke | ||
16 | - sh 'rake db:migrate RAILS_ENV=test SCHEMA=/dev/null' | 8 | + if Dir.glob('config/plugins/*/db/migrate/*.rb').empty? |
9 | + puts "I: skipping database setup, enabled plugins have no migrations" | ||
10 | + else | ||
11 | + Rake::Task['db:test:prepare'].invoke | ||
12 | + sh 'rake db:migrate RAILS_ENV=test SCHEMA=/dev/null' | ||
13 | + end | ||
17 | end | 14 | end |
18 | 15 | ||
19 | -namespace :test do | ||
20 | - namespace :noosfero_plugins do | ||
21 | - tasks = [ | ||
22 | - {:name => :available, :folder => 'plugins'}, | ||
23 | - {:name => :enabled, :folder => File.join('config', 'plugins')} | ||
24 | - ] | ||
25 | - tests = [ | ||
26 | - {:name => 'units', :folder => 'unit'}, | ||
27 | - {:name => 'functionals', :folder => 'functional'}, | ||
28 | - {:name => 'integration', :folder => 'integration'} | ||
29 | - ] | ||
30 | - | ||
31 | - tasks.each do |t| | ||
32 | - namespace t[:name] do | ||
33 | - tests.each do |test| | ||
34 | - define_task(test, t[:folder]) | ||
35 | - end | ||
36 | - end | ||
37 | - end | 16 | +def plugin_name(plugin) |
17 | + "#{plugin} plugin" | ||
18 | +end | ||
19 | + | ||
20 | +def run_tests(name, files_glob) | ||
21 | + files = Dir.glob(files_glob) | ||
22 | + if files.empty? | ||
23 | + puts "I: no tests to run (#{name})" | ||
24 | + else | ||
25 | + sh 'testrb', '-Itest', *files | ||
26 | + end | ||
27 | +end | ||
38 | 28 | ||
39 | - plugins = Dir.glob(File.join(Rails.root, 'plugins', '*')).map {|path| File.basename(path)} | 29 | +def run_cucumber(name, profile, files_glob) |
30 | + files = Dir.glob(files_glob) | ||
31 | + if files.empty? | ||
32 | + puts "I: no tests to run #{name}" | ||
33 | + else | ||
34 | + sh 'xvfb-run', 'ruby', '-S', 'cucumber', '--profile', profile, '--format', ENV['CUCUMBER_FORMAT'] || 'progress' , *features | ||
35 | + end | ||
36 | +end | ||
40 | 37 | ||
41 | - plugins.each do |plugin_name| | ||
42 | - namespace plugin_name do | ||
43 | - tests.each do |test| | ||
44 | - define_task(test, 'plugins', plugin_name) | ||
45 | - end | ||
46 | - end | 38 | +def plugin_test_task(name, plugin, files_glob) |
39 | + desc "Run #{name} tests for #{plugin_name(plugin)}" | ||
40 | + task name => 'db:test:plugins:prepare' do |t| | ||
41 | + run_tests t.name, files_glob | ||
42 | + end | ||
43 | +end | ||
44 | + | ||
45 | +def plugin_cucumber_task(plugin, files_glob) | ||
46 | + task :cucumber => 'db:test:plugins:prepare' do |t| | ||
47 | + run_cucumber t.name, :default, files_glob | ||
48 | + end | ||
49 | +end | ||
47 | 50 | ||
48 | - dependencies = [] | ||
49 | - tests.each do |test| | ||
50 | - dependencies << plugin_name+':'+test[:name] | 51 | +def plugin_selenium_task(plugin, files_glob) |
52 | + task :selenium => 'db:test:plugins:prepare' do |t| | ||
53 | + run_cucumber t.name, :selenium, files_glob | ||
54 | + end | ||
55 | +end | ||
56 | + | ||
57 | +def test_sequence_task(name, plugin, *tasks) | ||
58 | + desc "Run all tests for #{plugin_name(plugin)}" | ||
59 | + task name do | ||
60 | + failed = [] | ||
61 | + tasks.each do |task| | ||
62 | + begin | ||
63 | + Rake::Task['test:noosfero_plugins:' + task.to_s].invoke | ||
64 | + rescue Exception => ex | ||
65 | + puts ex | ||
66 | + failed << task | ||
51 | end | 67 | end |
52 | - task plugin_name => dependencies | ||
53 | end | 68 | end |
54 | - | ||
55 | - task :temp_enable_plugins do | ||
56 | - system('./script/noosfero-plugins enableall') | 69 | + unless failed.empty? |
70 | + fail 'Tests failed: ' + failed.join(', ') | ||
57 | end | 71 | end |
72 | + end | ||
73 | +end | ||
58 | 74 | ||
59 | - task :rollback_temp_enable_plugins do | ||
60 | - @disabled_plugins.each { |plugin| system('./script/noosfero-plugins disable ' + plugin)} | 75 | +namespace :test do |
76 | + namespace :noosfero_plugins do | ||
77 | + all_plugins.each do |plugin| | ||
78 | + namespace plugin do | ||
79 | + plugin_test_task :units, plugin, "plugins/#{plugin}/test/unit/**/*.rb" | ||
80 | + plugin_test_task :functionals, plugin, "plugins/#{plugin}/test/functional/**/*.rb" | ||
81 | + plugin_test_task :integration, plugin, "plugins/#{plugin}/test/integration/**/*.rb" | ||
82 | + plugin_cucumber_task plugin, "plugins/#{plugin}/features/**/*.feature" | ||
83 | + plugin_selenium_task plugin, "plugins/#{plugin}/features/**/*.feature" | ||
84 | + end | ||
85 | + | ||
86 | + test_sequence_task(plugin, plugin, "#{plugin}:units", "#{plugin}:functionals", "#{plugin}:integration", "#{plugin}:cucumber", "#{plugin}:selenium") # FIXME missing cucumber and selenium | ||
61 | end | 87 | end |
62 | 88 | ||
63 | - task :units => 'available:units' | ||
64 | - task :functionals => 'available:functionals' | ||
65 | - task :integration => 'available:integration' | ||
66 | - task :available do | ||
67 | - Rake::Task['test:noosfero_plugins:temp_enable_plugins'].invoke | ||
68 | - begin | ||
69 | - Rake::Task['test:noosfero_plugins:units'].invoke | ||
70 | - Rake::Task['test:noosfero_plugins:functionals'].invoke | ||
71 | - Rake::Task['test:noosfero_plugins:integration'].invoke | ||
72 | - rescue | 89 | + { :units => :unit , :functionals => :functional , :integration => :integration }.each do |taskname,folder| |
90 | + task taskname => 'db:test:plugins:prepare' do |t| | ||
91 | + run_tests t.name, "plugins/{#{enabled_plugins.join(',')}}/test/#{folder}/**/*.rb" | ||
73 | end | 92 | end |
74 | - Rake::Task['test:noosfero_plugins:rollback_temp_enable_plugins'].invoke | ||
75 | end | 93 | end |
76 | - task :enabled => ['enabled:units', 'enabled:functionals', 'enabled:integration'] | ||
77 | 94 | ||
95 | + task :cucumber => 'db:test:plugins:prepare' do |t| | ||
96 | + run_cucumber t.name, :default, "plugins/{#{enabled_plugins.join(',')}}/features/**/*.features" | ||
97 | + end | ||
78 | 98 | ||
79 | - namespace :cucumber do | ||
80 | - task :enabled do | ||
81 | - features = Dir.glob('config/plugins/*/features/*.feature') | ||
82 | - if features.empty? | ||
83 | - puts "No acceptance tests for enabled plugins, skipping" | ||
84 | - else | ||
85 | - ruby '-S', 'cucumber', '--format', ENV['CUCUMBER_FORMAT'] || 'progress' , *features | ||
86 | - end | ||
87 | - end | 99 | + task :selenium => 'db:test:plugins:prepare' do |t| |
100 | + run_cucumber t.name, :selenium, "plugins/{#{enabled_plugins.join(',')}}/features/**/*.features" | ||
88 | end | 101 | end |
89 | 102 | ||
90 | - namespace :selenium do | ||
91 | - task :enabled do | ||
92 | - features = Dir.glob('config/plugins/*/features/*.feature') | ||
93 | - if features.empty? | ||
94 | - puts "No acceptance tests for enabled plugins, skipping" | ||
95 | - else | ||
96 | - sh 'xvfb-run', 'ruby', '-S', 'cucumber', '--profile', 'selenium', '--format', ENV['CUCUMBER_FORMAT'] || 'progress' , *features | ||
97 | - end | ||
98 | - end | 103 | + task :temp_enable_all_plugins do |
104 | + sh './script/noosfero-plugins', 'enableall' | ||
99 | end | 105 | end |
100 | 106 | ||
107 | + task :rollback_enable_all_plugins do | ||
108 | + sh './script/noosfero-plugins', 'disable', *disabled_plugins | ||
109 | + end | ||
101 | end | 110 | end |
102 | 111 | ||
103 | - task :noosfero_plugins => %w[ noosfero_plugins:available noosfero_plugins:cucumber:enabled noosfero_plugins:selenium:enabled ] | 112 | + test_sequence_task(:noosfero_plugins, '*', :temp_enable_all_plugins, :units, :functionals, :integration, :cucumber, :selenium, :rollback_enable_all_plugins) |
104 | 113 | ||
105 | end | 114 | end |
106 | - |
lib/tasks/release.rake
@@ -95,6 +95,9 @@ EOF | @@ -95,6 +95,9 @@ EOF | ||
95 | sh "cd #{target} && dpkg-buildpackage -us -uc -b" | 95 | sh "cd #{target} && dpkg-buildpackage -us -uc -b" |
96 | end | 96 | end |
97 | 97 | ||
98 | + desc "Build Debian packages (shorcut)" | ||
99 | + task :deb => :debian_packages | ||
100 | + | ||
98 | desc 'Test Debian package' | 101 | desc 'Test Debian package' |
99 | task 'debian:test' => :debian_packages do | 102 | task 'debian:test' => :debian_packages do |
100 | Dir.chdir 'pkg' do | 103 | Dir.chdir 'pkg' do |
plugins/anti_spam/controllers/anti_spam_plugin_admin_controller.rb
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +class AntiSpamPluginAdminController < AdminController | ||
2 | + append_view_path File.join(File.dirname(__FILE__) + '/../views') | ||
3 | + | ||
4 | + def index | ||
5 | + @settings = AntiSpamPlugin::Settings.new(environment, params[:settings]) | ||
6 | + if request.post? | ||
7 | + @settings.save! | ||
8 | + redirect_to :action => 'index' | ||
9 | + end | ||
10 | + end | ||
11 | + | ||
12 | +end |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +require 'rakismet' |
@@ -0,0 +1,39 @@ | @@ -0,0 +1,39 @@ | ||
1 | +class AntiSpamPlugin < Noosfero::Plugin | ||
2 | + | ||
3 | + def self.plugin_name | ||
4 | + "AntiSpam" | ||
5 | + end | ||
6 | + | ||
7 | + def self.plugin_description | ||
8 | + _("Checks comments against a spam checking service compatible with the Akismet API") | ||
9 | + end | ||
10 | + | ||
11 | + def check_comment_for_spam(comment) | ||
12 | + if rakismet_call(comment, :spam?) | ||
13 | + comment.spam = true | ||
14 | + comment.save! | ||
15 | + end | ||
16 | + end | ||
17 | + | ||
18 | + def comment_marked_as_spam(comment) | ||
19 | + rakismet_call(comment, :spam!) | ||
20 | + end | ||
21 | + | ||
22 | + def comment_marked_as_ham(comment) | ||
23 | + rakismet_call(comment, :ham!) | ||
24 | + end | ||
25 | + | ||
26 | + protected | ||
27 | + | ||
28 | + def rakismet_call(comment, op) | ||
29 | + settings = AntiSpamPlugin::Settings.new(comment.environment) | ||
30 | + | ||
31 | + Rakismet.host = settings.host | ||
32 | + Rakismet.key = settings.api_key | ||
33 | + Rakismet.url = comment.environment.top_url | ||
34 | + | ||
35 | + submission = AntiSpamPlugin::CommentWrapper.new(comment) | ||
36 | + submission.send(op) | ||
37 | + end | ||
38 | + | ||
39 | +end |
plugins/anti_spam/lib/anti_spam_plugin/comment_wrapper.rb
0 → 100644
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +class AntiSpamPlugin::CommentWrapper < Struct.new(:comment) | ||
2 | + | ||
3 | + delegate :author_name, :author_email, :title, :body, :ip_address, :user_agent, :referrer, :to => :comment | ||
4 | + | ||
5 | + include Rakismet::Model | ||
6 | + | ||
7 | + alias :author :author_name | ||
8 | + alias :user_ip :ip_address | ||
9 | + alias :content :body | ||
10 | + | ||
11 | +end |
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +class AntiSpamPlugin::Settings | ||
2 | + | ||
3 | + def initialize(environment, attributes = nil) | ||
4 | + @environment = environment | ||
5 | + attributes ||= {} | ||
6 | + attributes.each do |k,v| | ||
7 | + self.send("#{k}=", v) | ||
8 | + end | ||
9 | + end | ||
10 | + | ||
11 | + def settings | ||
12 | + @environment.settings[:anti_spam_plugin] ||= {} | ||
13 | + end | ||
14 | + | ||
15 | + def host | ||
16 | + settings[:host] ||= 'api.antispam.typepad.com' | ||
17 | + end | ||
18 | + | ||
19 | + def host=(value) | ||
20 | + settings[:host] = value | ||
21 | + end | ||
22 | + | ||
23 | + def api_key | ||
24 | + settings[:api_key] | ||
25 | + end | ||
26 | + | ||
27 | + def api_key=(value) | ||
28 | + settings[:api_key] = value | ||
29 | + end | ||
30 | + | ||
31 | + def save! | ||
32 | + @environment.save! | ||
33 | + end | ||
34 | + | ||
35 | +end |
@@ -0,0 +1,115 @@ | @@ -0,0 +1,115 @@ | ||
1 | +require 'benchmark' | ||
2 | + | ||
3 | +class AntiSpamPlugin::Spaminator | ||
4 | + | ||
5 | + class << self | ||
6 | + def run(environment) | ||
7 | + instance = new(environment) | ||
8 | + instance.run | ||
9 | + end | ||
10 | + | ||
11 | + def benchmark(environment) | ||
12 | + puts Benchmark.measure { run(environment) } | ||
13 | + end | ||
14 | + end | ||
15 | + | ||
16 | + | ||
17 | + def initialize(environment) | ||
18 | + @environment = environment | ||
19 | + end | ||
20 | + | ||
21 | + def run | ||
22 | + start_time = Time.now | ||
23 | + | ||
24 | + process_all_comments | ||
25 | + process_all_people | ||
26 | + process_people_without_network | ||
27 | + | ||
28 | + finish(start_time) | ||
29 | + end | ||
30 | + | ||
31 | + protected | ||
32 | + | ||
33 | + def finish(start_time) | ||
34 | + @environment.settings[:spaminator_last_run] = start_time | ||
35 | + @environment.save! | ||
36 | + end | ||
37 | + | ||
38 | + def conditions(table) | ||
39 | + last_run = @environment.settings[:spaminator_last_run] | ||
40 | + if last_run | ||
41 | + ["profiles.environment_id = ? AND #{table}.created_at > ?", @environment.id, last_run] | ||
42 | + else | ||
43 | + [ "profiles.environment_id = ?", @environment.id] | ||
44 | + end | ||
45 | + end | ||
46 | + | ||
47 | + def process_all_comments | ||
48 | + puts 'Processing comments ...' | ||
49 | + i = 0 | ||
50 | + comments = Comment.joins("JOIN articles ON (comments.source_id = articles.id AND comments.source_type = 'Article') JOIN profiles ON (profiles.id = articles.profile_id)").where(conditions(:comments)) | ||
51 | + total = comments.count | ||
52 | + comments.find_each do |comment| | ||
53 | + puts "Comment #{i += 1}/#{total} (#{100*i/total}%)" | ||
54 | + process_comment(comment) | ||
55 | + end | ||
56 | + end | ||
57 | + | ||
58 | + def process_all_people | ||
59 | + puts 'Processing people ...' | ||
60 | + i = 0 | ||
61 | + people = Person.where(conditions(:profiles)) | ||
62 | + total = people.count | ||
63 | + people.find_each do |person| | ||
64 | + puts "Person #{i += 1}/#{total} (#{100*i/total}%)" | ||
65 | + process_person(person) | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
69 | + def process_comment(comment) | ||
70 | + comment.check_for_spam | ||
71 | + | ||
72 | + # TODO several comments with the same content: | ||
73 | + # → disable author | ||
74 | + # → mark all of them as spam | ||
75 | + | ||
76 | + # TODO check comments that contains URL's | ||
77 | + end | ||
78 | + | ||
79 | + def process_person(person) | ||
80 | + # person is author of more than 2 comments marked as spam | ||
81 | + # → burn | ||
82 | + # | ||
83 | + number_of_spam_comments = Comment.spam.where(author_id => person.id).count | ||
84 | + if number_of_spam_comments > 2 | ||
85 | + mark_as_spammer(person) | ||
86 | + end | ||
87 | + end | ||
88 | + | ||
89 | + def process_people_without_network | ||
90 | + # people who signed up more than one month ago, have no friends and <= 1 | ||
91 | + # communities | ||
92 | + # | ||
93 | + # → burn | ||
94 | + # → mark their comments as spam | ||
95 | + # | ||
96 | + Person.where(:environment_id => @environment.id).where(['created_at < ?', Time.now - 1.month]).find_each do |person| | ||
97 | + # TODO progress indicator - see process_all_people above | ||
98 | + number_of_friends = person.friends.count | ||
99 | + number_of_communities = person.communities.count | ||
100 | + if number_of_friends == 0 && number_of_communities <= 1 | ||
101 | + mark_as_spammer(person) | ||
102 | + Comment.where(:author_id => person.id).find_each do |comment| | ||
103 | + comment.spam! | ||
104 | + end | ||
105 | + end | ||
106 | + end | ||
107 | + end | ||
108 | + | ||
109 | + def mark_as_spammer(person) | ||
110 | + # FIXME create an AbuseComplaint and finish instead of calling | ||
111 | + # Person#disable directly | ||
112 | + person.disable | ||
113 | + end | ||
114 | + | ||
115 | +end |
plugins/anti_spam/test/unit/anti_spam_plugin/comment_wrapper_test.rb
0 → 100644
@@ -0,0 +1,46 @@ | @@ -0,0 +1,46 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class AntiSpamPluginCommentWrapperTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @comment = Comment.new( | ||
7 | + :title => 'comment title', | ||
8 | + :body => 'comment body', | ||
9 | + :name => 'foo', | ||
10 | + :email => 'foo@example.com', | ||
11 | + :ip_address => '1.2.3.4', | ||
12 | + :user_agent => 'Some Good Browser (I hope)', | ||
13 | + :referrer => 'http://noosfero.org/' | ||
14 | + ) | ||
15 | + @wrapper = AntiSpamPlugin::CommentWrapper.new(@comment) | ||
16 | + end | ||
17 | + | ||
18 | + should 'use Rakismet::Model' do | ||
19 | + assert_includes @wrapper.class.included_modules, Rakismet::Model | ||
20 | + end | ||
21 | + | ||
22 | + should 'get contents' do | ||
23 | + assert_equal @comment.body, @wrapper.content | ||
24 | + end | ||
25 | + | ||
26 | + should 'get author name' do | ||
27 | + assert_equal @comment.author_name, @wrapper.author | ||
28 | + end | ||
29 | + | ||
30 | + should 'get author email' do | ||
31 | + assert_equal @comment.author_email, @wrapper.author_email | ||
32 | + end | ||
33 | + | ||
34 | + should 'get IP address' do | ||
35 | + assert_equal @comment.ip_address, @wrapper.user_ip | ||
36 | + end | ||
37 | + | ||
38 | + should 'get User-Agent' do | ||
39 | + assert_equal @comment.user_agent, @wrapper.user_agent | ||
40 | + end | ||
41 | + | ||
42 | + should 'get get Referrer' do | ||
43 | + assert_equal @comment.referrer, @wrapper.referrer | ||
44 | + end | ||
45 | + | ||
46 | +end |
plugins/anti_spam/test/unit/anti_spam_plugin/settings_test.rb
0 → 100644
@@ -0,0 +1,29 @@ | @@ -0,0 +1,29 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class AntiSpamSettingsTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @environment = Environment.new | ||
7 | + @settings = AntiSpamPlugin::Settings.new(@environment) | ||
8 | + end | ||
9 | + | ||
10 | + should 'store setttings in environment' do | ||
11 | + @settings.host = 'foo.com' | ||
12 | + @settings.api_key = '1234567890' | ||
13 | + assert_equal 'foo.com', @environment.settings[:anti_spam_plugin][:host] | ||
14 | + assert_equal '1234567890', @environment.settings[:anti_spam_plugin][:api_key] | ||
15 | + assert_equal 'foo.com', @settings.host | ||
16 | + assert_equal '1234567890', @settings.api_key | ||
17 | + end | ||
18 | + | ||
19 | + should 'save environment on save' do | ||
20 | + @environment.expects(:save!) | ||
21 | + @settings.save! | ||
22 | + end | ||
23 | + | ||
24 | + should 'use TypePad AntiSpam by default' do | ||
25 | + assert_equal 'api.antispam.typepad.com', @settings.host | ||
26 | + end | ||
27 | + | ||
28 | + | ||
29 | +end |
plugins/anti_spam/test/unit/anti_spam_plugin/spaminator_test.rb
0 → 100644
@@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class AntiSpamPluginSpaminatorTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @environment = Environment.new | ||
7 | + @environment.id = 99 | ||
8 | + @spaminator = AntiSpamPlugin::Spaminator.new(@environment) | ||
9 | + @spaminator.stubs(:puts) | ||
10 | + @now = Time.now | ||
11 | + Time.stubs(:now).returns(@now) | ||
12 | + end | ||
13 | + | ||
14 | + should 'search everything in the first run' do | ||
15 | + assert_equal(['profiles.environment_id = ?',99], @spaminator.send(:conditions, nil)) | ||
16 | + end | ||
17 | + | ||
18 | + should 'search using recorded last date' do | ||
19 | + @environment.settings[:spaminator_last_run] = @now | ||
20 | + assert_equal(['profiles.environment_id = ? AND table.created_at > ?', 99, @now], @spaminator.send(:conditions, 'table')) | ||
21 | + end | ||
22 | + | ||
23 | + should 'record time of last run in environment' do | ||
24 | + @spaminator.expects(:process_all_comments) | ||
25 | + @spaminator.expects(:process_all_people) | ||
26 | + @environment.stubs(:save!) | ||
27 | + @spaminator.run | ||
28 | + assert_equal @now, @environment.settings[:spaminator_last_run] | ||
29 | + end | ||
30 | + | ||
31 | + should 'find all comments' do | ||
32 | + @spaminator.stubs(:process_comment) | ||
33 | + @spaminator.send :process_all_comments | ||
34 | + end | ||
35 | + | ||
36 | + should 'find all people' do | ||
37 | + @spaminator.stubs(:process_person) | ||
38 | + @spaminator.send :process_all_people | ||
39 | + end | ||
40 | + | ||
41 | + should 'find all comments newer than a date' do | ||
42 | + @environment.settings[:spaminator_last_run] = Time.now - 1.month | ||
43 | + @spaminator.stubs(:process_comment) | ||
44 | + @spaminator.send :process_all_comments | ||
45 | + end | ||
46 | + | ||
47 | + should 'find all people newer than a date' do | ||
48 | + @environment.settings[:spaminator_last_run] = Time.now - 1.month | ||
49 | + @spaminator.stubs(:process_person) | ||
50 | + @spaminator.send :process_all_people | ||
51 | + end | ||
52 | + | ||
53 | +end |
@@ -0,0 +1,36 @@ | @@ -0,0 +1,36 @@ | ||
1 | +require 'test_helper' | ||
2 | + | ||
3 | +class AntiSpamPluginTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + profile = fast_create(Profile) | ||
7 | + article = fast_create(TextileArticle, :profile_id => profile.id) | ||
8 | + @comment = fast_create(Comment, :source_id => article.id, :source_type => 'Article') | ||
9 | + | ||
10 | + @settings = AntiSpamPlugin::Settings.new(@comment.environment) | ||
11 | + @settings.api_key = 'b8b80ddb8084062d0c9119c945ce3bc3' | ||
12 | + @settings.save! | ||
13 | + | ||
14 | + @plugin = AntiSpamPlugin.new | ||
15 | + @plugin.context = @comment | ||
16 | + end | ||
17 | + | ||
18 | + should 'check for spam and mark comment as spam if server says it is spam' do | ||
19 | + AntiSpamPlugin::CommentWrapper.any_instance.expects(:spam?).returns(true) | ||
20 | + @comment.expects(:save!) | ||
21 | + | ||
22 | + @plugin.check_comment_for_spam(@comment) | ||
23 | + assert @comment.spam | ||
24 | + end | ||
25 | + | ||
26 | + should 'report spam' do | ||
27 | + AntiSpamPlugin::CommentWrapper.any_instance.expects(:spam!) | ||
28 | + @plugin.comment_marked_as_spam(@comment) | ||
29 | + end | ||
30 | + | ||
31 | + should 'report ham' do | ||
32 | + AntiSpamPlugin::CommentWrapper.any_instance.expects(:ham!) | ||
33 | + @plugin.comment_marked_as_ham(@comment) | ||
34 | + end | ||
35 | + | ||
36 | +end |
plugins/anti_spam/views/anti_spam_plugin_admin/index.rhtml
0 → 100644
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +<h1><%= _('AntiSpam settings')%></h1> | ||
2 | + | ||
3 | +<% form_for(:settings) do |f| %> | ||
4 | + | ||
5 | + <%= labelled_form_field _('Host'), f.text_field(:host) %> | ||
6 | + | ||
7 | + <%= labelled_form_field _('API key'), f.text_field(:api_key, :size => 40) %> | ||
8 | + | ||
9 | + <% button_bar do %> | ||
10 | + <%= submit_button(:save, _('Save'), :cancel => {:controller => 'plugins', :action => 'index'}) %> | ||
11 | + <% end %> | ||
12 | + | ||
13 | +<% end %> | ||
14 | + |