Commit cbc821f22fa498cebe584b77a0fc053a263856ca
Exists in
master
and in
8 other branches
Merge commit 'refs/merge-requests/216' of git://gitorious.org/noosfero/noosfero …
…into merge-requests/216 Conflicts: debian/changelog etc/noosfero/varnish-noosfero.vcl lib/noosfero.rb
Showing
94 changed files
with
2774 additions
and
409 deletions
Show diff stats
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,7 +113,7 @@ class ApplicationController < ActionController::Base | @@ -112,7 +113,7 @@ 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 | + plugins.each do |plugin| |
116 | plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| | 117 | plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| |
117 | self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) | 118 | 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]) | 119 | self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) |
@@ -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/content_viewer_controller.rb
@@ -75,8 +75,14 @@ class ContentViewerController < ApplicationController | @@ -75,8 +75,14 @@ class ContentViewerController < ApplicationController | ||
75 | @comment = Comment.new | 75 | @comment = Comment.new |
76 | end | 76 | end |
77 | 77 | ||
78 | - if request.post? && params[:remove_comment] | ||
79 | - remove_comment | 78 | + if request.post? |
79 | + if params[:remove_comment] | ||
80 | + remove_comment | ||
81 | + return | ||
82 | + elsif params[:mark_comment_as_spam] | ||
83 | + mark_comment_as_spam | ||
84 | + return | ||
85 | + end | ||
80 | end | 86 | end |
81 | 87 | ||
82 | if @page.has_posts? | 88 | if @page.has_posts? |
@@ -107,8 +113,9 @@ class ContentViewerController < ApplicationController | @@ -107,8 +113,9 @@ class ContentViewerController < ApplicationController | ||
107 | end | 113 | end |
108 | end | 114 | end |
109 | 115 | ||
110 | - @comments = @page.comments(true).as_thread | ||
111 | - @comments_count = @page.comments.count | 116 | + comments = @page.comments.without_spam |
117 | + @comments = comments.as_thread | ||
118 | + @comments_count = comments.count | ||
112 | if params[:slideshow] | 119 | if params[:slideshow] |
113 | render :action => 'slideshow', :layout => 'slideshow' | 120 | render :action => 'slideshow', :layout => 'slideshow' |
114 | end | 121 | end |
@@ -120,10 +127,11 @@ class ContentViewerController < ApplicationController | @@ -120,10 +127,11 @@ class ContentViewerController < ApplicationController | ||
120 | @comment.author = user if logged_in? | 127 | @comment.author = user if logged_in? |
121 | @comment.article = @page | 128 | @comment.article = @page |
122 | @comment.ip_address = request.remote_ip | 129 | @comment.ip_address = request.remote_ip |
130 | + @comment.user_agent = request.user_agent | ||
131 | + @comment.referrer = request.referrer | ||
123 | plugins_filter_comment(@comment) | 132 | plugins_filter_comment(@comment) |
124 | return if @comment.rejected? | 133 | return if @comment.rejected? |
125 | if (pass_without_comment_captcha? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save | 134 | 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 | 135 | @page.touch |
128 | @comment = nil # clear the comment form | 136 | @comment = nil # clear the comment form |
129 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] | 137 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] |
@@ -138,12 +146,6 @@ class ContentViewerController < ApplicationController | @@ -138,12 +146,6 @@ class ContentViewerController < ApplicationController | ||
138 | end | 146 | end |
139 | end | 147 | end |
140 | 148 | ||
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? | 149 | def pass_without_comment_captcha? |
148 | logged_in? && !environment.enabled?('captcha_for_logged_users') | 150 | logged_in? && !environment.enabled?('captcha_for_logged_users') |
149 | end | 151 | end |
@@ -153,9 +155,24 @@ class ContentViewerController < ApplicationController | @@ -153,9 +155,24 @@ class ContentViewerController < ApplicationController | ||
153 | @comment = @page.comments.find(params[:remove_comment]) | 155 | @comment = @page.comments.find(params[:remove_comment]) |
154 | if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) | 156 | if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) |
155 | @comment.destroy | 157 | @comment.destroy |
156 | - session[:notice] = _('Comment succesfully deleted') | ||
157 | end | 158 | end |
158 | - redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] | 159 | + finish_comment_handling |
160 | + end | ||
161 | + | ||
162 | + def mark_comment_as_spam | ||
163 | + @comment = @page.comments.find(params[:mark_comment_as_spam]) | ||
164 | + if logged_in? && (user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) | ||
165 | + @comment.spam! | ||
166 | + end | ||
167 | + finish_comment_handling | ||
168 | + end | ||
169 | + | ||
170 | + def finish_comment_handling | ||
171 | + if request.xhr? | ||
172 | + render :text => {'ok' => true}.to_json, :content_type => 'application/json' | ||
173 | + else | ||
174 | + redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] | ||
175 | + end | ||
159 | end | 176 | end |
160 | 177 | ||
161 | def per_page | 178 | def per_page |
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/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? }) |
@@ -85,7 +88,28 @@ class Comment < ActiveRecord::Base | @@ -85,7 +88,28 @@ class Comment < ActiveRecord::Base | ||
85 | end | 88 | end |
86 | end | 89 | end |
87 | 90 | ||
88 | - after_create :notify_by_mail | 91 | + after_create :schedule_notification |
92 | + | ||
93 | + def schedule_notification | ||
94 | + Delayed::Job.enqueue CommentHandler.new(self.id, :verify_and_notify) | ||
95 | + end | ||
96 | + | ||
97 | + delegate :environment, :to => :profile | ||
98 | + delegate :profile, :to => :source | ||
99 | + | ||
100 | + include Noosfero::Plugin::HotSpot | ||
101 | + | ||
102 | + def verify_and_notify | ||
103 | + check_for_spam | ||
104 | + unless spam? | ||
105 | + notify_by_mail | ||
106 | + end | ||
107 | + end | ||
108 | + | ||
109 | + def check_for_spam | ||
110 | + plugins.dispatch(:check_comment_for_spam, self) | ||
111 | + end | ||
112 | + | ||
89 | def notify_by_mail | 113 | def notify_by_mail |
90 | if source.kind_of?(Article) && article.notify_comments? | 114 | if source.kind_of?(Article) && article.notify_comments? |
91 | if !article.profile.notification_emails.empty? | 115 | if !article.profile.notification_emails.empty? |
@@ -123,10 +147,14 @@ class Comment < ActiveRecord::Base | @@ -123,10 +147,14 @@ class Comment < ActiveRecord::Base | ||
123 | def self.as_thread | 147 | def self.as_thread |
124 | result = {} | 148 | result = {} |
125 | root = [] | 149 | root = [] |
126 | - all.each do |c| | 150 | + order(:id).each do |c| |
127 | c.replies = [] | 151 | c.replies = [] |
128 | result[c.id] ||= c | 152 | result[c.id] ||= c |
129 | - c.reply_of_id.nil? ? root << c : result[c.reply_of_id].replies << c | 153 | + if result[c.reply_of_id] |
154 | + result[c.reply_of_id].replies << c | ||
155 | + else | ||
156 | + root << c | ||
157 | + end | ||
130 | end | 158 | end |
131 | root | 159 | root |
132 | end | 160 | end |
@@ -183,4 +211,34 @@ class Comment < ActiveRecord::Base | @@ -183,4 +211,34 @@ class Comment < ActiveRecord::Base | ||
183 | @rejected = true | 211 | @rejected = true |
184 | end | 212 | end |
185 | 213 | ||
214 | + def spam? | ||
215 | + !spam.nil? && spam | ||
216 | + end | ||
217 | + | ||
218 | + def ham? | ||
219 | + !spam.nil? && !spam | ||
220 | + end | ||
221 | + | ||
222 | + def spam! | ||
223 | + self.spam = true | ||
224 | + self.save! | ||
225 | + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam)) | ||
226 | + self | ||
227 | + end | ||
228 | + | ||
229 | + def ham! | ||
230 | + self.spam = false | ||
231 | + self.save! | ||
232 | + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham)) | ||
233 | + self | ||
234 | + end | ||
235 | + | ||
236 | + def marked_as_spam | ||
237 | + plugins.dispatch(:comment_marked_as_spam, self) | ||
238 | + end | ||
239 | + | ||
240 | + def marked_as_ham | ||
241 | + plugins.dispatch(:comment_marked_as_ham, self) | ||
242 | + end | ||
243 | + | ||
186 | end | 244 | 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) |
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/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> | 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> | ||
18 | <tr><td><%= link_to _('Manage Licenses'), :controller =>'licenses' %></td></tr> | 11 | <tr><td><%= link_to _('Manage Licenses'), :controller =>'licenses' %></td></tr> |
19 | - <% @plugins.dispatch(:admin_panel_links).each do |link| %> | 12 | +</table> |
13 | + | ||
14 | +<h2><%= _('Profiles') %></h2> | ||
15 | + | ||
16 | +<table> | ||
17 | + <tr><td><%= link_to _('User roles'), :controller => 'role' %></td></tr> | ||
18 | + <tr><td><%= link_to _('Users'), :controller => 'users' %></td></tr> | ||
19 | + <tr><td><%= link_to _('Profile templates'), :controller => 'templates' %></td></tr> | ||
20 | + <tr><td><%= link_to _('Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr> | ||
21 | +</table> | ||
22 | + | ||
23 | + | ||
24 | +<% | ||
25 | + plugin_links = @plugins.dispatch(:admin_panel_links) | ||
26 | +%> | ||
27 | +<% unless plugin_links.empty? %> | ||
28 | + <h2><%= _('Plugins') %></h2> | ||
29 | + <table> | ||
30 | + <% plugin_links.each do |link| %> | ||
20 | <tr><td><%= link_to link[:title], link[:url] %></td></tr> | 31 | <tr><td><%= link_to link[:title], link[:url] %></td></tr> |
21 | <% end %> | 32 | <% end %> |
33 | + </table> | ||
34 | +<% end %> | ||
35 | + | ||
36 | +<h2><%= _('Enterprise-related settings') %></h2> | ||
37 | + | ||
38 | +<table> | ||
39 | + <tr><td><%= link_to __('Message for disabled enterprises'), :action => 'message_for_disabled_enterprise' %></td></tr> | ||
40 | + <tr><td><%= link_to _('Validators by region'), :controller => 'region_validators' %></td></tr> | ||
41 | + <tr><td><%= link_to _('Categories'), :controller => 'categories'%></td></tr> | ||
22 | </table> | 42 | </table> |
app/views/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,37 @@ | @@ -57,18 +52,37 @@ | ||
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'), | 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 logged_in? && (user == profile || user == comment.author || user.has_permission?(:moderate_comments, profile)) %> | ||
67 | + | ||
68 | + <%= 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') %> | ||
69 | + <% end %> | ||
70 | + | ||
71 | + <% unless comment.spam? %> | ||
72 | + | ||
73 | + <%= 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, | 74 | "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id, |
62 | :class => 'comment-footer comment-footer-link comment-footer-hide', | 75 | :class => 'comment-footer comment-footer-link comment-footer-hide', |
63 | :id => 'comment-reply-to-' + comment.id.to_s | 76 | :id => 'comment-reply-to-' + comment.id.to_s |
64 | - %> | 77 | + %> |
78 | + <% end %> | ||
65 | </div> | 79 | </div> |
66 | 80 | ||
67 | <% end %> | 81 | <% end %> |
68 | 82 | ||
69 | </div> | 83 | </div> |
70 | 84 | ||
71 | - <% unless comment.replies.blank? %> | 85 | + <% unless comment.replies.blank? || comment.spam? %> |
72 | <ul class="comment-replies"> | 86 | <ul class="comment-replies"> |
73 | <% comment.replies.each do |reply| %> | 87 | <% comment.replies.each do |reply| %> |
74 | <%= render :partial => 'comment', :locals => { :comment => reply } %> | 88 | <%= render :partial => 'comment', :locals => { :comment => reply } %> |
app/views/content_viewer/view_page.rhtml
@@ -99,12 +99,6 @@ | @@ -99,12 +99,6 @@ | ||
99 | 99 | ||
100 | <% if @page.accept_comments? %> | 100 | <% if @page.accept_comments? %> |
101 | <div id="page-comment-form"><%= render :partial => 'comment_form' %></div> | 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> | ||
108 | <% end %> | 102 | <% end %> |
109 | </div><!-- end class="comments" --> | 103 | </div><!-- end class="comments" --> |
110 | 104 |
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_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 %> |
@@ -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 %> |
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 |
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 => 20120818030329) 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 => 20120818030329) do | @@ -213,6 +213,8 @@ ActiveRecord::Schema.define(:version => 20120818030329) do | ||
213 | t.string "ip_address" | 213 | t.string "ip_address" |
214 | t.boolean "spam" | 214 | t.boolean "spam" |
215 | t.string "source_type" | 215 | t.string "source_type" |
216 | + t.string "user_agent" | ||
217 | + t.string "referrer" | ||
216 | end | 218 | end |
217 | 219 | ||
218 | create_table "contact_lists", :force => true do |t| | 220 | create_table "contact_lists", :force => true do |t| |
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 | + | ||
1 | noosfero (0.38.2) unstable; urgency=low | 7 | noosfero (0.38.2) unstable; urgency=low |
2 | 8 | ||
3 | * Bugfixes release | 9 | * Bugfixes release |
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/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.2' | 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
@@ -15,14 +15,29 @@ class Noosfero::Plugin | @@ -15,14 +15,29 @@ class Noosfero::Plugin | ||
15 | Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')).select do |entry| | 15 | Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')).select do |entry| |
16 | File.directory?(entry) | 16 | File.directory?(entry) |
17 | end.each do |dir| | 17 | 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') | 18 | + plugin_name = File.basename(dir) |
19 | + | ||
20 | + plugin_dependencies_ok = true | ||
21 | + plugin_dependencies_file = File.join(dir, 'dependencies.rb') | ||
22 | + if File.exists?(plugin_dependencies_file) | ||
23 | + begin | ||
24 | + require plugin_dependencies_file | ||
25 | + rescue LoadError => ex | ||
26 | + plugin_dependencies_ok = false | ||
27 | + $stderr.puts "W: Noosfero plugin #{plugin_name} failed to load (#{ex})" | ||
28 | + end | ||
23 | end | 29 | end |
24 | 30 | ||
25 | - klass(File.basename(dir)) | 31 | + if plugin_dependencies_ok |
32 | + Rails.configuration.controller_paths << File.join(dir, 'controllers') | ||
33 | + ActiveSupport::Dependencies.load_paths << File.join(dir, 'controllers') | ||
34 | + [ ActiveSupport::Dependencies.load_paths, $:].each do |path| | ||
35 | + path << File.join(dir, 'models') | ||
36 | + path << File.join(dir, 'lib') | ||
37 | + end | ||
38 | + | ||
39 | + klass(plugin_name) | ||
40 | + end | ||
26 | end | 41 | end |
27 | end | 42 | end |
28 | 43 | ||
@@ -226,16 +241,53 @@ class Noosfero::Plugin | @@ -226,16 +241,53 @@ class Noosfero::Plugin | ||
226 | # example: | 241 | # example: |
227 | # | 242 | # |
228 | # def filter_comment(comment) | 243 | # def filter_comment(comment) |
229 | - # comment.reject! if anti_spam_service.is_spam?(comment) | 244 | + # if user_not_logged_in |
245 | + # comment.reject! | ||
246 | + # end | ||
230 | # end | 247 | # end |
231 | # | 248 | # |
232 | def filter_comment(comment) | 249 | def filter_comment(comment) |
233 | end | 250 | end |
234 | 251 | ||
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. | 252 | + # This method is called by the CommentHandler background job before sending |
253 | + # the notification email. If the comment is marked as spam (i.e. by calling | ||
254 | + # <tt>comment.spam!</tt>), then the notification email will *not* be sent. | ||
255 | + # | ||
256 | + # example: | ||
257 | + # | ||
258 | + # def check_comment_for_spam(comment) | ||
259 | + # if anti_spam_service.is_spam?(comment) | ||
260 | + # comment.spam! | ||
261 | + # end | ||
262 | + # end | ||
263 | + # | ||
264 | + def check_comment_for_spam(comment) | ||
265 | + end | ||
266 | + | ||
267 | + # This method is called when the user manually marks a comment as SPAM. A | ||
268 | + # plugin implementing this method should train its spam detection mechanism | ||
269 | + # by submitting this comment as a confirmed spam. | ||
270 | + # | ||
271 | + # example: | ||
272 | + # | ||
273 | + # def comment_marked_as_spam(comment) | ||
274 | + # anti_spam_service.train_with_spam(comment) | ||
275 | + # end | ||
276 | + # | ||
277 | + def comment_marked_as_spam(comment) | ||
278 | + end | ||
279 | + | ||
280 | + # This method is called when the user manually marks a comment a NOT SPAM. A | ||
281 | + # plugin implementing this method should train its spam detection mechanism | ||
282 | + # by submitting this coimment as a confirmed ham. | ||
283 | + # | ||
284 | + # example: | ||
285 | + # | ||
286 | + # def comment_marked_as_ham(comment) | ||
287 | + # anti_spam_service.train_with_ham(comment) | ||
288 | + # end | ||
237 | # | 289 | # |
238 | - def comment_saved(comment) | 290 | + def comment_marked_as_ham(comment) |
239 | end | 291 | end |
240 | 292 | ||
241 | # -> Adds fields to the signup form | 293 | # -> Adds fields to the signup form |
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/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 | + |
plugins/mezuro/lib/mezuro_plugin.rb
plugins/mezuro/lib/mezuro_plugin/helpers/content_viewer_helper.rb
plugins/require_auth_to_comment/test/unit/require_auth_to_comment_plugin_test.rb
@@ -35,7 +35,7 @@ class RequireAuthToCommentPluginTest < ActiveSupport::TestCase | @@ -35,7 +35,7 @@ class RequireAuthToCommentPluginTest < ActiveSupport::TestCase | ||
35 | controller = mock() | 35 | controller = mock() |
36 | controller.stubs(:logged_in?).returns(boolean) | 36 | controller.stubs(:logged_in?).returns(boolean) |
37 | controller.stubs(:profile).returns(Profile.new) | 37 | controller.stubs(:profile).returns(Profile.new) |
38 | - Noosfero::Plugin::Context.new(controller) | 38 | + controller |
39 | end | 39 | end |
40 | 40 | ||
41 | end | 41 | end |
plugins/stoa/test/functional/profile_editor_controller.rb
@@ -1,55 +0,0 @@ | @@ -1,55 +0,0 @@ | ||
1 | -require File.dirname(__FILE__) + '/../../../../test/test_helper' | ||
2 | -require File.dirname(__FILE__) + '/../../../../app/controllers/my_profile/profile_editor_controller' | ||
3 | - | ||
4 | -# Re-raise errors caught by the controller. | ||
5 | -class ProfileEditorController; def rescue_action(e) raise e end; end | ||
6 | - | ||
7 | -class ProfileEditorTest < ActionController::TestCase | ||
8 | - | ||
9 | - SALT=YAML::load(File.open(StoaPlugin.root_path + '/config.yml'))['salt'] | ||
10 | - | ||
11 | - def setup | ||
12 | - @controller = ProfileEditorController.new | ||
13 | - @request = ActionController::TestRequest.new | ||
14 | - @response = ActionController::TestResponse.new | ||
15 | - @person = User.create(:login => 'test_user', :email => 'test_user@example.com', :password => 'test', :password_confirmation => 'test').person | ||
16 | - login_as(@person.identifier) | ||
17 | - Environment.default.enable_plugin(StoaPlugin.name) | ||
18 | - db = Tempfile.new('stoa-test') | ||
19 | - ActiveRecord::Base.configurations['stoa'] = {:adapter => 'sqlite3', :database => db.path} | ||
20 | - end | ||
21 | - | ||
22 | - attr_accessor :person | ||
23 | - | ||
24 | - should 'show usp_id field if person did not filled it' do | ||
25 | - get :edit, :profile => person.identifier | ||
26 | - assert_match /USP number/, @response.body | ||
27 | - end | ||
28 | - | ||
29 | - should 'not show usp_id field if person already filled it' do | ||
30 | - person.usp_id = 12345 | ||
31 | - person.save | ||
32 | - get :edit, :profile => person.identifier | ||
33 | - assert_no_match /USP number/, @response.body | ||
34 | - end | ||
35 | - | ||
36 | - should 'not display field if profile is an organization' do | ||
37 | - organization = fast_create(Organization) | ||
38 | - get :edit, :profile => organization.identifier | ||
39 | - assert_no_match /USP number/, @response.body | ||
40 | - end | ||
41 | - | ||
42 | - should 'display error if usp_id does not match with supplied confirmation' do | ||
43 | - StoaPlugin::UspUser.stubs(:matches?).returns(false) | ||
44 | - post :edit, :profile => person.identifier, :profile_data => {:usp_id => 12345678}, :confirmation_field => 'cpf', :cpf => 99999999 | ||
45 | - assert assigns(:profile_data).errors.invalid?(:usp_id) | ||
46 | - end | ||
47 | - | ||
48 | - should 'save usp_id if everyhtings is ok' do | ||
49 | - StoaPlugin::UspUser.stubs(:matches?).returns(true) | ||
50 | - post :edit, :profile => person.identifier, :profile_data => {:usp_id => 12345678}, :confirmation_field => 'cpf', :cpf => 99999999 | ||
51 | - person.reload | ||
52 | - assert_equal '12345678', person.usp_id | ||
53 | - end | ||
54 | - | ||
55 | -end |
plugins/stoa/test/functional/profile_editor_controller_test.rb
0 → 100644
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +require File.dirname(__FILE__) + '/../../../../test/test_helper' | ||
2 | +require File.dirname(__FILE__) + '/../../../../app/controllers/my_profile/profile_editor_controller' | ||
3 | + | ||
4 | +# Re-raise errors caught by the controller. | ||
5 | +class ProfileEditorController; def rescue_action(e) raise e end; end | ||
6 | + | ||
7 | +class StoaPluginProfileEditorControllerTest < ActionController::TestCase | ||
8 | + | ||
9 | + SALT=YAML::load(File.open(StoaPlugin.root_path + '/config.yml'))['salt'] | ||
10 | + | ||
11 | + def setup | ||
12 | + @controller = ProfileEditorController.new | ||
13 | + @request = ActionController::TestRequest.new | ||
14 | + @response = ActionController::TestResponse.new | ||
15 | + @person = User.create(:login => 'test_user', :email => 'test_user@example.com', :password => 'test', :password_confirmation => 'test').person | ||
16 | + login_as(@person.identifier) | ||
17 | + Environment.default.enable_plugin(StoaPlugin.name) | ||
18 | + db = Tempfile.new('stoa-test') | ||
19 | + ActiveRecord::Base.configurations['stoa'] = {:adapter => 'sqlite3', :database => db.path} | ||
20 | + end | ||
21 | + | ||
22 | + attr_accessor :person | ||
23 | + | ||
24 | + should 'show usp_id field if person did not filled it' do | ||
25 | + get :edit, :profile => person.identifier | ||
26 | + assert_match /USP number/, @response.body | ||
27 | + end | ||
28 | + | ||
29 | + should 'not show usp_id field if person already filled it' do | ||
30 | + person.usp_id = 12345 | ||
31 | + person.save | ||
32 | + get :edit, :profile => person.identifier | ||
33 | + assert_no_match /USP number/, @response.body | ||
34 | + end | ||
35 | + | ||
36 | + should 'not display field if profile is an organization' do | ||
37 | + organization = fast_create(Organization) | ||
38 | + get :edit, :profile => organization.identifier | ||
39 | + assert_no_match /USP number/, @response.body | ||
40 | + end | ||
41 | + | ||
42 | + should 'display error if usp_id does not match with supplied confirmation' do | ||
43 | + StoaPlugin::UspUser.stubs(:matches?).returns(false) | ||
44 | + post :edit, :profile => person.identifier, :profile_data => {:usp_id => 12345678}, :confirmation_field => 'cpf', :cpf => 99999999 | ||
45 | + assert assigns(:profile_data).errors.invalid?(:usp_id) | ||
46 | + end | ||
47 | + | ||
48 | + should 'save usp_id if everyhtings is ok' do | ||
49 | + StoaPlugin::UspUser.stubs(:matches?).returns(true) | ||
50 | + post :edit, :profile => person.identifier, :profile_data => {:usp_id => 12345678}, :confirmation_field => 'cpf', :cpf => 99999999 | ||
51 | + person.reload | ||
52 | + assert_equal '12345678', person.usp_id | ||
53 | + end | ||
54 | + | ||
55 | +end |
3.94 KB
@@ -0,0 +1,504 @@ | @@ -0,0 +1,504 @@ | ||
1 | +<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
2 | +<!-- Created with Inkscape (http://www.inkscape.org/) --> | ||
3 | +<svg | ||
4 | + xmlns:dc="http://purl.org/dc/elements/1.1/" | ||
5 | + xmlns:cc="http://creativecommons.org/ns#" | ||
6 | + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | ||
7 | + xmlns:svg="http://www.w3.org/2000/svg" | ||
8 | + xmlns="http://www.w3.org/2000/svg" | ||
9 | + xmlns:xlink="http://www.w3.org/1999/xlink" | ||
10 | + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" | ||
11 | + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" | ||
12 | + inkscape:export-ydpi="90.000000" | ||
13 | + inkscape:export-xdpi="90.000000" | ||
14 | + inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png" | ||
15 | + width="48px" | ||
16 | + height="48px" | ||
17 | + id="svg11300" | ||
18 | + sodipodi:version="0.32" | ||
19 | + inkscape:version="0.46" | ||
20 | + sodipodi:docbase="/home/jimmac/src/cvs/tango-icon-theme/scalable/actions" | ||
21 | + sodipodi:docname="mail-mark-junk.svg" | ||
22 | + inkscape:output_extension="org.inkscape.output.svg.inkscape"> | ||
23 | + <defs | ||
24 | + id="defs3"> | ||
25 | + <inkscape:perspective | ||
26 | + sodipodi:type="inkscape:persp3d" | ||
27 | + inkscape:vp_x="0 : 24 : 1" | ||
28 | + inkscape:vp_y="0 : 1000 : 0" | ||
29 | + inkscape:vp_z="48 : 24 : 1" | ||
30 | + inkscape:persp3d-origin="24 : 16 : 1" | ||
31 | + id="perspective72" /> | ||
32 | + <linearGradient | ||
33 | + inkscape:collect="always" | ||
34 | + id="linearGradient5166"> | ||
35 | + <stop | ||
36 | + style="stop-color:white;stop-opacity:1;" | ||
37 | + offset="0" | ||
38 | + id="stop5168" /> | ||
39 | + <stop | ||
40 | + style="stop-color:white;stop-opacity:0;" | ||
41 | + offset="1" | ||
42 | + id="stop5170" /> | ||
43 | + </linearGradient> | ||
44 | + <linearGradient | ||
45 | + id="linearGradient5196"> | ||
46 | + <stop | ||
47 | + style="stop-color:#dfe2dc;stop-opacity:1;" | ||
48 | + offset="0" | ||
49 | + id="stop5198" /> | ||
50 | + <stop | ||
51 | + style="stop-color:#86917a;stop-opacity:1;" | ||
52 | + offset="1" | ||
53 | + id="stop5200" /> | ||
54 | + </linearGradient> | ||
55 | + <linearGradient | ||
56 | + id="linearGradient5188"> | ||
57 | + <stop | ||
58 | + style="stop-color:white;stop-opacity:1;" | ||
59 | + offset="0" | ||
60 | + id="stop5190" /> | ||
61 | + <stop | ||
62 | + style="stop-color:#aeaea3;stop-opacity:1;" | ||
63 | + offset="1" | ||
64 | + id="stop5192" /> | ||
65 | + </linearGradient> | ||
66 | + <linearGradient | ||
67 | + inkscape:collect="always" | ||
68 | + id="linearGradient5176"> | ||
69 | + <stop | ||
70 | + style="stop-color:black;stop-opacity:1;" | ||
71 | + offset="0" | ||
72 | + id="stop5178" /> | ||
73 | + <stop | ||
74 | + style="stop-color:black;stop-opacity:0;" | ||
75 | + offset="1" | ||
76 | + id="stop5180" /> | ||
77 | + </linearGradient> | ||
78 | + <linearGradient | ||
79 | + id="linearGradient5162"> | ||
80 | + <stop | ||
81 | + style="stop-color:#babdb6;stop-opacity:1;" | ||
82 | + offset="0" | ||
83 | + id="stop5164" /> | ||
84 | + <stop | ||
85 | + style="stop-color:white;stop-opacity:1;" | ||
86 | + offset="1" | ||
87 | + id="stop5166" /> | ||
88 | + </linearGradient> | ||
89 | + <linearGradient | ||
90 | + inkscape:collect="always" | ||
91 | + id="linearGradient5150"> | ||
92 | + <stop | ||
93 | + style="stop-color:black;stop-opacity:1;" | ||
94 | + offset="0" | ||
95 | + id="stop5152" /> | ||
96 | + <stop | ||
97 | + style="stop-color:black;stop-opacity:0;" | ||
98 | + offset="1" | ||
99 | + id="stop5154" /> | ||
100 | + </linearGradient> | ||
101 | + <linearGradient | ||
102 | + id="linearGradient11520"> | ||
103 | + <stop | ||
104 | + id="stop11522" | ||
105 | + offset="0.0000000" | ||
106 | + style="stop-color:#ffffff;stop-opacity:1.0000000;" /> | ||
107 | + <stop | ||
108 | + id="stop11524" | ||
109 | + offset="1.0000000" | ||
110 | + style="stop-color:#dcdcdc;stop-opacity:1.0000000;" /> | ||
111 | + </linearGradient> | ||
112 | + <linearGradient | ||
113 | + id="linearGradient11508" | ||
114 | + inkscape:collect="always"> | ||
115 | + <stop | ||
116 | + id="stop11510" | ||
117 | + offset="0" | ||
118 | + style="stop-color:#000000;stop-opacity:1;" /> | ||
119 | + <stop | ||
120 | + id="stop11512" | ||
121 | + offset="1" | ||
122 | + style="stop-color:#000000;stop-opacity:0;" /> | ||
123 | + </linearGradient> | ||
124 | + <linearGradient | ||
125 | + id="linearGradient11494" | ||
126 | + inkscape:collect="always"> | ||
127 | + <stop | ||
128 | + id="stop11496" | ||
129 | + offset="0" | ||
130 | + style="stop-color:#ef2929;stop-opacity:1;" /> | ||
131 | + <stop | ||
132 | + id="stop11498" | ||
133 | + offset="1" | ||
134 | + style="stop-color:#ef2929;stop-opacity:0;" /> | ||
135 | + </linearGradient> | ||
136 | + <linearGradient | ||
137 | + id="linearGradient11415"> | ||
138 | + <stop | ||
139 | + id="stop11417" | ||
140 | + offset="0.0000000" | ||
141 | + style="stop-color:#204a87;stop-opacity:0.0000000;" /> | ||
142 | + <stop | ||
143 | + style="stop-color:#204a87;stop-opacity:1.0000000;" | ||
144 | + offset="0.50000000" | ||
145 | + id="stop11423" /> | ||
146 | + <stop | ||
147 | + id="stop11419" | ||
148 | + offset="1" | ||
149 | + style="stop-color:#204a87;stop-opacity:0;" /> | ||
150 | + </linearGradient> | ||
151 | + <linearGradient | ||
152 | + id="linearGradient11399" | ||
153 | + inkscape:collect="always"> | ||
154 | + <stop | ||
155 | + id="stop11401" | ||
156 | + offset="0" | ||
157 | + style="stop-color:#000000;stop-opacity:1;" /> | ||
158 | + <stop | ||
159 | + id="stop11403" | ||
160 | + offset="1" | ||
161 | + style="stop-color:#000000;stop-opacity:0;" /> | ||
162 | + </linearGradient> | ||
163 | + <linearGradient | ||
164 | + gradientTransform="translate(-60.28571,-0.285714)" | ||
165 | + y2="34.462429" | ||
166 | + x2="43.615788" | ||
167 | + y1="3.7744560" | ||
168 | + x1="15.828360" | ||
169 | + gradientUnits="userSpaceOnUse" | ||
170 | + id="linearGradient11425" | ||
171 | + xlink:href="#linearGradient11415" | ||
172 | + inkscape:collect="always" /> | ||
173 | + <linearGradient | ||
174 | + gradientTransform="translate(-60.57143,0.000000)" | ||
175 | + y2="39.033859" | ||
176 | + x2="35.679932" | ||
177 | + y1="9.3458843" | ||
178 | + x1="9.6957054" | ||
179 | + gradientUnits="userSpaceOnUse" | ||
180 | + id="linearGradient11427" | ||
181 | + xlink:href="#linearGradient11415" | ||
182 | + inkscape:collect="always" /> | ||
183 | + <linearGradient | ||
184 | + y2="33.462429" | ||
185 | + x2="26.758644" | ||
186 | + y1="19.774456" | ||
187 | + x1="13.267134" | ||
188 | + gradientTransform="translate(-60.85714,0.428571)" | ||
189 | + gradientUnits="userSpaceOnUse" | ||
190 | + id="linearGradient11439" | ||
191 | + xlink:href="#linearGradient11415" | ||
192 | + inkscape:collect="always" /> | ||
193 | + <radialGradient | ||
194 | + r="8.5000000" | ||
195 | + fy="39.142857" | ||
196 | + fx="12.071428" | ||
197 | + cy="39.142857" | ||
198 | + cx="12.071428" | ||
199 | + gradientTransform="matrix(1.000000,0.000000,0.000000,0.487395,0.000000,20.06483)" | ||
200 | + gradientUnits="userSpaceOnUse" | ||
201 | + id="radialGradient11441" | ||
202 | + xlink:href="#linearGradient11399" | ||
203 | + inkscape:collect="always" /> | ||
204 | + <radialGradient | ||
205 | + gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)" | ||
206 | + gradientUnits="userSpaceOnUse" | ||
207 | + r="3.8335034" | ||
208 | + fy="15.048258" | ||
209 | + fx="27.577173" | ||
210 | + cy="15.048258" | ||
211 | + cx="27.577173" | ||
212 | + id="radialGradient11500" | ||
213 | + xlink:href="#linearGradient11494" | ||
214 | + inkscape:collect="always" /> | ||
215 | + <radialGradient | ||
216 | + r="3.8335034" | ||
217 | + fy="16.049133" | ||
218 | + fx="27.577173" | ||
219 | + cy="16.049133" | ||
220 | + cx="27.577173" | ||
221 | + gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)" | ||
222 | + gradientUnits="userSpaceOnUse" | ||
223 | + id="radialGradient11504" | ||
224 | + xlink:href="#linearGradient11494" | ||
225 | + inkscape:collect="always" /> | ||
226 | + <radialGradient | ||
227 | + gradientUnits="userSpaceOnUse" | ||
228 | + gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,2.166583e-14,29.48178)" | ||
229 | + r="6.5659914" | ||
230 | + fy="44.565483" | ||
231 | + fx="30.203562" | ||
232 | + cy="44.565483" | ||
233 | + cx="30.203562" | ||
234 | + id="radialGradient11514" | ||
235 | + xlink:href="#linearGradient11508" | ||
236 | + inkscape:collect="always" /> | ||
237 | + <radialGradient | ||
238 | + gradientTransform="matrix(1.995058,-1.651527e-32,0.000000,1.995058,-24.32488,-35.70087)" | ||
239 | + gradientUnits="userSpaceOnUse" | ||
240 | + r="20.530962" | ||
241 | + fy="35.878170" | ||
242 | + fx="24.445690" | ||
243 | + cy="35.878170" | ||
244 | + cx="24.445690" | ||
245 | + id="radialGradient11526" | ||
246 | + xlink:href="#linearGradient11520" | ||
247 | + inkscape:collect="always" /> | ||
248 | + <radialGradient | ||
249 | + r="6.5659914" | ||
250 | + fy="44.565483" | ||
251 | + fx="30.203562" | ||
252 | + cy="44.565483" | ||
253 | + cx="30.203562" | ||
254 | + gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,3.185827e-15,29.48178)" | ||
255 | + gradientUnits="userSpaceOnUse" | ||
256 | + id="radialGradient11532" | ||
257 | + xlink:href="#linearGradient11508" | ||
258 | + inkscape:collect="always" /> | ||
259 | + <radialGradient | ||
260 | + inkscape:collect="always" | ||
261 | + xlink:href="#linearGradient11508" | ||
262 | + id="radialGradient1348" | ||
263 | + gradientUnits="userSpaceOnUse" | ||
264 | + gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,-1.353344e-14,29.48178)" | ||
265 | + cx="30.203562" | ||
266 | + cy="44.565483" | ||
267 | + fx="30.203562" | ||
268 | + fy="44.565483" | ||
269 | + r="6.5659914" /> | ||
270 | + <radialGradient | ||
271 | + inkscape:collect="always" | ||
272 | + xlink:href="#linearGradient11520" | ||
273 | + id="radialGradient1350" | ||
274 | + gradientUnits="userSpaceOnUse" | ||
275 | + gradientTransform="matrix(1.995058,-1.651527e-32,0.000000,1.995058,-24.32488,-35.70087)" | ||
276 | + cx="24.445690" | ||
277 | + cy="35.878170" | ||
278 | + fx="24.445690" | ||
279 | + fy="35.878170" | ||
280 | + r="20.530962" /> | ||
281 | + <radialGradient | ||
282 | + inkscape:collect="always" | ||
283 | + xlink:href="#linearGradient11494" | ||
284 | + id="radialGradient1352" | ||
285 | + gradientUnits="userSpaceOnUse" | ||
286 | + gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)" | ||
287 | + cx="27.577173" | ||
288 | + cy="16.049133" | ||
289 | + fx="27.577173" | ||
290 | + fy="16.049133" | ||
291 | + r="3.8335034" /> | ||
292 | + <radialGradient | ||
293 | + inkscape:collect="always" | ||
294 | + xlink:href="#linearGradient11494" | ||
295 | + id="radialGradient1354" | ||
296 | + gradientUnits="userSpaceOnUse" | ||
297 | + gradientTransform="matrix(1.243453,2.106784e-16,-2.106784e-16,1.243453,-6.713754,-3.742847)" | ||
298 | + cx="27.577173" | ||
299 | + cy="15.048258" | ||
300 | + fx="27.577173" | ||
301 | + fy="15.048258" | ||
302 | + r="3.8335034" /> | ||
303 | + <radialGradient | ||
304 | + inkscape:collect="always" | ||
305 | + xlink:href="#linearGradient11508" | ||
306 | + id="radialGradient1356" | ||
307 | + gradientUnits="userSpaceOnUse" | ||
308 | + gradientTransform="matrix(1.000000,0.000000,0.000000,0.338462,2.220359e-14,29.48178)" | ||
309 | + cx="30.203562" | ||
310 | + cy="44.565483" | ||
311 | + fx="30.203562" | ||
312 | + fy="44.565483" | ||
313 | + r="6.5659914" /> | ||
314 | + <radialGradient | ||
315 | + inkscape:collect="always" | ||
316 | + xlink:href="#linearGradient11520" | ||
317 | + id="radialGradient1366" | ||
318 | + gradientUnits="userSpaceOnUse" | ||
319 | + gradientTransform="matrix(2.049266,-1.696401e-32,0.000000,2.049266,-25.65002,-37.31089)" | ||
320 | + cx="24.445690" | ||
321 | + cy="35.878170" | ||
322 | + fx="24.445690" | ||
323 | + fy="35.878170" | ||
324 | + r="20.530962" /> | ||
325 | + <radialGradient | ||
326 | + inkscape:collect="always" | ||
327 | + xlink:href="#linearGradient5150" | ||
328 | + id="radialGradient5156" | ||
329 | + cx="24.837126" | ||
330 | + cy="40.663769" | ||
331 | + fx="24.837126" | ||
332 | + fy="40.663769" | ||
333 | + r="21.478369" | ||
334 | + gradientTransform="matrix(1,0,0,0.325103,2.211772e-16,27.44386)" | ||
335 | + gradientUnits="userSpaceOnUse" /> | ||
336 | + <linearGradient | ||
337 | + inkscape:collect="always" | ||
338 | + xlink:href="#linearGradient5162" | ||
339 | + id="linearGradient5168" | ||
340 | + x1="24.365993" | ||
341 | + y1="20.246058" | ||
342 | + x2="32.600704" | ||
343 | + y2="28.554564" | ||
344 | + gradientUnits="userSpaceOnUse" /> | ||
345 | + <linearGradient | ||
346 | + inkscape:collect="always" | ||
347 | + xlink:href="#linearGradient5162" | ||
348 | + id="linearGradient5170" | ||
349 | + gradientUnits="userSpaceOnUse" | ||
350 | + x1="22.008699" | ||
351 | + y1="36.509514" | ||
352 | + x2="23.585091" | ||
353 | + y2="14.412428" /> | ||
354 | + <linearGradient | ||
355 | + inkscape:collect="always" | ||
356 | + xlink:href="#linearGradient5176" | ||
357 | + id="linearGradient5182" | ||
358 | + x1="25.632622" | ||
359 | + y1="10.611729" | ||
360 | + x2="38.714096" | ||
361 | + y2="18.389904" | ||
362 | + gradientUnits="userSpaceOnUse" /> | ||
363 | + <radialGradient | ||
364 | + inkscape:collect="always" | ||
365 | + xlink:href="#linearGradient5188" | ||
366 | + id="radialGradient5361" | ||
367 | + gradientUnits="userSpaceOnUse" | ||
368 | + gradientTransform="matrix(2.135667,1.912751e-16,-1.890308e-16,2.110607,-26.90176,-15.66914)" | ||
369 | + cx="23.688078" | ||
370 | + cy="14.210698" | ||
371 | + fx="23.688078" | ||
372 | + fy="14.210698" | ||
373 | + r="22.597087" /> | ||
374 | + <radialGradient | ||
375 | + inkscape:collect="always" | ||
376 | + xlink:href="#linearGradient5196" | ||
377 | + id="radialGradient5363" | ||
378 | + gradientUnits="userSpaceOnUse" | ||
379 | + gradientTransform="matrix(1.790269,1.339577e-16,-1.323859e-16,1.769263,-15.81394,-11.94997)" | ||
380 | + cx="20.089987" | ||
381 | + cy="10.853651" | ||
382 | + fx="20.089987" | ||
383 | + fy="10.853651" | ||
384 | + r="22.597087" /> | ||
385 | + <linearGradient | ||
386 | + inkscape:collect="always" | ||
387 | + xlink:href="#linearGradient5166" | ||
388 | + id="linearGradient5172" | ||
389 | + x1="19.450956" | ||
390 | + y1="14.463861" | ||
391 | + x2="23.71875" | ||
392 | + y2="48.404987" | ||
393 | + gradientUnits="userSpaceOnUse" /> | ||
394 | + </defs> | ||
395 | + <sodipodi:namedview | ||
396 | + stroke="#ef2929" | ||
397 | + fill="#eeeeec" | ||
398 | + id="base" | ||
399 | + pagecolor="#ffffff" | ||
400 | + bordercolor="#666666" | ||
401 | + borderopacity="0.25490196" | ||
402 | + inkscape:pageopacity="0.0" | ||
403 | + inkscape:pageshadow="2" | ||
404 | + inkscape:zoom="1" | ||
405 | + inkscape:cx="-91.650069" | ||
406 | + inkscape:cy="-6.8095951" | ||
407 | + inkscape:current-layer="layer1" | ||
408 | + showgrid="false" | ||
409 | + inkscape:grid-bbox="true" | ||
410 | + inkscape:document-units="px" | ||
411 | + inkscape:showpageshadow="false" | ||
412 | + inkscape:window-width="872" | ||
413 | + inkscape:window-height="688" | ||
414 | + inkscape:window-x="441" | ||
415 | + inkscape:window-y="160" /> | ||
416 | + <metadata | ||
417 | + id="metadata4"> | ||
418 | + <rdf:RDF> | ||
419 | + <cc:Work | ||
420 | + rdf:about=""> | ||
421 | + <dc:format>image/svg+xml</dc:format> | ||
422 | + <dc:type | ||
423 | + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> | ||
424 | + <dc:creator> | ||
425 | + <cc:Agent> | ||
426 | + <dc:title>Jakub Steiner</dc:title> | ||
427 | + </cc:Agent> | ||
428 | + </dc:creator> | ||
429 | + <dc:source>http://jimmac.musichall.cz</dc:source> | ||
430 | + <cc:license | ||
431 | + rdf:resource="http://creativecommons.org/licenses/publicdomain/" /> | ||
432 | + <dc:title>Mark mail as Junk</dc:title> | ||
433 | + <dc:subject> | ||
434 | + <rdf:Bag> | ||
435 | + <rdf:li>mail</rdf:li> | ||
436 | + <rdf:li>spam</rdf:li> | ||
437 | + <rdf:li>junk</rdf:li> | ||
438 | + </rdf:Bag> | ||
439 | + </dc:subject> | ||
440 | + </cc:Work> | ||
441 | + <cc:License | ||
442 | + rdf:about="http://creativecommons.org/licenses/publicdomain/"> | ||
443 | + <cc:permits | ||
444 | + rdf:resource="http://creativecommons.org/ns#Reproduction" /> | ||
445 | + <cc:permits | ||
446 | + rdf:resource="http://creativecommons.org/ns#Distribution" /> | ||
447 | + <cc:permits | ||
448 | + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> | ||
449 | + </cc:License> | ||
450 | + </rdf:RDF> | ||
451 | + </metadata> | ||
452 | + <g | ||
453 | + id="layer1" | ||
454 | + inkscape:label="Layer 1" | ||
455 | + inkscape:groupmode="layer"> | ||
456 | + <path | ||
457 | + sodipodi:type="arc" | ||
458 | + style="opacity:0.3258427;color:black;fill:url(#radialGradient5156);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
459 | + id="path4275" | ||
460 | + sodipodi:cx="24.837126" | ||
461 | + sodipodi:cy="40.663769" | ||
462 | + sodipodi:rx="21.478369" | ||
463 | + sodipodi:ry="6.9826794" | ||
464 | + d="M 46.315495 40.663769 A 21.478369 6.9826794 0 1 1 3.358757,40.663769 A 21.478369 6.9826794 0 1 1 46.315495 40.663769 z" | ||
465 | + transform="matrix(1.106996,0,0,1.106996,-3.364576,-5.411516)" /> | ||
466 | + <path | ||
467 | + style="opacity:1;color:black;fill:url(#radialGradient5361);fill-opacity:1;fill-rule:evenodd;stroke:url(#radialGradient5363);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
468 | + d="M 9.0156115,37.570175 L 7.2478445,40.398602 L 10.960155,41.989592 L 13.611806,39.868272 L 25.455844,40.752155 L 29.168155,45.701903 L 32.526912,40.221825 L 36.769553,42.519922 L 42.426407,41.812816 L 41.012193,38.807612 L 44.901281,34.918524 L 39.421203,28.73134 L 44.724504,29.438447 L 47.022601,27.317127 L 44.017397,27.847457 L 40.835417,22.367379 L 36.239223,21.306719 L 39.951533,20.069282 L 40.12831,16.887302 L 32.880465,10.523341 L 30.228815,2.0380592 L 18.208,5.5735931 L 15.202796,12.644661 L 14.142136,10.346564 L 11.136932,10.523341 L 11.136932,13.351768 L 7.6013979,9.2859037 L 2.8284271,14.412428 L 2.8284271,21.660272 L 11.136932,28.908117 L 5.833631,31.913321 L 6.0104076,34.918524 L 9.0156115,37.570175 z " | ||
469 | + id="path4273" /> | ||
470 | + <path | ||
471 | + style="opacity:0.76966292;color:black;fill:url(#linearGradient5170);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
472 | + d="M 19.445437,22.720933 L 18.561553,29.26167 L 20.682873,32.620427 L 16.086679,34.034641 L 13.435029,39.337942 L 25.455844,40.221825 L 28.284271,44.287689 L 30.582368,38.100505 L 26.162951,35.272078 L 19.445437,37.216622 L 22.097087,33.681088 L 20.682873,27.493903 L 19.445437,22.720933 z " | ||
473 | + id="path5158" /> | ||
474 | + <path | ||
475 | + style="opacity:0.61797753;color:black;fill:url(#linearGradient5168);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
476 | + d="M 20.506097,23.781593 L 24.925514,30.675884 L 32.173359,25.726136 L 36.592776,28.20101 L 40.12831,25.195806 L 43.31029,28.024233 L 40.305087,23.074486 L 33.410795,21.483496 L 24.748737,17.240855 C 24.748737,17.240855 12.374369,20.953166 13.081475,20.953166 C 13.788582,20.953166 23.334524,21.129942 23.334524,21.129942 L 24.925514,18.831845 L 29.168155,20.776389 L 20.506097,23.781593 z " | ||
477 | + id="path5160" /> | ||
478 | + <path | ||
479 | + style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
480 | + d="M 29.521708,3.4522727 L 19.091883,6.9878066 L 17.67767,10.876894 L 23.688077,15.119535 L 29.344931,9.6394571 L 29.521708,3.4522727 z " | ||
481 | + id="path5172" /> | ||
482 | + <path | ||
483 | + style="opacity:0.13483146;color:black;fill:url(#linearGradient5182);fill-opacity:1.0;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
484 | + d="M 29.698485,3.8058261 L 31.996582,11.230447 L 36.239223,14.942758 L 27.577165,12.998214 C 27.577165,12.998214 25.102291,15.826641 26.162951,15.826641 C 27.223611,15.826641 38.714096,17.240855 38.714096,17.240855 L 38.53732,19.538952 L 22.273864,16.533748 L 29.344931,9.9930105 L 29.698485,3.8058261 z " | ||
485 | + id="path5174" /> | ||
486 | + <path | ||
487 | + style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
488 | + d="M 7.4246212,14.235651 L 6.5407377,23.074486 L 8.4852814,17.064078 L 13.611806,18.655069 L 14.849242,16.003418 L 21.036427,16.887302 L 22.45064,15.649865 L 13.435029,15.296311 L 12.551145,17.771185 L 8.6620581,15.826641 L 7.4246212,14.235651 z " | ||
489 | + id="path5184" /> | ||
490 | + <path | ||
491 | + style="opacity:1;color:black;fill:white;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
492 | + d="M 22.45064,27.317127 L 25.455844,30.852661 L 32.350135,26.256466 L 36.592776,28.554563 L 43.487067,35.095301 L 35.885669,29.26167 L 32.173359,28.20101 L 24.925514,33.150758 L 22.45064,27.317127 z " | ||
493 | + id="path5186" /> | ||
494 | + <path | ||
495 | + sodipodi:type="inkscape:offset" | ||
496 | + inkscape:radius="-0.83777463" | ||
497 | + inkscape:original="M 30.21875 2.03125 L 18.21875 5.5625 L 15.1875 12.65625 L 14.15625 10.34375 L 11.125 10.53125 L 11.125 13.34375 L 7.59375 9.28125 L 2.84375 14.40625 L 2.84375 21.65625 L 11.125 28.90625 L 5.84375 31.90625 L 6 34.90625 L 9 37.5625 L 7.25 40.40625 L 10.96875 42 L 13.625 39.875 L 25.46875 40.75 L 29.15625 45.6875 L 32.53125 40.21875 L 36.78125 42.53125 L 42.4375 41.8125 L 41 38.8125 L 44.90625 34.90625 L 39.40625 28.71875 L 44.71875 29.4375 L 47.03125 27.3125 L 44.03125 27.84375 L 40.84375 22.375 L 36.25 21.3125 L 39.9375 20.0625 L 40.125 16.875 L 32.875 10.53125 L 30.21875 2.03125 z " | ||
498 | + xlink:href="#path4273" | ||
499 | + style="opacity:1;color:black;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5172);stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" | ||
500 | + id="path5359" | ||
501 | + inkscape:href="#path4273" | ||
502 | + d="M 29.65625,3.09375 L 18.84375,6.25 L 15.96875,13 C 15.834262,13.30255 15.53422,13.497528 15.203125,13.497528 C 14.87203,13.497528 14.571988,13.30255 14.4375,13 L 13.65625,11.21875 L 11.96875,11.3125 L 11.96875,13.34375 C 11.973462,13.69495 11.758625,14.011813 11.430625,14.13743 C 11.102625,14.263047 10.731089,14.170753 10.5,13.90625 L 7.5625,10.53125 L 3.6875,14.71875 L 3.6875,21.28125 L 11.6875,28.28125 C 11.883657,28.462891 11.981357,28.727236 11.950479,28.992788 C 11.919601,29.25834 11.763852,29.493214 11.53125,29.625 L 6.71875,32.375 L 6.8125,34.5 L 9.5625,36.9375 C 9.8645501,37.207345 9.9303261,37.654622 9.71875,38 L 8.46875,40 L 10.84375,41.03125 L 13.09375,39.21875 C 13.260233,39.0823 13.472846,39.015159 13.6875,39.03125 L 25.53125,39.90625 C 25.769158,39.930835 25.985219,40.055923 26.125,40.25 L 29.09375,44.21875 L 31.8125,39.78125 C 32.041236,39.389926 32.539705,39.251463 32.9375,39.46875 L 36.96875,41.65625 L 41.1875,41.125 L 40.25,39.1875 C 40.087762,38.864671 40.150741,38.474201 40.40625,38.21875 L 43.75,34.875 L 38.78125,29.28125 C 38.529387,29.019826 38.474521,28.625949 38.645349,28.305645 C 38.816178,27.985341 39.17384,27.811478 39.53125,27.875 L 43.40625,28.40625 C 43.369413,28.35773 43.337977,28.305337 43.3125,28.25 L 40.3125,23.09375 L 36.0625,22.125 C 35.709163,22.034799 35.454745,21.726417 35.433331,21.362378 C 35.411917,20.998338 35.628425,20.662254 35.96875,20.53125 L 39.125,19.46875 L 39.25,17.21875 L 32.3125,11.15625 C 32.19648,11.05643 32.110019,10.926737 32.0625,10.78125 L 29.65625,3.09375 z " /> | ||
503 | + </g> | ||
504 | +</svg> |
public/javascripts/application.js
@@ -683,6 +683,33 @@ function add_comment_reply_form(button, comment_id) { | @@ -683,6 +683,33 @@ function add_comment_reply_form(button, comment_id) { | ||
683 | return f; | 683 | return f; |
684 | } | 684 | } |
685 | 685 | ||
686 | +function remove_comment(button, url, msg) { | ||
687 | + var $ = jQuery; | ||
688 | + var $button = $(button); | ||
689 | + if (msg && !confirm(msg)) { | ||
690 | + $button.removeClass('comment-button-loading'); | ||
691 | + return; | ||
692 | + } | ||
693 | + $button.addClass('comment-button-loading'); | ||
694 | + $.post(url, function(data) { | ||
695 | + if (data.ok) { | ||
696 | + var $comment = $button.closest('.article-comment'); | ||
697 | + var $replies = $comment.find('.comment-replies .article-comment'); | ||
698 | + $comment.slideUp(); | ||
699 | + var comments_removed = 1; | ||
700 | + if ($button.hasClass('remove-children')) { | ||
701 | + comments_removed = 1 + $replies.size(); | ||
702 | + } else { | ||
703 | + $replies.appendTo('.article-comments-list'); | ||
704 | + } | ||
705 | + $('.comment-count').each(function() { | ||
706 | + var count = parseInt($(this).html()); | ||
707 | + $(this).html(count - comments_removed); | ||
708 | + }); | ||
709 | + } | ||
710 | + }); | ||
711 | +} | ||
712 | + | ||
686 | function original_image_dimensions(src) { | 713 | function original_image_dimensions(src) { |
687 | var img = new Image(); | 714 | var img = new Image(); |
688 | img.src = src; | 715 | img.src = src; |
public/stylesheets/application.css
@@ -1069,15 +1069,6 @@ a.comment-picture { | @@ -1069,15 +1069,6 @@ a.comment-picture { | ||
1069 | top: 9px; | 1069 | top: 9px; |
1070 | right: 8px; | 1070 | right: 8px; |
1071 | } | 1071 | } |
1072 | -#content .comment-balloon a.button.icon-delete { | ||
1073 | - border: 0; | ||
1074 | - padding-top: 0; | ||
1075 | - padding-bottom: 0; | ||
1076 | - background-color: transparent; | ||
1077 | -} | ||
1078 | -#content .comments .comment-balloon a.button.icon-delete { | ||
1079 | - display: none; | ||
1080 | -} | ||
1081 | .msie7 .article-comments-list .comment-balloon { | 1072 | .msie7 .article-comments-list .comment-balloon { |
1082 | margin-top: -15px; | 1073 | margin-top: -15px; |
1083 | } | 1074 | } |
@@ -1271,6 +1262,11 @@ a.comment-picture { | @@ -1271,6 +1262,11 @@ a.comment-picture { | ||
1271 | } | 1262 | } |
1272 | /* * * Comment Box * * */ | 1263 | /* * * Comment Box * * */ |
1273 | 1264 | ||
1265 | +.comment-button-loading { | ||
1266 | + padding-left: 20px; | ||
1267 | + background: transparent url(../images/loading-small.gif) no-repeat left center; | ||
1268 | +} | ||
1269 | + | ||
1274 | .post_comment_box { | 1270 | .post_comment_box { |
1275 | text-align: center; | 1271 | text-align: center; |
1276 | padding: 0px 15px 5px 15px; | 1272 | padding: 0px 15px 5px 15px; |
@@ -3854,6 +3850,9 @@ h1#agenda-title { | @@ -3854,6 +3850,9 @@ h1#agenda-title { | ||
3854 | .controller-profile_editor .msie6 a.control-panel-edit-location { | 3850 | .controller-profile_editor .msie6 a.control-panel-edit-location { |
3855 | background-image: url(../images/control-panel/set-geolocation.gif) | 3851 | background-image: url(../images/control-panel/set-geolocation.gif) |
3856 | } | 3852 | } |
3853 | +.controller-profile_editor a.control-panel-manage-spam { | ||
3854 | + background-image: url(../images/control-panel/mail-mark-junk.png) | ||
3855 | +} | ||
3857 | /* ==> public/stylesheets/controller_profile_members.css <== */ | 3856 | /* ==> public/stylesheets/controller_profile_members.css <== */ |
3858 | .controller-profile_members .no-boxes { | 3857 | .controller-profile_members .no-boxes { |
3859 | margin: 30px | 3858 | margin: 30px |
script/install-dependencies/debian-squeeze.sh
1 | # needed to run noosfero | 1 | # needed to run noosfero |
2 | runtime_dependencies=$(sed -e '1,/^Depends:/d; /^Recommends:/,$ d; s/([^)]*)//g; s/,\s*/\n/g' debian/control | grep -v 'memcached\|debconf\|dbconfig-common\|postgresql\|misc:Depends\|adduser\|mail-transport-agent') | 2 | runtime_dependencies=$(sed -e '1,/^Depends:/d; /^Recommends:/,$ d; s/([^)]*)//g; s/,\s*/\n/g' debian/control | grep -v 'memcached\|debconf\|dbconfig-common\|postgresql\|misc:Depends\|adduser\|mail-transport-agent') |
3 | run sudo apt-get -y install $runtime_dependencies | 3 | run sudo apt-get -y install $runtime_dependencies |
4 | +sudo apt-get -y install iceweasel || sudo apt-get -y install firefox | ||
4 | 5 | ||
5 | # needed for development | 6 | # needed for development |
6 | run sudo apt-get -y install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev | 7 | run sudo apt-get -y install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev |
7 | -gem which bundler >/dev/null 2>&1 || run gem install bundler | ||
8 | -which bundle >/dev/null 2>&1 || export PATH="$(ruby -rubygems -e 'puts Gem.bindir'):$PATH" | 8 | +gem which bundler >/dev/null 2>&1 || gem_install bundler |
9 | +setup_rubygems_path | ||
9 | run bundle install | 10 | run bundle install |
script/noosfero-plugins
@@ -21,6 +21,8 @@ disabled_plugins=$(printf "%s\n" $available_plugins $enabled_plugins_dir | sort | @@ -21,6 +21,8 @@ disabled_plugins=$(printf "%s\n" $available_plugins $enabled_plugins_dir | sort | ||
21 | # operation defaults | 21 | # operation defaults |
22 | quiet=false | 22 | quiet=false |
23 | needs_migrate=false | 23 | needs_migrate=false |
24 | +load_paths="$NOOSFERO_DIR/lib:$(echo $NOOSFERO_DIR/vendor/plugins/*/lib | tr ' ' :)" | ||
25 | + | ||
24 | 26 | ||
25 | _list() { | 27 | _list() { |
26 | for plugin in $available_plugins; do | 28 | for plugin in $available_plugins; do |
@@ -72,11 +74,26 @@ _enable(){ | @@ -72,11 +74,26 @@ _enable(){ | ||
72 | if [ -h "$target" ]; then | 74 | if [ -h "$target" ]; then |
73 | _say "$plugin already enabled" | 75 | _say "$plugin already enabled" |
74 | else | 76 | else |
75 | - ln -s "$source" "$target" | ||
76 | - plugins_public_dir="$NOOSFERO_DIR/public/plugins" | ||
77 | - test -d "$target/public/" && ln -s "$target/public" "$plugins_public_dir/$plugin" | ||
78 | - _say "$plugin enabled" | ||
79 | - needs_migrate=true | 77 | + if [ ! -d "$source" ]; then |
78 | + echo "E: $plugin plugin does not exist!" | ||
79 | + return | ||
80 | + fi | ||
81 | + dependencies_ok=true | ||
82 | + dependencies_file="$source/dependencies.rb" | ||
83 | + if [ -e "$dependencies_file" ]; then | ||
84 | + if ! ruby -I$load_paths -e "require '$dependencies_file'"; then | ||
85 | + dependencies_ok=false | ||
86 | + fi | ||
87 | + fi | ||
88 | + if [ "$dependencies_ok" = true ]; then | ||
89 | + ln -s "$source" "$target" | ||
90 | + plugins_public_dir="$NOOSFERO_DIR/public/plugins" | ||
91 | + test -d "$target/public/" && ln -s "$target/public" "$plugins_public_dir/$plugin" | ||
92 | + _say "$plugin enabled" | ||
93 | + needs_migrate=true | ||
94 | + else | ||
95 | + echo "W: failed to load dependencies for $plugin; not enabling" | ||
96 | + fi | ||
80 | fi | 97 | fi |
81 | } | 98 | } |
82 | 99 |
script/production
@@ -34,8 +34,6 @@ do_start() { | @@ -34,8 +34,6 @@ do_start() { | ||
34 | } | 34 | } |
35 | 35 | ||
36 | do_stop() { | 36 | do_stop() { |
37 | - rake -s solr:stop | ||
38 | - | ||
39 | # During Debian upgrades, it is possible that rails is not available (e.g. | 37 | # During Debian upgrades, it is possible that rails is not available (e.g. |
40 | # Lenny -> Squeeze), so the programs below might fail. If they do, we fall | 38 | # Lenny -> Squeeze), so the programs below might fail. If they do, we fall |
41 | # back to stopping the daemons by manually reading their PID files, killing | 39 | # back to stopping the daemons by manually reading their PID files, killing |
@@ -46,6 +44,8 @@ do_stop() { | @@ -46,6 +44,8 @@ do_stop() { | ||
46 | 44 | ||
47 | environments_loop stop || | 45 | environments_loop stop || |
48 | stop_via_pid_file tmp/pids/delayed_job.pid tmp/pids/delayed_job.*.pid tmp/pids/feed-updater.*.pid | 46 | stop_via_pid_file tmp/pids/delayed_job.pid tmp/pids/delayed_job.*.pid tmp/pids/feed-updater.*.pid |
47 | + | ||
48 | + rake -s solr:stop || stop_via_pid_file tmp/pids/solr.*.pid | ||
49 | } | 49 | } |
50 | 50 | ||
51 | stop_via_pid_file() { | 51 | stop_via_pid_file() { |
script/quick-start
@@ -21,6 +21,22 @@ run() { | @@ -21,6 +21,22 @@ run() { | ||
21 | fi | 21 | fi |
22 | } | 22 | } |
23 | 23 | ||
24 | +gem_install() { | ||
25 | + if [ -w "$(ruby -rubygems -e 'puts Gem.dir')" ]; then | ||
26 | + run gem install --no-ri --no-rdoc $@ | ||
27 | + else | ||
28 | + run gem install --user-install --no-ri --no-rdoc $@ | ||
29 | + fi | ||
30 | +} | ||
31 | + | ||
32 | +setup_rubygems_path() { | ||
33 | + local dir="$(ruby -rubygems -e 'puts Gem.user_dir')/bin" | ||
34 | + if [ -d "$dir" ]; then | ||
35 | + export PATH="$dir:$PATH" | ||
36 | + fi | ||
37 | +} | ||
38 | + | ||
39 | + | ||
24 | force_install=false | 40 | force_install=false |
25 | if test "$1" = '--force-install'; then | 41 | if test "$1" = '--force-install'; then |
26 | force_install=true | 42 | force_install=true |
@@ -28,9 +44,15 @@ fi | @@ -28,9 +44,15 @@ fi | ||
28 | if gem which system_timer >/dev/null 2>&1 && which xvfb-run >/dev/null 2>&1 && test "$force_install" = 'false'; then | 44 | if gem which system_timer >/dev/null 2>&1 && which xvfb-run >/dev/null 2>&1 && test "$force_install" = 'false'; then |
29 | say "Assuming dependencies are already installed. Pass --force-install to force their installation" | 45 | say "Assuming dependencies are already installed. Pass --force-install to force their installation" |
30 | else | 46 | else |
31 | - if !which lsb_release >/dev/null 2>&1; then | ||
32 | - complain "E: lsb_release not available! (Try installing the lsb-release package)" | ||
33 | - exit 1 | 47 | + if ! which lsb_release >/dev/null 2>&1; then |
48 | + # special case Debian-based systems; in others people will have to install | ||
49 | + # lsb-release by themselves | ||
50 | + if which apt-get >/dev/null 2>&1; then | ||
51 | + sudo apt-get -y install lsb-release | ||
52 | + else | ||
53 | + complain "E: lsb_release not available! (Try installing the lsb-release package)" | ||
54 | + exit 1 | ||
55 | + fi | ||
34 | fi | 56 | fi |
35 | system=$(echo $(lsb_release -sic) | awk '{print(tolower($1) "-" tolower($2))}') | 57 | system=$(echo $(lsb_release -sic) | awk '{print(tolower($1) "-" tolower($2))}') |
36 | install_script="$(dirname $0)/install-dependencies/${system}.sh" | 58 | install_script="$(dirname $0)/install-dependencies/${system}.sh" |
test/functional/content_viewer_controller_test.rb
@@ -92,7 +92,7 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -92,7 +92,7 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
92 | 92 | ||
93 | login_as 'testuser' | 93 | login_as 'testuser' |
94 | get :view_page, :profile => 'testuser', :page => [ 'test' ] | 94 | get :view_page, :profile => 'testuser', :page => [ 'test' ] |
95 | - assert_tag :tag => 'a', :attributes => { :href => '/testuser/test?remove_comment=' + comment.id.to_s } | 95 | + assert_tag :tag => 'a', :attributes => { :onclick => %r(/testuser/test\?remove_comment=#{comment.id}.quot) } |
96 | end | 96 | end |
97 | 97 | ||
98 | should 'display remove comment button with param view when image' do | 98 | should 'display remove comment button with param view when image' do |
@@ -106,8 +106,9 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -106,8 +106,9 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
106 | 106 | ||
107 | login_as 'testuser' | 107 | login_as 'testuser' |
108 | get :view_page, :profile => 'testuser', :page => [ image.filename ], :view => true | 108 | get :view_page, :profile => 'testuser', :page => [ image.filename ], :view => true |
109 | - assert_tag :tag => 'a', :attributes => { :href => "/testuser/#{image.filename}?remove_comment=" + comment.id.to_s + '&view=true'} | ||
110 | - end | 109 | + assert_tag :tag => 'a', :attributes => { :onclick => %r(/testuser/#{image.filename}\?remove_comment=#{comment.id}.*amp;view=true.quot) } |
110 | +end | ||
111 | + | ||
111 | 112 | ||
112 | should 'not add unneeded params for remove comment button' do | 113 | should 'not add unneeded params for remove comment button' do |
113 | profile = create_user('testuser').person | 114 | profile = create_user('testuser').person |
@@ -117,8 +118,8 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -117,8 +118,8 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
117 | comment.save! | 118 | comment.save! |
118 | 119 | ||
119 | login_as 'testuser' | 120 | login_as 'testuser' |
120 | - get :view_page, :profile => 'testuser', :page => [ 'test' ], :random_param => 'bli' # <<<<<<<<<<<<<<< | ||
121 | - assert_tag :tag => 'a', :attributes => { :href => '/testuser/test?remove_comment=' + comment.id.to_s } | 121 | + get :view_page, :profile => 'testuser', :page => [ 'test' ], :random_param => 'bli' |
122 | + assert_tag :tag => 'a', :attributes => { :onclick => %r(/testuser/test\?remove_comment=#{comment.id.to_s}.quot) } | ||
122 | end | 123 | end |
123 | 124 | ||
124 | should 'be able to remove comment' do | 125 | should 'be able to remove comment' do |
@@ -1374,12 +1375,16 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1374,12 +1375,16 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1374 | assert_not_nil assigns(:comment) | 1375 | assert_not_nil assigns(:comment) |
1375 | end | 1376 | end |
1376 | 1377 | ||
1377 | - should 'store IP address for comments' do | 1378 | + should 'store IP address, user agent and referrer for comments' do |
1378 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | 1379 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') |
1379 | @request.stubs(:remote_ip).returns('33.44.55.66') | 1380 | @request.stubs(:remote_ip).returns('33.44.55.66') |
1381 | + @request.stubs(:referrer).returns('http://example.com') | ||
1382 | + @request.stubs(:user_agent).returns('MyBrowser') | ||
1380 | post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | 1383 | post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' |
1381 | comment = Comment.last | 1384 | comment = Comment.last |
1382 | assert_equal '33.44.55.66', comment.ip_address | 1385 | assert_equal '33.44.55.66', comment.ip_address |
1386 | + assert_equal 'MyBrowser', comment.user_agent | ||
1387 | + assert_equal 'http://example.com', comment.referrer | ||
1383 | end | 1388 | end |
1384 | 1389 | ||
1385 | should 'not save a comment if a plugin rejects it' do | 1390 | should 'not save a comment if a plugin rejects it' do |
@@ -1395,25 +1400,6 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1395,25 +1400,6 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1395 | end | 1400 | end |
1396 | end | 1401 | end |
1397 | 1402 | ||
1398 | - should 'notify plugins after a comment is saved' do | ||
1399 | - class TestNotifyCommentPlugin < Noosfero::Plugin | ||
1400 | - def comment_saved(c) | ||
1401 | - @__saved = c.id | ||
1402 | - @__title = c.title | ||
1403 | - end | ||
1404 | - attr_reader :__title | ||
1405 | - attr_reader :__saved | ||
1406 | - end | ||
1407 | - plugin = TestNotifyCommentPlugin.new | ||
1408 | - Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([plugin]) | ||
1409 | - page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') | ||
1410 | - post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'the title of the comment', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' | ||
1411 | - | ||
1412 | - assert_equal 'the title of the comment', plugin.__title | ||
1413 | - assert plugin.__saved | ||
1414 | - | ||
1415 | - end | ||
1416 | - | ||
1417 | should 'remove email from article followers when unfollow' do | 1403 | should 'remove email from article followers when unfollow' do |
1418 | profile = create_user('testuser').person | 1404 | profile = create_user('testuser').person |
1419 | follower_email = 'john@doe.br' | 1405 | follower_email = 'john@doe.br' |
@@ -1426,4 +1412,24 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1426,4 +1412,24 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1426 | assert_not_includes Article.find(article.id).followers, follower_email | 1412 | assert_not_includes Article.find(article.id).followers, follower_email |
1427 | end | 1413 | end |
1428 | 1414 | ||
1415 | + should 'not display comments marked as spam' do | ||
1416 | + article = fast_create(Article, :profile_id => profile.id) | ||
1417 | + ham = fast_create(Comment, :source_id => article.id, :source_type => 'Article') | ||
1418 | + spam = fast_create(Comment, :source_id => article.id, :source_type => 'Article', :spam => true) | ||
1419 | + | ||
1420 | + get 'view_page', :profile => profile.identifier, :page => article.path.split('/') | ||
1421 | + assert_equal 1, assigns(:comments_count) | ||
1422 | + end | ||
1423 | + | ||
1424 | + should 'be able to mark comments as spam' do | ||
1425 | + login_as profile.identifier | ||
1426 | + article = fast_create(Article, :profile_id => profile.id) | ||
1427 | + spam = fast_create(Comment, :name => 'foo', :email => 'foo@example.com', :source_id => article.id, :source_type => 'Article') | ||
1428 | + | ||
1429 | + post 'view_page', :profile => profile.identifier, :page => article.path.split('/'), :mark_comment_as_spam => spam.id | ||
1430 | + | ||
1431 | + spam.reload | ||
1432 | + assert spam.spam? | ||
1433 | + end | ||
1434 | + | ||
1429 | end | 1435 | end |
@@ -0,0 +1,41 @@ | @@ -0,0 +1,41 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class SpamControllerTest < ActionController::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @profile = create_user.person | ||
7 | + @article = fast_create(TextileArticle, :profile_id => @profile.id) | ||
8 | + @spam = fast_create(Comment, :source_id => @article.id, :spam => true, :name => 'foo', :email => 'foo@example.com') | ||
9 | + | ||
10 | + login_as @profile.identifier | ||
11 | + end | ||
12 | + | ||
13 | + test "should only list spammy comments" do | ||
14 | + ham = fast_create(Comment, :source_id => @article.id) | ||
15 | + | ||
16 | + get :index, :profile => @profile.identifier | ||
17 | + | ||
18 | + assert_equivalent [@spam], assigns(:spam) | ||
19 | + end | ||
20 | + | ||
21 | + test "should mark comments as ham" do | ||
22 | + post :index, :profile => @profile.identifier, :mark_comment_as_ham => @spam.id | ||
23 | + | ||
24 | + @spam.reload | ||
25 | + assert @spam.ham? | ||
26 | + end | ||
27 | + | ||
28 | + test "should remove comments" do | ||
29 | + post :index, :profile => @profile.identifier, :remove_comment => @spam.id | ||
30 | + | ||
31 | + assert !Comment.exists?(@spam.id) | ||
32 | + end | ||
33 | + | ||
34 | + should 'properly render spam that have replies' do | ||
35 | + reply_spam = fast_create(Comment, :source_id => @article_id, :reply_of_id => @spam.id) | ||
36 | + | ||
37 | + get :index, :profile => @profile.identifier | ||
38 | + assert_response :success | ||
39 | + end | ||
40 | + | ||
41 | +end |
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class CommentHandlerTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + should 'receive comment id' do | ||
6 | + handler = CommentHandler.new(99) | ||
7 | + assert_equal 99, handler.comment_id | ||
8 | + end | ||
9 | + | ||
10 | + should 'not crash with unexisting comment' do | ||
11 | + handler = CommentHandler.new(-1) | ||
12 | + handler.perform | ||
13 | + end | ||
14 | + | ||
15 | + should 'call Comment#whatever_method' do | ||
16 | + handler = CommentHandler.new(-1, :whatever_method) | ||
17 | + comment = Comment.new | ||
18 | + Comment.stubs(:find).with(-1).returns(comment) | ||
19 | + comment.expects(:whatever_method) | ||
20 | + | ||
21 | + handler.perform | ||
22 | + end | ||
23 | + | ||
24 | +end |
test/unit/comment_notifier_test.rb
@@ -14,24 +14,24 @@ class CommentNotifierTest < ActiveSupport::TestCase | @@ -14,24 +14,24 @@ class CommentNotifierTest < ActiveSupport::TestCase | ||
14 | 14 | ||
15 | should 'deliver mail after make an article comment' do | 15 | should 'deliver mail after make an article comment' do |
16 | assert_difference ActionMailer::Base.deliveries, :size do | 16 | assert_difference ActionMailer::Base.deliveries, :size do |
17 | - Comment.create(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article ) | 17 | + create_comment_and_notify(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article ) |
18 | end | 18 | end |
19 | end | 19 | end |
20 | 20 | ||
21 | should 'deliver mail to owner of article' do | 21 | should 'deliver mail to owner of article' do |
22 | - Comment.create(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article ) | 22 | + create_comment_and_notify(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article ) |
23 | sent = ActionMailer::Base.deliveries.first | 23 | sent = ActionMailer::Base.deliveries.first |
24 | assert_equal [@profile.email], sent.to | 24 | assert_equal [@profile.email], sent.to |
25 | end | 25 | end |
26 | 26 | ||
27 | should 'display author name in delivered mail' do | 27 | should 'display author name in delivered mail' do |
28 | - Comment.create(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article) | 28 | + create_comment_and_notify(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article) |
29 | sent = ActionMailer::Base.deliveries.first | 29 | sent = ActionMailer::Base.deliveries.first |
30 | assert_match /user_comment_test/, sent.body | 30 | assert_match /user_comment_test/, sent.body |
31 | end | 31 | end |
32 | 32 | ||
33 | should 'display unauthenticated author name and email in delivered mail' do | 33 | should 'display unauthenticated author name and email in delivered mail' do |
34 | - Comment.create(:name => 'flatline', :email => 'flatline@invalid.com', :title => 'test comment', :body => 'you suck!', :source => @article ) | 34 | + create_comment_and_notify(:name => 'flatline', :email => 'flatline@invalid.com', :title => 'test comment', :body => 'you suck!', :source => @article ) |
35 | sent = ActionMailer::Base.deliveries.first | 35 | sent = ActionMailer::Base.deliveries.first |
36 | assert_match /flatline/, sent.body | 36 | assert_match /flatline/, sent.body |
37 | assert_match /flatline@invalid.com/, sent.body | 37 | assert_match /flatline@invalid.com/, sent.body |
@@ -40,18 +40,18 @@ class CommentNotifierTest < ActiveSupport::TestCase | @@ -40,18 +40,18 @@ class CommentNotifierTest < ActiveSupport::TestCase | ||
40 | should 'not deliver mail if notify comments is false' do | 40 | should 'not deliver mail if notify comments is false' do |
41 | @article.update_attribute(:notify_comments, false) | 41 | @article.update_attribute(:notify_comments, false) |
42 | assert_no_difference ActionMailer::Base.deliveries, :size do | 42 | assert_no_difference ActionMailer::Base.deliveries, :size do |
43 | - @article.comments << Comment.new(:author => @profile, :title => 'test comment', :body => 'you suck!') | 43 | + create_comment_and_notify(:author => @profile, :title => 'test comment', :body => 'you suck!', :source => @article) |
44 | end | 44 | end |
45 | end | 45 | end |
46 | 46 | ||
47 | should 'include comment title in the e-mail' do | 47 | should 'include comment title in the e-mail' do |
48 | - Comment.create(:author => @profile, :title => 'comment title', :body => 'comment body', :source => @article) | 48 | + create_comment_and_notify(:author => @profile, :title => 'comment title', :body => 'comment body', :source => @article) |
49 | sent = ActionMailer::Base.deliveries.first | 49 | sent = ActionMailer::Base.deliveries.first |
50 | assert_match /comment title/, sent.body | 50 | assert_match /comment title/, sent.body |
51 | end | 51 | end |
52 | 52 | ||
53 | should 'include comment text in the e-mail' do | 53 | should 'include comment text in the e-mail' do |
54 | - Comment.create(:author => @profile, :title => 'comment title', :body => 'comment body', :source => @article) | 54 | + create_comment_and_notify(:author => @profile, :title => 'comment title', :body => 'comment body', :source => @article) |
55 | sent = ActionMailer::Base.deliveries.first | 55 | sent = ActionMailer::Base.deliveries.first |
56 | assert_match /comment body/, sent.body | 56 | assert_match /comment body/, sent.body |
57 | end | 57 | end |
@@ -61,7 +61,7 @@ class CommentNotifierTest < ActiveSupport::TestCase | @@ -61,7 +61,7 @@ class CommentNotifierTest < ActiveSupport::TestCase | ||
61 | assert_equal [], community.notification_emails | 61 | assert_equal [], community.notification_emails |
62 | article = fast_create(Article, :name => 'Article test', :profile_id => community.id, :notify_comments => true) | 62 | article = fast_create(Article, :name => 'Article test', :profile_id => community.id, :notify_comments => true) |
63 | assert_no_difference ActionMailer::Base.deliveries, :size do | 63 | assert_no_difference ActionMailer::Base.deliveries, :size do |
64 | - article.comments << Comment.new(:author => @profile, :title => 'test comment', :body => 'there is no addresses to send notification') | 64 | + create_comment_and_notify(:author => @profile, :title => 'test comment', :body => 'there is no addresses to send notification', :source => article) |
65 | end | 65 | end |
66 | end | 66 | end |
67 | 67 | ||
@@ -70,24 +70,29 @@ class CommentNotifierTest < ActiveSupport::TestCase | @@ -70,24 +70,29 @@ class CommentNotifierTest < ActiveSupport::TestCase | ||
70 | follower = create_user('follower').person | 70 | follower = create_user('follower').person |
71 | @article.followers += [follower.email] | 71 | @article.followers += [follower.email] |
72 | @article.save! | 72 | @article.save! |
73 | - @article.comments << Comment.new(:source => @article, :author => author, :title => 'comment title', :body => 'comment body') | 73 | + create_comment_and_notify(:source => @article, :author => author, :title => 'comment title', :body => 'comment body') |
74 | assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email | 74 | assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email |
75 | end | 75 | end |
76 | 76 | ||
77 | should "not deliver follower's mail about new comment to comment's author" do | 77 | should "not deliver follower's mail about new comment to comment's author" do |
78 | follower = create_user('follower').person | 78 | follower = create_user('follower').person |
79 | - @article.comments << Comment.new(:source => @article, :author => follower, :title => 'comment title', :body => 'comment body') | 79 | + create_comment_and_notify(:source => @article, :author => follower, :title => 'comment title', :body => 'comment body') |
80 | assert_not_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email | 80 | assert_not_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email |
81 | end | 81 | end |
82 | 82 | ||
83 | private | 83 | private |
84 | 84 | ||
85 | - def read_fixture(action) | ||
86 | - IO.readlines("#{FIXTURES_PATH}/mail_sender/#{action}") | ||
87 | - end | 85 | + def create_comment_and_notify(args) |
86 | + Comment.create!(args) | ||
87 | + process_delayed_job_queue | ||
88 | + end | ||
88 | 89 | ||
89 | - def encode(subject) | ||
90 | - quoted_printable(subject, CHARSET) | ||
91 | - end | 90 | + def read_fixture(action) |
91 | + IO.readlines("#{FIXTURES_PATH}/mail_sender/#{action}") | ||
92 | + end | ||
93 | + | ||
94 | + def encode(subject) | ||
95 | + quoted_printable(subject, CHARSET) | ||
96 | + end | ||
92 | 97 | ||
93 | end | 98 | end |
test/unit/comment_test.rb
@@ -398,6 +398,9 @@ class CommentTest < ActiveSupport::TestCase | @@ -398,6 +398,9 @@ class CommentTest < ActiveSupport::TestCase | ||
398 | end | 398 | end |
399 | 399 | ||
400 | should 'update article activity when add a comment' do | 400 | should 'update article activity when add a comment' do |
401 | + now = Time.now | ||
402 | + Time.stubs(:now).returns(now) | ||
403 | + | ||
401 | profile = create_user('testuser').person | 404 | profile = create_user('testuser').person |
402 | article = create(TinyMceArticle, :profile => profile) | 405 | article = create(TinyMceArticle, :profile => profile) |
403 | 406 | ||
@@ -422,4 +425,142 @@ class CommentTest < ActiveSupport::TestCase | @@ -422,4 +425,142 @@ class CommentTest < ActiveSupport::TestCase | ||
422 | assert_not_nil article.activity | 425 | assert_not_nil article.activity |
423 | end | 426 | end |
424 | 427 | ||
428 | + should 'be able to mark comments as spam/ham/unknown' do | ||
429 | + c = Comment.new | ||
430 | + c.spam = true | ||
431 | + assert c.spam? | ||
432 | + assert !c.ham? | ||
433 | + | ||
434 | + c.spam = false | ||
435 | + assert c.ham? | ||
436 | + assert !c.spam? | ||
437 | + | ||
438 | + c.spam = nil | ||
439 | + assert !c.spam? | ||
440 | + assert !c.ham? | ||
441 | + end | ||
442 | + | ||
443 | + should 'be able to select non-spam comments' do | ||
444 | + c1 = fast_create(Comment) | ||
445 | + c2 = fast_create(Comment, :spam => false) | ||
446 | + c3 = fast_create(Comment, :spam => true) | ||
447 | + | ||
448 | + assert_equivalent [c1,c2], Comment.without_spam | ||
449 | + end | ||
450 | + | ||
451 | + should 'be able to mark as spam atomically' do | ||
452 | + c1 = create_comment | ||
453 | + c1.spam! | ||
454 | + c1.reload | ||
455 | + assert c1.spam? | ||
456 | + end | ||
457 | + | ||
458 | + should 'be able to select spammy comments' do | ||
459 | + c1 = fast_create(Comment) | ||
460 | + c2 = fast_create(Comment, :spam => false) | ||
461 | + c3 = fast_create(Comment, :spam => true) | ||
462 | + | ||
463 | + assert_equivalent [c3], Comment.spam | ||
464 | + end | ||
465 | + | ||
466 | + should 'be able to mark as ham atomically' do | ||
467 | + c1 = create_comment | ||
468 | + c1.ham! | ||
469 | + c1.reload | ||
470 | + assert c1.ham? | ||
471 | + end | ||
472 | + | ||
473 | + should 'notify by email' do | ||
474 | + c1 = create_comment | ||
475 | + c1.expects(:notify_by_mail) | ||
476 | + c1.verify_and_notify | ||
477 | + end | ||
478 | + | ||
479 | + should 'not notify by email when comment is spam' do | ||
480 | + c1 = create_comment(:spam => true) | ||
481 | + c1.expects(:notify_by_mail).never | ||
482 | + c1.verify_and_notify | ||
483 | + end | ||
484 | + | ||
485 | + class EverythingIsSpam < Noosfero::Plugin | ||
486 | + def check_comment_for_spam(comment) | ||
487 | + comment.spam! | ||
488 | + end | ||
489 | + end | ||
490 | + | ||
491 | + | ||
492 | + should 'delegate spam detection to plugins' do | ||
493 | + Environment.default.enable_plugin(EverythingIsSpam) | ||
494 | + | ||
495 | + c1 = create_comment | ||
496 | + | ||
497 | + c1.expects(:notify_by_mail).never | ||
498 | + | ||
499 | + c1.verify_and_notify | ||
500 | + end | ||
501 | + | ||
502 | + class SpamNotification < Noosfero::Plugin | ||
503 | + class << self | ||
504 | + attr_accessor :marked_as_spam | ||
505 | + attr_accessor :marked_as_ham | ||
506 | + end | ||
507 | + | ||
508 | + def comment_marked_as_spam(c) | ||
509 | + self.class.marked_as_spam = c | ||
510 | + end | ||
511 | + | ||
512 | + def comment_marked_as_ham(c) | ||
513 | + self.class.marked_as_ham = c | ||
514 | + end | ||
515 | + end | ||
516 | + | ||
517 | + should 'notify plugins of comments being marked as spam' do | ||
518 | + Environment.default.enable_plugin(SpamNotification) | ||
519 | + | ||
520 | + c = create_comment | ||
521 | + | ||
522 | + c.spam! | ||
523 | + process_delayed_job_queue | ||
524 | + | ||
525 | + assert_equal c, SpamNotification.marked_as_spam | ||
526 | + end | ||
527 | + | ||
528 | + should 'notify plugins of comments being marked as ham' do | ||
529 | + Environment.default.enable_plugin(SpamNotification) | ||
530 | + | ||
531 | + c = create_comment | ||
532 | + | ||
533 | + c.ham! | ||
534 | + process_delayed_job_queue | ||
535 | + | ||
536 | + assert_equal c, SpamNotification.marked_as_ham | ||
537 | + end | ||
538 | + | ||
539 | + should 'ignore spam when constructing threads' do | ||
540 | + original = create_comment | ||
541 | + response = create_comment(:reply_of_id => original.id) | ||
542 | + original.spam! | ||
543 | + | ||
544 | + assert_equivalent [response], Comment.without_spam.as_thread | ||
545 | + end | ||
546 | + | ||
547 | + | ||
548 | + should 'store User-Agent' do | ||
549 | + c = Comment.new(:user_agent => 'foo') | ||
550 | + assert_equal 'foo', c.user_agent | ||
551 | + end | ||
552 | + | ||
553 | + should 'store referrer' do | ||
554 | + c = Comment.new(:referrer => 'bar') | ||
555 | + assert_equal 'bar', c.referrer | ||
556 | + end | ||
557 | + | ||
558 | + private | ||
559 | + | ||
560 | + def create_comment(args = {}) | ||
561 | + owner = create_user('testuser').person | ||
562 | + article = create(TextileArticle, :profile_id => owner.id) | ||
563 | + create(Comment, { :name => 'foo', :email => 'foo@example.com', :source => article }.merge(args)) | ||
564 | + end | ||
565 | + | ||
425 | end | 566 | end |
test/unit/content_viewer_helper_test.rb
@@ -61,9 +61,9 @@ class ContentViewerHelperTest < ActiveSupport::TestCase | @@ -61,9 +61,9 @@ class ContentViewerHelperTest < ActiveSupport::TestCase | ||
61 | end | 61 | end |
62 | 62 | ||
63 | should 'count total of comments from post' do | 63 | should 'count total of comments from post' do |
64 | - article = TextileArticle.new(:name => 'first post for test', :body => 'first post for test', :profile => profile) | 64 | + article = fast_create(TextileArticle) |
65 | article.stubs(:url).returns({}) | 65 | article.stubs(:url).returns({}) |
66 | - article.stubs(:comments).returns([Comment.new(:author => profile, :title => 'test', :body => 'test')]) | 66 | + article.comments.create!(:author => profile, :title => 'test', :body => 'test') |
67 | result = link_to_comments(article) | 67 | result = link_to_comments(article) |
68 | assert_match /One comment/, result | 68 | assert_match /One comment/, result |
69 | end | 69 | end |
test/unit/person_test.rb
@@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' | @@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' | ||
3 | class PersonTest < ActiveSupport::TestCase | 3 | class PersonTest < ActiveSupport::TestCase |
4 | fixtures :profiles, :users, :environments | 4 | fixtures :profiles, :users, :environments |
5 | 5 | ||
6 | - def teardown | ||
7 | - Thread.current[:enabled_plugins] = nil | ||
8 | - end | ||
9 | - | ||
10 | def test_person_must_come_form_the_cration_of_an_user | 6 | def test_person_must_come_form_the_cration_of_an_user |
11 | p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john') | 7 | p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john') |
12 | assert !p.valid? | 8 | assert !p.valid? |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +require File.dirname(__FILE__) + '/../test_helper' | ||
2 | + | ||
3 | +class PluginHotSpotTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + class Client | ||
6 | + include Noosfero::Plugin::HotSpot | ||
7 | + end | ||
8 | + | ||
9 | + def setup | ||
10 | + @client = Client.new | ||
11 | + @client.stubs(:environment).returns(Environment.new) | ||
12 | + end | ||
13 | + | ||
14 | + should 'instantiate only once' do | ||
15 | + assert_same @client.plugins, @client.plugins | ||
16 | + end | ||
17 | + | ||
18 | +end |
test/unit/plugin_manager_test.rb
@@ -8,10 +8,16 @@ class PluginManagerTest < ActiveSupport::TestCase | @@ -8,10 +8,16 @@ class PluginManagerTest < ActiveSupport::TestCase | ||
8 | @controller.stubs(:profile).returns() | 8 | @controller.stubs(:profile).returns() |
9 | @controller.stubs(:request).returns() | 9 | @controller.stubs(:request).returns() |
10 | @controller.stubs(:response).returns() | 10 | @controller.stubs(:response).returns() |
11 | - @controller.stubs(:environment).returns(@environment) | ||
12 | @controller.stubs(:params).returns() | 11 | @controller.stubs(:params).returns() |
12 | + @manager = Noosfero::Plugin::Manager.new(@environment, @controller) | ||
13 | end | 13 | end |
14 | attr_reader :environment | 14 | attr_reader :environment |
15 | + attr_reader :manager | ||
16 | + | ||
17 | + should 'give access to environment and context' do | ||
18 | + assert_same @environment, @manager.environment | ||
19 | + assert_same @controller, @manager.context | ||
20 | + end | ||
15 | 21 | ||
16 | should 'return the intersection between environment\'s enabled plugins and system available plugins' do | 22 | should 'return the intersection between environment\'s enabled plugins and system available plugins' do |
17 | class Plugin1 < Noosfero::Plugin; end; | 23 | class Plugin1 < Noosfero::Plugin; end; |
@@ -20,7 +26,6 @@ class PluginManagerTest < ActiveSupport::TestCase | @@ -20,7 +26,6 @@ class PluginManagerTest < ActiveSupport::TestCase | ||
20 | class Plugin4 < Noosfero::Plugin; end; | 26 | class Plugin4 < Noosfero::Plugin; end; |
21 | environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) | 27 | environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) |
22 | Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) | 28 | Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) |
23 | - manager = Noosfero::Plugin::Manager.new(@controller) | ||
24 | plugins = manager.enabled_plugins.map { |instance| instance.class.to_s } | 29 | plugins = manager.enabled_plugins.map { |instance| instance.class.to_s } |
25 | assert_equal [Plugin1.to_s, Plugin4.to_s], plugins | 30 | assert_equal [Plugin1.to_s, Plugin4.to_s], plugins |
26 | end | 31 | end |
@@ -49,7 +54,6 @@ class PluginManagerTest < ActiveSupport::TestCase | @@ -49,7 +54,6 @@ class PluginManagerTest < ActiveSupport::TestCase | ||
49 | 54 | ||
50 | p1 = Plugin1.new | 55 | p1 = Plugin1.new |
51 | p2 = Plugin2.new | 56 | p2 = Plugin2.new |
52 | - manager = Noosfero::Plugin::Manager.new(@controller) | ||
53 | 57 | ||
54 | assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event) | 58 | assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event) |
55 | end | 59 | end |
test/unit/profile_test.rb
@@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' | @@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' | ||
3 | class ProfileTest < ActiveSupport::TestCase | 3 | class ProfileTest < ActiveSupport::TestCase |
4 | fixtures :profiles, :environments, :users, :roles, :domains | 4 | fixtures :profiles, :environments, :users, :roles, :domains |
5 | 5 | ||
6 | - def teardown | ||
7 | - Thread.current[:enabled_plugins] = nil | ||
8 | - end | ||
9 | - | ||
10 | def test_identifier_validation | 6 | def test_identifier_validation |
11 | p = Profile.new | 7 | p = Profile.new |
12 | p.valid? | 8 | p.valid? |
@@ -1834,16 +1830,6 @@ class ProfileTest < ActiveSupport::TestCase | @@ -1834,16 +1830,6 @@ class ProfileTest < ActiveSupport::TestCase | ||
1834 | end | 1830 | end |
1835 | 1831 | ||
1836 | should 'merge members of plugins to original members' do | 1832 | should 'merge members of plugins to original members' do |
1837 | - original_community = fast_create(Community) | ||
1838 | - community1 = fast_create(Community, :identifier => 'community1') | ||
1839 | - community2 = fast_create(Community, :identifier => 'community2') | ||
1840 | - original_member = fast_create(Person) | ||
1841 | - plugin1_member = fast_create(Person) | ||
1842 | - plugin2_member = fast_create(Person) | ||
1843 | - original_community.add_member(original_member) | ||
1844 | - community1.add_member(plugin1_member) | ||
1845 | - community2.add_member(plugin2_member) | ||
1846 | - | ||
1847 | class Plugin1 < Noosfero::Plugin | 1833 | class Plugin1 < Noosfero::Plugin |
1848 | def organization_members(profile) | 1834 | def organization_members(profile) |
1849 | Person.members_of(Community.find_by_identifier('community1')) | 1835 | Person.members_of(Community.find_by_identifier('community1')) |
@@ -1855,8 +1841,18 @@ class ProfileTest < ActiveSupport::TestCase | @@ -1855,8 +1841,18 @@ class ProfileTest < ActiveSupport::TestCase | ||
1855 | Person.members_of(Community.find_by_identifier('community2')) | 1841 | Person.members_of(Community.find_by_identifier('community2')) |
1856 | end | 1842 | end |
1857 | end | 1843 | end |
1844 | + Environment.default.enable_plugin(Plugin1) | ||
1845 | + Environment.default.enable_plugin(Plugin2) | ||
1858 | 1846 | ||
1859 | - original_community.stubs(:enabled_plugins).returns([Plugin1.new, Plugin2.new]) | 1847 | + original_community = fast_create(Community) |
1848 | + community1 = fast_create(Community, :identifier => 'community1') | ||
1849 | + community2 = fast_create(Community, :identifier => 'community2') | ||
1850 | + original_member = fast_create(Person) | ||
1851 | + plugin1_member = fast_create(Person) | ||
1852 | + plugin2_member = fast_create(Person) | ||
1853 | + original_community.add_member(original_member) | ||
1854 | + community1.add_member(plugin1_member) | ||
1855 | + community2.add_member(plugin2_member) | ||
1860 | 1856 | ||
1861 | assert_includes original_community.members, original_member | 1857 | assert_includes original_community.members, original_member |
1862 | assert_includes original_community.members, plugin1_member | 1858 | assert_includes original_community.members, plugin1_member |
vendor/plugins/acts_as_solr_reloaded/lib/tasks/solr.rake
@@ -20,7 +20,16 @@ namespace :solr do | @@ -20,7 +20,16 @@ namespace :solr do | ||
20 | 20 | ||
21 | tmpdir = [ '/var/tmp', '/tmp' ].find { |d| File.exists?(d) } | 21 | tmpdir = [ '/var/tmp', '/tmp' ].find { |d| File.exists?(d) } |
22 | Dir.chdir tmpdir do | 22 | Dir.chdir tmpdir do |
23 | - sh "wget -c #{SOLR_URL}" | 23 | + skip_download = false |
24 | + if File.exists?(SOLR_FILENAME) | ||
25 | + sh "echo \"#{SOLR_MD5SUM} #{SOLR_FILENAME}\" | md5sum -c -" do |ok, res| | ||
26 | + skip_download = ok | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + unless skip_download | ||
31 | + sh "wget -c #{SOLR_URL}" | ||
32 | + end | ||
24 | 33 | ||
25 | sh "echo \"#{SOLR_MD5SUM} #{SOLR_FILENAME}\" | md5sum -c -" do |ok, res| | 34 | sh "echo \"#{SOLR_MD5SUM} #{SOLR_FILENAME}\" | md5sum -c -" do |ok, res| |
26 | abort "MD5SUM do not match" if !ok | 35 | abort "MD5SUM do not match" if !ok |
vendor/plugins/acts_as_solr_reloaded/test/db/connections/mysql/connection.rb
vendor/plugins/acts_as_solr_reloaded/test/db/connections/sqlite/connection.rb
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +* Clean up gemspec and load paths [Steven Harman] | ||
2 | +* Add Akismet is_test param [Steven Harman] | ||
3 | +* Add Akismet user_role attribute [Steven Harman] | ||
4 | += 1.2.1 | ||
5 | +* Fix deprecated usage of HTTPResponse for Ruby 1.9.3 [Leonid Shevtsov] | ||
6 | += 1.2.0 | ||
7 | +* Rakismet attribute mappings are now inheritable | ||
8 | += 1.1.2 | ||
9 | +* Explicitly load version | ||
10 | += 1.1.1 | ||
11 | +* Fix SafeBuffer error under Rails 3.0.8 and 3.0.9 [Brandon Ferguson] | ||
12 | +* Readme cleanup [Zeke Sikelianos] | ||
13 | +* Drop Jeweler in favor of Bundler's gem tasks | ||
14 | += 1.1.0 | ||
15 | +* Add HTTP Proxy support [Francisco Trindade] | ||
16 | += 1.0.1 | ||
17 | +* Fix hash access for Ruby 1.9 [Alex Crichton] | ||
18 | += 1.0.0 | ||
19 | +* Update for Rails 3 | ||
20 | +* Remove filters and replace with middleware | ||
21 | +* Remove initializers and replace with Railtie | ||
22 | += 0.4.0 | ||
23 | +* Rakismet is no longer injected into ActiveRecord or ActionController | ||
24 | +* API changes to support newly decoupled modules | ||
25 | +* Use Jeweler to manage gemspec | ||
26 | += 0.3.6 | ||
27 | +* Allow attributes to fall through to methods or AR attributes | ||
28 | += 0.3.5 | ||
29 | +* Added gemspec and rails/init.rb so rakismet can work as a gem [Michael Air] | ||
30 | +* Added generator template and manifest [Michael Air] | ||
31 | += 0.3.0 | ||
32 | +* Abstract out Rakismet version string | ||
33 | +* Set default Akismet Host | ||
34 | +* Abstract out the Akismet host [Mike Burns] | ||
35 | +* Started keeping a changelog :P |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +Copyright (c) 2008 Josh French | ||
2 | + | ||
3 | +Permission is hereby granted, free of charge, to any person obtaining | ||
4 | +a copy of this software and associated documentation files (the | ||
5 | +"Software"), to deal in the Software without restriction, including | ||
6 | +without limitation the rights to use, copy, modify, merge, publish, | ||
7 | +distribute, sublicense, and/or sell copies of the Software, and to | ||
8 | +permit persons to whom the Software is furnished to do so, subject to | ||
9 | +the following conditions: | ||
10 | + | ||
11 | +The above copyright notice and this permission notice shall be | ||
12 | +included in all copies or substantial portions of the Software. | ||
13 | + | ||
14 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
15 | +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
16 | +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
17 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
18 | +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
19 | +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
20 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
@@ -0,0 +1,229 @@ | @@ -0,0 +1,229 @@ | ||
1 | +Rakismet | ||
2 | +======== | ||
3 | + | ||
4 | +**Akismet** (<http://akismet.com/>) is a collaborative spam filtering service. | ||
5 | +**Rakismet** is easy Akismet integration with Rails and rack apps. TypePad's | ||
6 | +AntiSpam service and generic Akismet endpoints are supported. | ||
7 | + | ||
8 | +Compatibility | ||
9 | +============= | ||
10 | + | ||
11 | +**Rakismet >= 1.0.0** work with Rails 3 and other Rack-based frameworks. | ||
12 | + | ||
13 | +**Rakismet <= 0.4.2** is compatible with Rails 2. | ||
14 | + | ||
15 | +Getting Started | ||
16 | +=============== | ||
17 | + | ||
18 | +Once you've installed the Rakismet gem and added it to your application's Gemfile, | ||
19 | +you'll need an API key. Head on over to http://akismet.com/signup/ and sign up | ||
20 | +for a new username. | ||
21 | + | ||
22 | +Configure the Rakismet key and the URL of your application by setting the following | ||
23 | +in application.rb: | ||
24 | + | ||
25 | +```ruby | ||
26 | +config.rakismet.key = 'your wordpress key' | ||
27 | +config.rakismet.url = 'http://yourdomain.com/' | ||
28 | +``` | ||
29 | + | ||
30 | +or an initializer, for example `config/initializers/rakismet.rb`: | ||
31 | + | ||
32 | +```ruby | ||
33 | +YourApp::Application.config.rakismet.key = 'your wordpress key' | ||
34 | +YourApp::Application.config.rakismet.url = 'http://yourdomain.com/' | ||
35 | +``` | ||
36 | + | ||
37 | +If you wish to use another Akismet-compatible API provider such as TypePad's | ||
38 | +antispam service, you'll also need to set `config.rakismet.host` to your service | ||
39 | +provider's endpoint. | ||
40 | + | ||
41 | +If you want to use a proxy to access akismet (i.e. your application is behind a | ||
42 | +firewall), set the proxy_host and proxy_port option. | ||
43 | + | ||
44 | +```ruby | ||
45 | +config.rakismet.proxy_host = 'http://yourdomain.com/' | ||
46 | +config.rakismet.proxy_port = '8080' | ||
47 | +``` | ||
48 | + | ||
49 | +Checking For Spam | ||
50 | +----------------- | ||
51 | + | ||
52 | +First, introduce Rakismet to your model: | ||
53 | + | ||
54 | +```ruby | ||
55 | +class Comment | ||
56 | + include Rakismet::Model | ||
57 | +end | ||
58 | +``` | ||
59 | + | ||
60 | +With Rakismet mixed in to your model, you'll get three instance methods for interacting with | ||
61 | +Akismet: | ||
62 | + | ||
63 | + * `spam?` submits the comment to Akismet and returns true if Akismet thinks the comment is spam, false if not. | ||
64 | + * `ham!` resubmits a valid comment that Akismet erroneously marked as spam (marks it as a false positive.) | ||
65 | + * `spam!` resubmits a spammy comment that Akismet missed (marks it as a false negative.) | ||
66 | + | ||
67 | +The `ham!` and `spam!` methods will change the value of `spam?` but their | ||
68 | +primary purpose is to send feedback to Akismet. The service works best when you | ||
69 | +help correct the rare mistake; please consider using these methods if you're | ||
70 | +moderating comments or otherwise reviewing the Akismet responses. | ||
71 | + | ||
72 | +Configuring Your Model | ||
73 | +---------------------- | ||
74 | + | ||
75 | +Rakismet sends the following information to the spam-hungry robots at Akismet: | ||
76 | + | ||
77 | + author : name submitted with the comment | ||
78 | + author_url : URL submitted with the comment | ||
79 | + author_email : email submitted with the comment | ||
80 | + comment_type : Defaults to comment but you can set it to trackback, pingback, or something more appropriate | ||
81 | + content : the content submitted | ||
82 | + permalink : the permanent URL for the entry the comment belongs to | ||
83 | + user_ip : IP address used to submit this comment | ||
84 | + user_agent : user agent string | ||
85 | + referrer : referring URL (note the spelling) | ||
86 | + | ||
87 | +By default, Rakismet just looks for attributes or methods on your class that | ||
88 | +match these names. You don't have to have accessors that match these exactly, | ||
89 | +however. If yours differ, just tell Rakismet what to call them: | ||
90 | + | ||
91 | +```ruby | ||
92 | +class Comment | ||
93 | + include Rakismet::Model | ||
94 | + attr_accessor :commenter_name, :commenter_email | ||
95 | + rakismet_attrs :author => :commenter_name, :author_email => :commenter_email | ||
96 | +end | ||
97 | +``` | ||
98 | + | ||
99 | +Or you can pass in a proc, to access associations: | ||
100 | + | ||
101 | +```ruby | ||
102 | +class Comment < ActiveRecord::Base | ||
103 | + include Rakismet::Model | ||
104 | + belongs_to :author | ||
105 | + rakismet_attrs :author => proc { author.name }, | ||
106 | + :author_email => proc { author.email } | ||
107 | +end | ||
108 | +``` | ||
109 | + | ||
110 | +You can even hard-code specific fields: | ||
111 | + | ||
112 | +```ruby | ||
113 | +class Trackback | ||
114 | + include Rakismet::Model | ||
115 | + rakismet_attrs :comment_type => "trackback" | ||
116 | +end | ||
117 | +``` | ||
118 | + | ||
119 | +Optional Request Variables | ||
120 | +-------------------------- | ||
121 | + | ||
122 | +Akismet wants certain information about the request environment: remote IP, the | ||
123 | +user agent string, and the HTTP referer when available. Normally, Rakismet | ||
124 | +asks your model for these. Storing this information on your model allows you to | ||
125 | +call the `spam?` method at a later time. For instance, maybe you're storing your | ||
126 | +comments in an administrative queue or processing them with a background job. | ||
127 | + | ||
128 | +You don't need to have these three attributes on your model, however. If you | ||
129 | +choose to omit them, Rakismet will instead look at the current request (if one | ||
130 | +exists) and take the values from the request object instead. | ||
131 | + | ||
132 | +This means that if you are **not storing the request variables**, you must call | ||
133 | +`spam?` from within the controller action that handles comment submissions. That | ||
134 | +way the IP, user agent, and referer will belong to the person submitting the | ||
135 | +comment. If you're not storing the request variables and you call `spam?` at a | ||
136 | +later time, the request information will be missing or invalid and Akismet won't | ||
137 | +be able to do its job properly. | ||
138 | + | ||
139 | +If you've decided to handle the request variables yourself, you can disable the | ||
140 | +middleware responsible for tracking the request information by adding this to | ||
141 | +your app initialization: | ||
142 | + | ||
143 | +```ruby | ||
144 | +config.rakismet.use_middleware = false | ||
145 | +``` | ||
146 | + | ||
147 | +Testing | ||
148 | +------- | ||
149 | + | ||
150 | +Rakismet can be configued to tell Akismet that it should operate in test mode - | ||
151 | +so Akismet will not change its behavior based on any test API calls, meaning | ||
152 | +they will have no training effect. That means your tests can be somewhat | ||
153 | +repeatable in the sense that one test won't influence subsequent calls. | ||
154 | + | ||
155 | +You can configure Rakismet for test mode via application.rb: | ||
156 | + | ||
157 | +```ruby | ||
158 | +config.rakismet.test = false # <- default | ||
159 | +config.rakismet.test = true | ||
160 | +``` | ||
161 | + | ||
162 | +Or via an initializer: | ||
163 | + | ||
164 | +```ruby | ||
165 | +YourApp::Application.config.rakismet.test = false # <- default | ||
166 | +YourApp::Application.config.rakismet.test = true | ||
167 | +``` | ||
168 | + | ||
169 | +**NOTE**: When running in Rails, Rakismet will run in test mode when your Rails | ||
170 | +environment is `test` or `development`, unless explictly configured otherwise. | ||
171 | +Outside of Rails Rakismet defaults to test mode turned **off**. | ||
172 | + | ||
173 | + | ||
174 | +Verifying Responses | ||
175 | +------------------- | ||
176 | + | ||
177 | +If you want to see what's happening behind the scenes, after you call one of | ||
178 | +`@comment.spam?`, `@comment.spam!` or `@comment.ham!` you can check | ||
179 | +`@comment.akismet_response`. | ||
180 | + | ||
181 | +This will contain the last response from the Akismet server. In the case of | ||
182 | +`spam?` it should be `true` or `false.` For `spam!` and `ham!` it should be | ||
183 | +`Feedback received.` If Akismet returned an error instead (e.g. if you left out | ||
184 | +some required information) this will contain the error message. | ||
185 | + | ||
186 | +FAQ | ||
187 | +=== | ||
188 | + | ||
189 | +Why does Akismet think all of my test data is spam? | ||
190 | +--------------------------------------------------- | ||
191 | + | ||
192 | +Akismet needs enough information to decide if your test data is spam or not. | ||
193 | +Try to supply as much as possible, especially the author name and request | ||
194 | +variables. | ||
195 | + | ||
196 | +How can I simulate a spam submission? | ||
197 | +------------------------------------- | ||
198 | + | ||
199 | +Most people have the opposite problem, where Akismet doesn't think anything is | ||
200 | +spam. The only guaranteed way to trigger a positive spam response is to set the | ||
201 | +comment author to "viagra-test-123". | ||
202 | + | ||
203 | +If you've done this and `spam?` is still returning false, you're probably | ||
204 | +missing the user IP or one of the key/url config variables. One way to check is | ||
205 | +to call `@comment.akismet_response`. If you are missing a required field or | ||
206 | +there was another error, this will hold the Akismet error message. If your comment | ||
207 | +was processed normally, this value will simply be `true` or `false`. | ||
208 | + | ||
209 | +Can I use Rakismet with a different ORM or framework? | ||
210 | +----------------------------------------------------- | ||
211 | + | ||
212 | +Sure. Rakismet doesn't care what your persistence layer is. It will work with | ||
213 | +Datamapper, a NoSQL store, or whatever next month's DB flavor is. | ||
214 | + | ||
215 | +Rakismet also has no dependencies on Rails or any of its components, and only | ||
216 | +uses a small Rack middleware object to do some of its magic. Depending on your | ||
217 | +framework, you may have to modify this slightly and/or manually place it in your | ||
218 | +stack. | ||
219 | + | ||
220 | +You'll also need to set a few config variables by hand. Instead of | ||
221 | +`config.rakismet.key`, `config.rakismet.url`, and `config.rakismet.host`, set | ||
222 | +these values directly with `Rakismet.key`, `Rakismet.url`, and `Rakismet.host`. | ||
223 | + | ||
224 | +--------------------------------------------------------------------------- | ||
225 | + | ||
226 | +If you have any implementation or usage questions, don't hesitate to get in | ||
227 | +touch: josh@vitamin-j.com. | ||
228 | + | ||
229 | +Copyright (c) 2008 Josh French, released under the MIT license |
@@ -0,0 +1,9 @@ | @@ -0,0 +1,9 @@ | ||
1 | +require 'bundler' | ||
2 | +Bundler::GemHelper.install_tasks | ||
3 | + | ||
4 | +require 'rspec/core/rake_task' | ||
5 | +RSpec::Core::RakeTask.new do |spec| | ||
6 | + spec.rspec_opts = ["--color", "--format progress"] | ||
7 | +end | ||
8 | + | ||
9 | +task :default => :spec | ||
0 | \ No newline at end of file | 10 | \ No newline at end of file |
@@ -0,0 +1,92 @@ | @@ -0,0 +1,92 @@ | ||
1 | +require 'net/http' | ||
2 | +require 'uri' | ||
3 | +require 'cgi' | ||
4 | +require 'yaml' | ||
5 | + | ||
6 | +require 'rakismet/model' | ||
7 | +require 'rakismet/middleware' | ||
8 | +require 'rakismet/version' | ||
9 | + | ||
10 | +if defined?(Rails) && Rails::VERSION::STRING > '3.2.0' | ||
11 | + require 'rakismet/railtie.rb' | ||
12 | + $stderr.puts "W: on Rails 3, this vendored version of rakismet should be replaced by a proper dependency" | ||
13 | +end | ||
14 | + | ||
15 | +module Rakismet | ||
16 | + Request = Struct.new(:user_ip, :user_agent, :referrer) | ||
17 | + Undefined = Class.new(NameError) | ||
18 | + | ||
19 | + class << self | ||
20 | + attr_accessor :key, :url, :host, :proxy_host, :proxy_port, :test | ||
21 | + | ||
22 | + def request | ||
23 | + @request ||= Request.new | ||
24 | + end | ||
25 | + | ||
26 | + def set_request_vars(env) | ||
27 | + request.user_ip, request.user_agent, request.referrer = | ||
28 | + env['REMOTE_ADDR'], env['HTTP_USER_AGENT'], env['HTTP_REFERER'] | ||
29 | + end | ||
30 | + | ||
31 | + def clear_request | ||
32 | + @request = Request.new | ||
33 | + end | ||
34 | + | ||
35 | + def headers | ||
36 | + @headers ||= begin | ||
37 | + user_agent = "Rakismet/#{Rakismet::VERSION}" | ||
38 | + user_agent = "Rails/#{Rails.version} | " + user_agent if defined?(Rails) | ||
39 | + { 'User-Agent' => user_agent, 'Content-Type' => 'application/x-www-form-urlencoded' } | ||
40 | + end | ||
41 | + end | ||
42 | + | ||
43 | + def validate_key | ||
44 | + validate_config | ||
45 | + akismet = URI.parse(verify_url) | ||
46 | + response = Net::HTTP::Proxy(proxy_host, proxy_port).start(akismet.host) do |http| | ||
47 | + data = "key=#{Rakismet.key}&blog=#{Rakismet.url}" | ||
48 | + http.post(akismet.path, data, Rakismet.headers) | ||
49 | + end | ||
50 | + @valid_key = (response.body == 'valid') | ||
51 | + end | ||
52 | + | ||
53 | + def valid_key? | ||
54 | + @valid_key == true | ||
55 | + end | ||
56 | + | ||
57 | + def akismet_call(function, args={}) | ||
58 | + validate_config | ||
59 | + args.merge!(:blog => Rakismet.url, :is_test => Rakismet.test_mode) | ||
60 | + akismet = URI.parse(call_url(function)) | ||
61 | + response = Net::HTTP::Proxy(proxy_host, proxy_port).start(akismet.host) do |http| | ||
62 | + params = args.map do |k,v| | ||
63 | + param = v.class < String ? v.to_str : v.to_s # for ActiveSupport::SafeBuffer and Nil, respectively | ||
64 | + "#{k}=#{CGI.escape(param)}" | ||
65 | + end | ||
66 | + http.post(akismet.path, params.join('&'), Rakismet.headers) | ||
67 | + end | ||
68 | + response.body | ||
69 | + end | ||
70 | + | ||
71 | + protected | ||
72 | + | ||
73 | + def verify_url | ||
74 | + "http://#{Rakismet.host}/1.1/verify-key" | ||
75 | + end | ||
76 | + | ||
77 | + def call_url(function) | ||
78 | + "http://#{Rakismet.key}.#{Rakismet.host}/1.1/#{function}" | ||
79 | + end | ||
80 | + | ||
81 | + def validate_config | ||
82 | + raise Undefined, "Rakismet.key is not defined" if Rakismet.key.nil? || Rakismet.key.empty? | ||
83 | + raise Undefined, "Rakismet.url is not defined" if Rakismet.url.nil? || Rakismet.url.empty? | ||
84 | + raise Undefined, "Rakismet.host is not defined" if Rakismet.host.nil? || Rakismet.host.empty? | ||
85 | + end | ||
86 | + | ||
87 | + def test_mode | ||
88 | + test ? 1 : 0 | ||
89 | + end | ||
90 | + end | ||
91 | + | ||
92 | +end |
@@ -0,0 +1,86 @@ | @@ -0,0 +1,86 @@ | ||
1 | +module Rakismet | ||
2 | + module Model | ||
3 | + | ||
4 | + def self.included(base) | ||
5 | + base.class_eval do | ||
6 | + attr_accessor :akismet_response | ||
7 | + class << self; attr_accessor :akismet_attrs; end | ||
8 | + extend ClassMethods | ||
9 | + include InstanceMethods | ||
10 | + self.rakismet_attrs | ||
11 | + end | ||
12 | + end | ||
13 | + | ||
14 | + module ClassMethods | ||
15 | + def rakismet_attrs(args={}) | ||
16 | + self.akismet_attrs ||= {} | ||
17 | + [:comment_type, :author, :author_url, :author_email, :content, :user_role].each do |field| | ||
18 | + # clunky, but throwing around +type+ will break your heart | ||
19 | + fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern | ||
20 | + self.akismet_attrs[fieldname] = args.delete(field) || field | ||
21 | + end | ||
22 | + [:user_ip, :user_agent, :referrer].each do |field| | ||
23 | + self.akismet_attrs[field] = args.delete(field) || field | ||
24 | + end | ||
25 | + args.each_pair do |f,v| | ||
26 | + self.akismet_attrs[f] = v | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + def inherited(subclass) | ||
31 | + super | ||
32 | + subclass.rakismet_attrs akismet_attrs.dup | ||
33 | + end | ||
34 | + end | ||
35 | + | ||
36 | + module InstanceMethods | ||
37 | + def spam? | ||
38 | + if instance_variable_defined? :@_spam | ||
39 | + @_spam | ||
40 | + else | ||
41 | + data = akismet_data | ||
42 | + self.akismet_response = Rakismet.akismet_call('comment-check', data) | ||
43 | + @_spam = self.akismet_response == 'true' | ||
44 | + end | ||
45 | + end | ||
46 | + | ||
47 | + def spam! | ||
48 | + Rakismet.akismet_call('submit-spam', akismet_data) | ||
49 | + @_spam = true | ||
50 | + end | ||
51 | + | ||
52 | + def ham! | ||
53 | + Rakismet.akismet_call('submit-ham', akismet_data) | ||
54 | + @_spam = false | ||
55 | + end | ||
56 | + | ||
57 | + private | ||
58 | + | ||
59 | + def akismet_data | ||
60 | + akismet = self.class.akismet_attrs.keys.inject({}) do |data,attr| | ||
61 | + mapped_field = self.class.akismet_attrs[attr] | ||
62 | + data.merge attr => if mapped_field.is_a?(Proc) | ||
63 | + instance_eval(&mapped_field) | ||
64 | + elsif !mapped_field.nil? && respond_to?(mapped_field) | ||
65 | + send(mapped_field) | ||
66 | + elsif not [:comment_type, :author, :author_email, | ||
67 | + :author_url, :content, :user_role, | ||
68 | + :user_ip, :referrer, | ||
69 | + :user_agent].include?(mapped_field) | ||
70 | + # we've excluded any fields that appear to | ||
71 | + # have their default unmapped values | ||
72 | + mapped_field | ||
73 | + elsif respond_to?(attr) | ||
74 | + send(attr) | ||
75 | + elsif Rakismet.request.respond_to?(attr) | ||
76 | + Rakismet.request.send(attr) | ||
77 | + end | ||
78 | + end | ||
79 | + akismet.delete_if { |k,v| v.nil? || v.empty? } | ||
80 | + akismet[:comment_type] ||= 'comment' | ||
81 | + akismet | ||
82 | + end | ||
83 | + end | ||
84 | + | ||
85 | + end | ||
86 | +end |
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +require 'rails' | ||
2 | +require 'rakismet' | ||
3 | + | ||
4 | +module Rakismet | ||
5 | + class Railtie < Rails::Railtie | ||
6 | + | ||
7 | + config.rakismet = ActiveSupport::OrderedOptions.new | ||
8 | + config.rakismet.host = 'rest.akismet.com' | ||
9 | + config.rakismet.use_middleware = true | ||
10 | + | ||
11 | + initializer 'rakismet.setup', :after => :load_config_initializers do |app| | ||
12 | + Rakismet.key = app.config.rakismet[:key] | ||
13 | + Rakismet.url = app.config.rakismet[:url] | ||
14 | + Rakismet.host = app.config.rakismet[:host] | ||
15 | + Rakismet.proxy_host = app.config.rakismet[:proxy_host] | ||
16 | + Rakismet.proxy_port = app.config.rakismet[:proxy_port] | ||
17 | + Rakismet.test = app.config.rakismet.fetch(:test) { Rails.env.test? || Rails.env.development? } | ||
18 | + app.middleware.use Rakismet::Middleware if app.config.rakismet.use_middleware | ||
19 | + end | ||
20 | + | ||
21 | + end | ||
22 | +end |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +# -*- encoding: utf-8 -*- | ||
2 | +require File.expand_path('../lib/rakismet/version', __FILE__) | ||
3 | + | ||
4 | +Gem::Specification.new do |s| | ||
5 | + s.name = "rakismet" | ||
6 | + s.version = Rakismet::VERSION | ||
7 | + s.platform = Gem::Platform::RUBY | ||
8 | + s.authors = ["Josh French"] | ||
9 | + s.email = "josh@vitamin-j.com" | ||
10 | + s.homepage = "http://github.com/joshfrench/rakismet" | ||
11 | + s.summary = "Akismet and TypePad AntiSpam integration for Rails." | ||
12 | + s.description = "Rakismet is the easiest way to integrate Akismet or TypePad's AntiSpam into your Rails app." | ||
13 | + s.date = "2012-04-22" | ||
14 | + | ||
15 | + s.rubyforge_project = "rakismet" | ||
16 | + s.add_development_dependency "rake" | ||
17 | + s.add_development_dependency "rspec", "~> 2.11" | ||
18 | + | ||
19 | + s.files = `git ls-files`.split("\n") | ||
20 | + s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n") | ||
21 | + s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) } | ||
22 | + s.require_paths = ["lib"] | ||
23 | + s.extra_rdoc_files = ["README.md"] | ||
24 | +end | ||
25 | + |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +--color |
vendor/plugins/rakismet/spec/models/block_params_spec.rb
0 → 100644
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +PROC = proc { author.reverse } | ||
4 | + | ||
5 | +class BlockAkismetModel | ||
6 | + include Rakismet::Model | ||
7 | + rakismet_attrs :author => PROC | ||
8 | +end | ||
9 | + | ||
10 | +describe BlockAkismetModel do | ||
11 | + | ||
12 | + before do | ||
13 | + @block = BlockAkismetModel.new | ||
14 | + comment_attrs.each_pair { |k,v| @block.stub!(k).and_return(v) } | ||
15 | + end | ||
16 | + | ||
17 | + it "should accept a block" do | ||
18 | + BlockAkismetModel.akismet_attrs[:comment_author].should eql(PROC) | ||
19 | + end | ||
20 | + | ||
21 | + it "should eval block with self = instance" do | ||
22 | + data = @block.send(:akismet_data) | ||
23 | + data[:comment_author].should eql(comment_attrs[:author].reverse) | ||
24 | + end | ||
25 | +end |
vendor/plugins/rakismet/spec/models/custom_params_spec.rb
0 → 100644
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +MAPPED_PARAMS = { :comment_type => :type2, :author => :author2, :content => :content2, | ||
4 | + :author_email => :author_email2, :author_url => :author_url2, | ||
5 | + :user_role => :user_role2 } | ||
6 | + | ||
7 | +class CustomAkismetModel | ||
8 | + include Rakismet::Model | ||
9 | + rakismet_attrs MAPPED_PARAMS.dup | ||
10 | +end | ||
11 | + | ||
12 | + | ||
13 | +describe CustomAkismetModel do | ||
14 | + it "should override default mappings" do | ||
15 | + [:comment_type, :author, :author_url, :author_email, :content, :user_role].each do |field| | ||
16 | + fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern | ||
17 | + CustomAkismetModel.akismet_attrs[fieldname].should eql(MAPPED_PARAMS[field]) | ||
18 | + end | ||
19 | + end | ||
20 | +end |
vendor/plugins/rakismet/spec/models/extended_params_spec.rb
0 → 100644
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +EXTRA = { :extra => :extra, :another => lambda { } } | ||
4 | + | ||
5 | +class ExtendedAkismetModel | ||
6 | + include Rakismet::Model | ||
7 | + rakismet_attrs EXTRA.dup | ||
8 | +end | ||
9 | + | ||
10 | +describe ExtendedAkismetModel do | ||
11 | + it "should include additional attributes" do | ||
12 | + [:extra, :another].each do |field| | ||
13 | + ExtendedAkismetModel.akismet_attrs[field].should eql(EXTRA[field]) | ||
14 | + end | ||
15 | + end | ||
16 | +end |
vendor/plugins/rakismet/spec/models/rakismet_model_spec.rb
0 → 100644
@@ -0,0 +1,98 @@ | @@ -0,0 +1,98 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe AkismetModel do | ||
4 | + | ||
5 | + before do | ||
6 | + @model = AkismetModel.new | ||
7 | + comment_attrs.each_pair { |k,v| @model.stub!(k).and_return(v) } | ||
8 | + end | ||
9 | + | ||
10 | + it "should have default mappings" do | ||
11 | + [:comment_type, :author, :author_email, :author_url, :content, :user_role].each do |field| | ||
12 | + fieldname = field.to_s =~ %r(^comment_) ? field : "comment_#{field}".intern | ||
13 | + AkismetModel.akismet_attrs[fieldname].should eql(field) | ||
14 | + end | ||
15 | + end | ||
16 | + | ||
17 | + it "should have request mappings" do | ||
18 | + [:user_ip, :user_agent, :referrer].each do |field| | ||
19 | + AkismetModel.akismet_attrs[field].should eql(field) | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + it "should populate comment type" do | ||
24 | + @model.send(:akismet_data)[:comment_type].should == comment_attrs[:comment_type] | ||
25 | + end | ||
26 | + | ||
27 | + describe ".spam?" do | ||
28 | + | ||
29 | + it "should use request variables from Rakismet.request if absent in model" do | ||
30 | + [:user_ip, :user_agent, :referrer].each do |field| | ||
31 | + @model.should_not respond_to(:field) | ||
32 | + end | ||
33 | + Rakismet.stub!(:request).and_return(request) | ||
34 | + Rakismet.should_receive(:akismet_call). | ||
35 | + with('comment-check', akismet_attrs.merge(:user_ip => '127.0.0.1', | ||
36 | + :user_agent => 'RSpec', | ||
37 | + :referrer => 'http://test.host/referrer')) | ||
38 | + @model.spam? | ||
39 | + end | ||
40 | + | ||
41 | + it "should cache result of #spam?" do | ||
42 | + Rakismet.should_receive(:akismet_call).once | ||
43 | + @model.spam? | ||
44 | + @model.spam? | ||
45 | + end | ||
46 | + | ||
47 | + it "should be true if comment is spam" do | ||
48 | + Rakismet.stub!(:akismet_call).and_return('true') | ||
49 | + @model.should be_spam | ||
50 | + end | ||
51 | + | ||
52 | + it "should be false if comment is not spam" do | ||
53 | + Rakismet.stub!(:akismet_call).and_return('false') | ||
54 | + @model.should_not be_spam | ||
55 | + end | ||
56 | + | ||
57 | + it "should set akismet_response" do | ||
58 | + Rakismet.stub!(:akismet_call).and_return('response') | ||
59 | + @model.spam? | ||
60 | + @model.akismet_response.should eql('response') | ||
61 | + end | ||
62 | + | ||
63 | + it "should not throw an error if request vars are missing" do | ||
64 | + Rakismet.stub!(:request).and_return(empty_request) | ||
65 | + lambda { @model.spam? }.should_not raise_error(NoMethodError) | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
69 | + | ||
70 | + describe ".spam!" do | ||
71 | + it "should call Base.akismet_call with submit-spam" do | ||
72 | + Rakismet.should_receive(:akismet_call).with('submit-spam', akismet_attrs) | ||
73 | + @model.spam! | ||
74 | + end | ||
75 | + | ||
76 | + it "should mutate #spam?" do | ||
77 | + Rakismet.stub!(:akismet_call) | ||
78 | + @model.instance_variable_set(:@_spam, false) | ||
79 | + @model.spam! | ||
80 | + @model.should be_spam | ||
81 | + end | ||
82 | + end | ||
83 | + | ||
84 | + describe ".ham!" do | ||
85 | + it "should call Base.akismet_call with submit-ham" do | ||
86 | + Rakismet.should_receive(:akismet_call).with('submit-ham', akismet_attrs) | ||
87 | + @model.ham! | ||
88 | + end | ||
89 | + | ||
90 | + it "should mutate #spam?" do | ||
91 | + Rakismet.stub!(:akismet_call) | ||
92 | + @model.instance_variable_set(:@_spam, true) | ||
93 | + @model.ham! | ||
94 | + @model.should_not be_spam | ||
95 | + end | ||
96 | + end | ||
97 | + | ||
98 | +end |
vendor/plugins/rakismet/spec/models/request_params_spec.rb
0 → 100644
@@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +class RequestParams | ||
4 | + include Rakismet::Model | ||
5 | + attr_accessor :user_ip, :user_agent, :referrer | ||
6 | +end | ||
7 | + | ||
8 | +describe RequestParams do | ||
9 | + before do | ||
10 | + @model = RequestParams.new | ||
11 | + attrs = comment_attrs(:user_ip => '192.168.0.1', :user_agent => 'Rakismet', :referrer => 'http://localhost/referrer') | ||
12 | + attrs.each_pair { |k,v| @model.stub!(k).and_return(v) } | ||
13 | + end | ||
14 | + | ||
15 | + it "should use local values even if Rakismet.request is populated" do | ||
16 | + Rakismet.stub(:request).and_return(request) | ||
17 | + Rakismet.should_receive(:akismet_call). | ||
18 | + with('comment-check', akismet_attrs.merge(:user_ip => '192.168.0.1', | ||
19 | + :user_agent => 'Rakismet', | ||
20 | + :referrer => 'http://localhost/referrer')) | ||
21 | + @model.spam? | ||
22 | + end | ||
23 | +end |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +class Subclass < AkismetModel | ||
4 | +end | ||
5 | + | ||
6 | +describe Subclass do | ||
7 | + it "should inherit parent's rakismet attrs" do | ||
8 | + Subclass.akismet_attrs.should eql AkismetModel.akismet_attrs # key/value equality | ||
9 | + end | ||
10 | + | ||
11 | + it "should get a new copy of parent's rakismet attrs" do | ||
12 | + Subclass.akismet_attrs.should_not equal AkismetModel.akismet_attrs # object equality | ||
13 | + end | ||
14 | +end |
vendor/plugins/rakismet/spec/rakismet_middleware_spec.rb
0 → 100644
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe Rakismet::Middleware do | ||
4 | + | ||
5 | + let(:env) { { 'REMOTE_ADDR' => '127.0.0.1', 'HTTP_USER_AGENT' => 'RSpec', 'HTTP_REFERER' => 'http://test.host/referrer' } } | ||
6 | + let(:app) { double(:app, :call => nil) } | ||
7 | + let(:request) { double(:request).as_null_object } | ||
8 | + | ||
9 | + before do | ||
10 | + @middleware = Rakismet::Middleware.new(app) | ||
11 | + end | ||
12 | + | ||
13 | + it "should set set Rakismet.request variables" do | ||
14 | + Rakismet.stub(:request).and_return(request) | ||
15 | + request.should_receive(:user_ip=).with('127.0.0.1') | ||
16 | + request.should_receive(:user_agent=).with('RSpec') | ||
17 | + request.should_receive(:referrer=).with('http://test.host/referrer') | ||
18 | + @middleware.call(env) | ||
19 | + end | ||
20 | + | ||
21 | + it "should clear Rakismet.request after request is complete" do | ||
22 | + @middleware.call(env) | ||
23 | + Rakismet.request.user_ip.should be_nil | ||
24 | + Rakismet.request.user_agent.should be_nil | ||
25 | + Rakismet.request.referrer.should be_nil | ||
26 | + end | ||
27 | +end |
@@ -0,0 +1,123 @@ | @@ -0,0 +1,123 @@ | ||
1 | +require 'spec_helper' | ||
2 | + | ||
3 | +describe Rakismet do | ||
4 | + | ||
5 | + def mock_response(body) | ||
6 | + double(:response, :body => body) | ||
7 | + end | ||
8 | + let(:http) { double(:http, :post => mock_response('akismet response')) } | ||
9 | + | ||
10 | + before do | ||
11 | + Rakismet.key = 'dummy-key' | ||
12 | + Rakismet.url = 'test.localhost' | ||
13 | + Rakismet.host = 'endpoint.localhost' | ||
14 | + end | ||
15 | + | ||
16 | + describe "proxy host" do | ||
17 | + it "should have proxy host and port as nil by default" do | ||
18 | + Rakismet.proxy_host.should be_nil | ||
19 | + Rakismet.proxy_port.should be_nil | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + describe ".validate_config" do | ||
24 | + it "should raise an error if key is not found" do | ||
25 | + Rakismet.key = '' | ||
26 | + lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined) | ||
27 | + end | ||
28 | + | ||
29 | + it "should raise an error if url is not found" do | ||
30 | + Rakismet.url = '' | ||
31 | + lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined) | ||
32 | + end | ||
33 | + | ||
34 | + it "should raise an error if host is not found" do | ||
35 | + Rakismet.host = '' | ||
36 | + lambda { Rakismet.send(:validate_config) }.should raise_error(Rakismet::Undefined) | ||
37 | + end | ||
38 | + end | ||
39 | + | ||
40 | + describe ".validate_key" do | ||
41 | + before (:each) do | ||
42 | + @proxy = mock(Net::HTTP) | ||
43 | + Net::HTTP.stub!(:Proxy).and_return(@proxy) | ||
44 | + end | ||
45 | + | ||
46 | + it "should use proxy host and port" do | ||
47 | + Rakismet.proxy_host = 'proxy_host' | ||
48 | + Rakismet.proxy_port = 'proxy_port' | ||
49 | + @proxy.stub!(:start).and_return(mock_response('valid')) | ||
50 | + Net::HTTP.should_receive(:Proxy).with('proxy_host', 'proxy_port').and_return(@proxy) | ||
51 | + Rakismet.validate_key | ||
52 | + end | ||
53 | + | ||
54 | + it "should set @@valid_key = true if key is valid" do | ||
55 | + @proxy.stub!(:start).and_return(mock_response('valid')) | ||
56 | + Rakismet.validate_key | ||
57 | + Rakismet.valid_key?.should be_true | ||
58 | + end | ||
59 | + | ||
60 | + it "should set @@valid_key = false if key is invalid" do | ||
61 | + @proxy.stub!(:start).and_return(mock_response('invalid')) | ||
62 | + Rakismet.validate_key | ||
63 | + Rakismet.valid_key?.should be_false | ||
64 | + end | ||
65 | + | ||
66 | + it "should build url with host" do | ||
67 | + host = "api.antispam.typepad.com" | ||
68 | + Rakismet.host = host | ||
69 | + @proxy.should_receive(:start).with(host).and_yield(http) | ||
70 | + Rakismet.validate_key | ||
71 | + end | ||
72 | + end | ||
73 | + | ||
74 | + describe ".akismet_call" do | ||
75 | + before do | ||
76 | + @proxy = mock(Net::HTTP) | ||
77 | + Net::HTTP.stub!(:Proxy).and_return(@proxy) | ||
78 | + @proxy.stub(:start).and_yield(http) | ||
79 | + end | ||
80 | + | ||
81 | + it "should use proxy host and port" do | ||
82 | + Rakismet.proxy_host = 'proxy_host' | ||
83 | + Rakismet.proxy_port = 'proxy_port' | ||
84 | + @proxy.stub!(:start).and_return(mock_response('valid')) | ||
85 | + Net::HTTP.should_receive(:Proxy).with('proxy_host', 'proxy_port').and_return(@proxy) | ||
86 | + Rakismet.send(:akismet_call, 'bogus-function') | ||
87 | + end | ||
88 | + | ||
89 | + it "should build url with API key for the correct host" do | ||
90 | + host = 'api.antispam.typepad.com' | ||
91 | + Rakismet.host = host | ||
92 | + @proxy.should_receive(:start).with("#{Rakismet.key}.#{host}") | ||
93 | + Rakismet.send(:akismet_call, 'bogus-function') | ||
94 | + end | ||
95 | + | ||
96 | + it "should post data to named function" do | ||
97 | + http.should_receive(:post).with('/1.1/bogus-function', %r(foo=#{CGI.escape 'escape//this'}), Rakismet.headers) | ||
98 | + Rakismet.send(:akismet_call, 'bogus-function', { :foo => 'escape//this' }) | ||
99 | + end | ||
100 | + | ||
101 | + it "should default to not being in test mode" do | ||
102 | + http.should_receive(:post).with(anything, %r(is_test=0), anything) | ||
103 | + Rakismet.send(:akismet_call, 'bogus-function') | ||
104 | + end | ||
105 | + | ||
106 | + it "should be in test mode when configured" do | ||
107 | + Rakismet.test = true | ||
108 | + http.should_receive(:post).with(anything, %r(is_test=1), anything) | ||
109 | + Rakismet.send(:akismet_call, 'bogus-function') | ||
110 | + end | ||
111 | + | ||
112 | + it "should return response.body" do | ||
113 | + Rakismet.send(:akismet_call, 'bogus-function').should eql('akismet response') | ||
114 | + end | ||
115 | + | ||
116 | + it "should build query string when params are nil" do | ||
117 | + lambda { | ||
118 | + Rakismet.send(:akismet_call, 'bogus-function', { :nil_param => nil }) | ||
119 | + }.should_not raise_error(NoMethodError) | ||
120 | + end | ||
121 | + end | ||
122 | + | ||
123 | +end |
@@ -0,0 +1,34 @@ | @@ -0,0 +1,34 @@ | ||
1 | +require File.expand_path "lib/rakismet" | ||
2 | +require 'ostruct' | ||
3 | + | ||
4 | +RSpec.configure do |config| | ||
5 | + config.mock_with :rspec | ||
6 | +end | ||
7 | + | ||
8 | +class AkismetModel | ||
9 | + include Rakismet::Model | ||
10 | +end | ||
11 | + | ||
12 | +def comment_attrs(attrs={}) | ||
13 | + { :comment_type => 'test', :author => 'Rails test', | ||
14 | + :author_email => 'test@test.host', :author_url => 'test.host', | ||
15 | + :content => 'comment content', :blog => Rakismet.url }.merge(attrs) | ||
16 | +end | ||
17 | + | ||
18 | +def akismet_attrs(attrs={}) | ||
19 | + { :comment_type => 'test', :comment_author_email => 'test@test.host', | ||
20 | + :comment_author => 'Rails test', :comment_author_url => 'test.host', | ||
21 | + :comment_content => 'comment content' }.merge(attrs) | ||
22 | +end | ||
23 | + | ||
24 | +def request | ||
25 | + OpenStruct.new(:user_ip => '127.0.0.1', | ||
26 | + :user_agent => 'RSpec', | ||
27 | + :referrer => 'http://test.host/referrer') | ||
28 | +end | ||
29 | + | ||
30 | +def empty_request | ||
31 | + OpenStruct.new(:user_ip => nil, | ||
32 | + :user_agent => nil, | ||
33 | + :referrer => nil) | ||
34 | +end | ||
0 | \ No newline at end of file | 35 | \ No newline at end of file |