Commit cbc821f22fa498cebe584b77a0fc053a263856ca
Exists in
master
and in
29 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 | 101 | end |
102 | 102 | end |
103 | 103 | |
104 | + include Noosfero::Plugin::HotSpot | |
105 | + | |
104 | 106 | def init_noosfero_plugins |
105 | - @plugins = Noosfero::Plugin::Manager.new(self) | |
106 | - @plugins.each do |plugin| | |
107 | + plugins.each do |plugin| | |
107 | 108 | prepend_view_path(plugin.class.view_path) |
108 | 109 | end |
109 | 110 | init_noosfero_plugins_controller_filters |
... | ... | @@ -112,7 +113,7 @@ class ApplicationController < ActionController::Base |
112 | 113 | # This is a generic method that initialize any possible filter defined by a |
113 | 114 | # plugin to the current controller being initialized. |
114 | 115 | def init_noosfero_plugins_controller_filters |
115 | - @plugins.each do |plugin| | |
116 | + plugins.each do |plugin| | |
116 | 117 | plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| |
117 | 118 | self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) |
118 | 119 | self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) | ... | ... |
... | ... | @@ -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 | 75 | @comment = Comment.new |
76 | 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 | 86 | end |
81 | 87 | |
82 | 88 | if @page.has_posts? |
... | ... | @@ -107,8 +113,9 @@ class ContentViewerController < ApplicationController |
107 | 113 | end |
108 | 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 | 119 | if params[:slideshow] |
113 | 120 | render :action => 'slideshow', :layout => 'slideshow' |
114 | 121 | end |
... | ... | @@ -120,10 +127,11 @@ class ContentViewerController < ApplicationController |
120 | 127 | @comment.author = user if logged_in? |
121 | 128 | @comment.article = @page |
122 | 129 | @comment.ip_address = request.remote_ip |
130 | + @comment.user_agent = request.user_agent | |
131 | + @comment.referrer = request.referrer | |
123 | 132 | plugins_filter_comment(@comment) |
124 | 133 | return if @comment.rejected? |
125 | 134 | if (pass_without_comment_captcha? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save |
126 | - plugins_comment_saved(@comment) | |
127 | 135 | @page.touch |
128 | 136 | @comment = nil # clear the comment form |
129 | 137 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] |
... | ... | @@ -138,12 +146,6 @@ class ContentViewerController < ApplicationController |
138 | 146 | end |
139 | 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 | 149 | def pass_without_comment_captcha? |
148 | 150 | logged_in? && !environment.enabled?('captcha_for_logged_users') |
149 | 151 | end |
... | ... | @@ -153,9 +155,24 @@ class ContentViewerController < ApplicationController |
153 | 155 | @comment = @page.comments.find(params[:remove_comment]) |
154 | 156 | if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) |
155 | 157 | @comment.destroy |
156 | - session[:notice] = _('Comment succesfully deleted') | |
157 | 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 | 176 | end |
160 | 177 | |
161 | 178 | def per_page | ... | ... |
app/helpers/content_viewer_helper.rb
... | ... | @@ -4,11 +4,11 @@ module ContentViewerHelper |
4 | 4 | include ForumHelper |
5 | 5 | |
6 | 6 | def number_of_comments(article) |
7 | - n = article.comments.size | |
7 | + n = article.comments.without_spam.count | |
8 | 8 | if n == 0 |
9 | 9 | _('No comments yet') |
10 | 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 | 12 | end |
13 | 13 | end |
14 | 14 | ... | ... |
app/models/comment.rb
... | ... | @@ -10,6 +10,9 @@ class Comment < ActiveRecord::Base |
10 | 10 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
11 | 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 | 16 | # unauthenticated authors: |
14 | 17 | validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) |
15 | 18 | validates_presence_of :email, :if => (lambda { |record| !record.name.blank? }) |
... | ... | @@ -85,7 +88,28 @@ class Comment < ActiveRecord::Base |
85 | 88 | end |
86 | 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 | 113 | def notify_by_mail |
90 | 114 | if source.kind_of?(Article) && article.notify_comments? |
91 | 115 | if !article.profile.notification_emails.empty? |
... | ... | @@ -123,10 +147,14 @@ class Comment < ActiveRecord::Base |
123 | 147 | def self.as_thread |
124 | 148 | result = {} |
125 | 149 | root = [] |
126 | - all.each do |c| | |
150 | + order(:id).each do |c| | |
127 | 151 | c.replies = [] |
128 | 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 | 158 | end |
131 | 159 | root |
132 | 160 | end |
... | ... | @@ -183,4 +211,34 @@ class Comment < ActiveRecord::Base |
183 | 211 | @rejected = true |
184 | 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 | 244 | end | ... | ... |
app/models/person.rb
... | ... | @@ -22,8 +22,6 @@ class Person < Profile |
22 | 22 | super |
23 | 23 | end |
24 | 24 | |
25 | - acts_as_having_hotspots | |
26 | - | |
27 | 25 | named_scope :members_of, lambda { |resources| |
28 | 26 | resources = [resources] if !resources.kind_of?(Array) |
29 | 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 | 30 | |
33 | 31 | def has_permission_with_plugins?(permission, profile) |
34 | 32 | permissions = [has_permission_without_plugins?(permission, profile)] |
35 | - permissions += enabled_plugins.map do |plugin| | |
33 | + permissions += plugins.map do |plugin| | |
36 | 34 | plugin.has_permission?(self, permission, profile) |
37 | 35 | end |
38 | 36 | permissions.include?(true) | ... | ... |
app/models/profile.rb
... | ... | @@ -60,7 +60,8 @@ class Profile < ActiveRecord::Base |
60 | 60 | } |
61 | 61 | |
62 | 62 | acts_as_accessible |
63 | - acts_as_having_hotspots | |
63 | + | |
64 | + include Noosfero::Plugin::HotSpot | |
64 | 65 | |
65 | 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 | 67 | #FIXME: these will work only if the subclass is already loaded |
... | ... | @@ -69,7 +70,7 @@ class Profile < ActiveRecord::Base |
69 | 70 | named_scope :templates, :conditions => {:is_template => true} |
70 | 71 | |
71 | 72 | def members |
72 | - scopes = dispatch_scopes(:organization_members, self) | |
73 | + scopes = plugins.dispatch_scopes(:organization_members, self) | |
73 | 74 | scopes << Person.members_of(self) |
74 | 75 | scopes.size == 1 ? scopes.first : Person.or_scope(scopes) |
75 | 76 | end |
... | ... | @@ -113,6 +114,8 @@ class Profile < ActiveRecord::Base |
113 | 114 | has_many :scraps_received, :class_name => 'Scrap', :foreign_key => :receiver_id, :order => "updated_at DESC", :dependent => :destroy |
114 | 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 | 119 | # FIXME ugly workaround |
117 | 120 | def self.human_attribute_name(attrib) |
118 | 121 | _(self.superclass.human_attribute_name(attrib)) |
... | ... | @@ -255,7 +258,7 @@ class Profile < ActiveRecord::Base |
255 | 258 | self.categories(true) |
256 | 259 | self.solr_save |
257 | 260 | end |
258 | - self.categories(reload) | |
261 | + self.categories(reload) | |
259 | 262 | end |
260 | 263 | |
261 | 264 | def category_ids=(ids) | ... | ... |
app/views/admin_panel/index.rhtml
1 | 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 | 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 | 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 | 31 | <tr><td><%= link_to link[:title], link[:url] %></td></tr> |
21 | 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 | 42 | </table> | ... | ... |
app/views/content_viewer/_comment.rhtml
1 | 1 | <li id="<%= comment.anchor %>" class="article-comment"> |
2 | 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 | 6 | <% if comment.author %> |
7 | 7 | <%= link_to image_tag(profile_icon(comment.author, :minor)) + |
... | ... | @@ -29,17 +29,12 @@ |
29 | 29 | <% end %> |
30 | 30 | |
31 | 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 | 33 | <div class="comment-details"> |
39 | 34 | <div class="comment-created-at"> |
40 | 35 | <%= show_time(comment.created_at) %> |
41 | 36 | </div> |
42 | - <h4><%= comment.title %></h4> | |
37 | + <h4><%= comment.title.blank? && ' ' || comment.title %></h4> | |
43 | 38 | <div class="comment-text"> |
44 | 39 | <p/> |
45 | 40 | <%= txt2html comment.body %> |
... | ... | @@ -57,18 +52,37 @@ |
57 | 52 | </script> |
58 | 53 | <% end %> |
59 | 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 | 74 | "var f = add_comment_reply_form(this, %s); f.find('input[name=comment[title]], textarea').val(''); return false" % comment.id, |
62 | 75 | :class => 'comment-footer comment-footer-link comment-footer-hide', |
63 | 76 | :id => 'comment-reply-to-' + comment.id.to_s |
64 | - %> | |
77 | + %> | |
78 | + <% end %> | |
65 | 79 | </div> |
66 | 80 | |
67 | 81 | <% end %> |
68 | 82 | |
69 | 83 | </div> |
70 | 84 | |
71 | - <% unless comment.replies.blank? %> | |
85 | + <% unless comment.replies.blank? || comment.spam? %> | |
72 | 86 | <ul class="comment-replies"> |
73 | 87 | <% comment.replies.each do |reply| %> |
74 | 88 | <%= render :partial => 'comment', :locals => { :comment => reply } %> | ... | ... |
app/views/content_viewer/view_page.rhtml
... | ... | @@ -99,12 +99,6 @@ |
99 | 99 | |
100 | 100 | <% if @page.accept_comments? %> |
101 | 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 | 102 | <% end %> |
109 | 103 | </div><!-- end class="comments" --> |
110 | 104 | ... | ... |
app/views/plugins/index.rhtml
1 | 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 | 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 | 28 | <div> |
23 | 29 | <% button_bar do %> | ... | ... |
app/views/profile_editor/index.rhtml
... | ... | @@ -66,6 +66,8 @@ |
66 | 66 | |
67 | 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 | 71 | <% @plugins.dispatch(:control_panel_buttons).each do |button| %> |
70 | 72 | <%= control_panel_button(button[:title], button[:icon], button[:url]) %> |
71 | 73 | <% end %> | ... | ... |
... | ... | @@ -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 | 1 | require 'noosfero/plugin' |
2 | -require 'noosfero/plugin/acts_as_having_hotspots' | |
2 | +require 'noosfero/plugin/hot_spot' | |
3 | 3 | require 'noosfero/plugin/manager' |
4 | -require 'noosfero/plugin/context' | |
5 | 4 | require 'noosfero/plugin/active_record' |
6 | 5 | require 'noosfero/plugin/mailer_base' |
7 | 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 @@ |
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 | 9 | # |
10 | 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 | 14 | create_table "abuse_reports", :force => true do |t| |
15 | 15 | t.integer "reporter_id" |
... | ... | @@ -213,6 +213,8 @@ ActiveRecord::Schema.define(:version => 20120818030329) do |
213 | 213 | t.string "ip_address" |
214 | 214 | t.boolean "spam" |
215 | 215 | t.string "source_type" |
216 | + t.string "user_agent" | |
217 | + t.string "referrer" | |
216 | 218 | end |
217 | 219 | |
218 | 220 | create_table "contact_lists", :force => true do |t| | ... | ... |
debian/changelog
features/edit_environment_templates.feature
... | ... | @@ -8,7 +8,7 @@ Feature: edit environment templates |
8 | 8 | Scenario: See links to edit all templates |
9 | 9 | Given I am logged in as admin |
10 | 10 | When I follow "Administration" |
11 | - And I follow "Edit Templates" | |
11 | + And I follow "Profile templates" | |
12 | 12 | Then I should see "Person template" link |
13 | 13 | And I should see "Community template" link |
14 | 14 | And I should see "Enterprise template" link |
... | ... | @@ -17,28 +17,28 @@ Feature: edit environment templates |
17 | 17 | Scenario: Go to control panel of person template |
18 | 18 | Given I am logged in as admin |
19 | 19 | When I follow "Administration" |
20 | - And I follow "Edit Templates" | |
20 | + And I follow "Profile templates" | |
21 | 21 | And I follow "Person template" |
22 | 22 | Then I should be on Person template's control panel |
23 | 23 | |
24 | 24 | Scenario: Go to control panel of enterprise template |
25 | 25 | Given I am logged in as admin |
26 | 26 | When I follow "Administration" |
27 | - And I follow "Edit Templates" | |
27 | + And I follow "Profile templates" | |
28 | 28 | And I follow "Enterprise template" |
29 | 29 | Then I should be on Enterprise template's control panel |
30 | 30 | |
31 | 31 | Scenario: Go to control panel of inactive enterprise template |
32 | 32 | Given I am logged in as admin |
33 | 33 | When I follow "Administration" |
34 | - And I follow "Edit Templates" | |
34 | + And I follow "Profile templates" | |
35 | 35 | And I follow "Inactive enterprise template" |
36 | 36 | Then I should be on Inactive Enterprise template's control panel |
37 | 37 | |
38 | 38 | Scenario: Go to control panel of community template |
39 | 39 | Given I am logged in as admin |
40 | 40 | When I follow "Administration" |
41 | - And I follow "Edit Templates" | |
41 | + And I follow "Profile templates" | |
42 | 42 | And I follow "Community template" |
43 | 43 | Then I should be on Community template's control panel |
44 | 44 | |
... | ... | @@ -46,7 +46,7 @@ Feature: edit environment templates |
46 | 46 | Given that the default environment have no Inactive Enterprise template |
47 | 47 | And I am logged in as admin |
48 | 48 | When I follow "Administration" |
49 | - And I follow "Edit Templates" | |
49 | + And I follow "Profile templates" | |
50 | 50 | Then I should see "Person template" link |
51 | 51 | And I should see "Community template" link |
52 | 52 | And I should see "Enterprise template" link | ... | ... |
features/environment_name.feature
... | ... | @@ -6,7 +6,7 @@ Feature: setting environment name |
6 | 6 | Scenario: setting environment name through administration panel |
7 | 7 | Given I am logged in as admin |
8 | 8 | When I follow "Administration" |
9 | - And I follow "Edit environment settings" | |
9 | + And I follow "Environment settings" | |
10 | 10 | And I fill in "Site name" with "My environment" |
11 | 11 | And I press "Save" |
12 | 12 | Then I should see "My environment" within "title" | ... | ... |
features/export_users.feature
... | ... | @@ -10,14 +10,14 @@ Feature: export users |
10 | 10 | Scenario: Export users as XML |
11 | 11 | Given I am logged in as admin |
12 | 12 | When I follow "Administration" |
13 | - And I follow "Manage users" | |
13 | + And I follow "Users" | |
14 | 14 | And I follow "[XML]" |
15 | 15 | Then I should see "ultraje" |
16 | 16 | |
17 | 17 | Scenario: Export users as CSV |
18 | 18 | Given I am logged in as admin |
19 | 19 | When I follow "Administration" |
20 | - And I follow "Manage users" | |
20 | + And I follow "Users" | |
21 | 21 | And I follow "[CSV]" |
22 | 22 | Then I should see "name;email" |
23 | 23 | And I should see "ultraje" | ... | ... |
features/manage_categories.feature
... | ... | @@ -14,7 +14,7 @@ Feature: manage categories |
14 | 14 | | Development | services | |
15 | 15 | And I am logged in as admin |
16 | 16 | And I am on the environment control panel |
17 | - And I follow "Manage categories" | |
17 | + And I follow "Categories" | |
18 | 18 | |
19 | 19 | Scenario: load only top level categories |
20 | 20 | Then I should see "Products" | ... | ... |
features/plugins.feature
... | ... | @@ -49,7 +49,7 @@ Feature: plugins |
49 | 49 | When I go to the profile |
50 | 50 | Then I should see "Test plugin tab" |
51 | 51 | And I go to the environment control panel |
52 | - And I follow "Enable/disable plugins" | |
52 | + And I follow "Plugins" | |
53 | 53 | And I uncheck "Test plugin" |
54 | 54 | And I press "Save changes" |
55 | 55 | When I go to the Control panel | ... | ... |
features/roles.feature
... | ... | @@ -5,26 +5,26 @@ Feature: manage roles |
5 | 5 | Scenario: create new role |
6 | 6 | Given I am logged in as admin |
7 | 7 | And I go to the environment control panel |
8 | - And I follow "Manage User roles" | |
8 | + And I follow "User roles" | |
9 | 9 | Then I should not see "My new role" |
10 | 10 | And I follow "Create a new role" |
11 | 11 | And I fill in "Name" with "My new role" |
12 | 12 | And I check "Publish content" |
13 | 13 | And I press "Create role" |
14 | 14 | And I go to the environment control panel |
15 | - And I follow "Manage User roles" | |
15 | + And I follow "User roles" | |
16 | 16 | Then I should see "My new role" |
17 | 17 | |
18 | 18 | Scenario: edit a role |
19 | 19 | Given I am logged in as admin |
20 | 20 | And I go to the environment control panel |
21 | - And I follow "Manage User roles" | |
21 | + And I follow "User roles" | |
22 | 22 | Then I should not see "My new role" |
23 | 23 | And I follow "Profile Administrator" |
24 | 24 | And I follow "Edit" |
25 | 25 | And I fill in "Name" with "My new role" |
26 | 26 | And I press "Save changes" |
27 | 27 | And I go to the environment control panel |
28 | - And I follow "Manage User roles" | |
28 | + And I follow "User roles" | |
29 | 29 | Then I should see "My new role" |
30 | 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 | 18 | Scenario: Send e-mail to members |
19 | 19 | Given I am logged in as admin |
20 | 20 | When I follow "Administration" |
21 | - And I follow "Manage users" | |
21 | + And I follow "Users" | |
22 | 22 | And I follow "Send e-mail to users" |
23 | 23 | And I fill in "Subject" with "Hello, user!" |
24 | 24 | And I fill in "body" with "We have some news" |
... | ... | @@ -28,7 +28,7 @@ Feature: send emails to environment members users |
28 | 28 | Scenario: Not send e-mail to members if subject is blank |
29 | 29 | Given I am logged in as admin |
30 | 30 | When I follow "Administration" |
31 | - And I follow "Manage users" | |
31 | + And I follow "Users" | |
32 | 32 | And I follow "Send e-mail to users" |
33 | 33 | And I fill in "body" with "We have some news" |
34 | 34 | When I press "Send" |
... | ... | @@ -37,7 +37,7 @@ Feature: send emails to environment members users |
37 | 37 | Scenario: Not send e-mail to members if body is blank |
38 | 38 | Given I am logged in as admin |
39 | 39 | When I follow "Administration" |
40 | - And I follow "Manage users" | |
40 | + And I follow "Users" | |
41 | 41 | And I follow "Send e-mail to users" |
42 | 42 | And I fill in "Subject" with "Hello, user!" |
43 | 43 | When I press "Send" |
... | ... | @@ -46,7 +46,7 @@ Feature: send emails to environment members users |
46 | 46 | Scenario: Cancel creation of mailing |
47 | 47 | Given I am logged in as admin |
48 | 48 | When I follow "Administration" |
49 | - And I follow "Manage users" | |
49 | + And I follow "Users" | |
50 | 50 | And I follow "Send e-mail to users" |
51 | 51 | Then I should be on /admin/users/send_mail |
52 | 52 | When I follow "Cancel e-mail" | ... | ... |
lib/needs_profile.rb
... | ... | @@ -14,12 +14,12 @@ module NeedsProfile |
14 | 14 | profile || environment # prefers profile, but defaults to environment |
15 | 15 | end |
16 | 16 | |
17 | - protected | |
18 | - | |
19 | 17 | def profile |
20 | 18 | @profile |
21 | 19 | end |
22 | 20 | |
21 | + protected | |
22 | + | |
23 | 23 | def load_profile |
24 | 24 | @profile ||= environment.profiles.find_by_identifier(params[:profile]) |
25 | 25 | if @profile | ... | ... |
lib/noosfero.rb
lib/noosfero/plugin.rb
... | ... | @@ -15,14 +15,29 @@ class Noosfero::Plugin |
15 | 15 | Dir.glob(File.join(Rails.root, 'config', 'plugins', '*')).select do |entry| |
16 | 16 | File.directory?(entry) |
17 | 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 | 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 | 41 | end |
27 | 42 | end |
28 | 43 | |
... | ... | @@ -226,16 +241,53 @@ class Noosfero::Plugin |
226 | 241 | # example: |
227 | 242 | # |
228 | 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 | 247 | # end |
231 | 248 | # |
232 | 249 | def filter_comment(comment) |
233 | 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 | 291 | end |
240 | 292 | |
241 | 293 | # -> Adds fields to the signup form | ... | ... |
lib/noosfero/plugin/acts_as_having_hotspots.rb
... | ... | @@ -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 | -# 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 @@ |
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 | 1 | class Noosfero::Plugin::Manager |
2 | 2 | |
3 | - extend ActsAsHavingHotspots::ClassMethods | |
4 | - acts_as_having_hotspots | |
5 | - | |
3 | + attr_reader :environment | |
6 | 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 | 11 | delegate :each, :to => :enabled_plugins |
10 | 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 | 37 | end |
19 | 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 | 4 | end |
5 | +disabled_plugins = all_plugins - enabled_plugins | |
13 | 6 | |
14 | 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 | 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 | 67 | end |
52 | - task plugin_name => dependencies | |
53 | 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 | 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 | 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 | 92 | end |
74 | - Rake::Task['test:noosfero_plugins:rollback_temp_enable_plugins'].invoke | |
75 | 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 | 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 | 105 | end |
100 | 106 | |
107 | + task :rollback_enable_all_plugins do | |
108 | + sh './script/noosfero-plugins', 'disable', *disabled_plugins | |
109 | + end | |
101 | 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 | 114 | end |
106 | - | ... | ... |
lib/tasks/release.rake
... | ... | @@ -95,6 +95,9 @@ EOF |
95 | 95 | sh "cd #{target} && dpkg-buildpackage -us -uc -b" |
96 | 96 | end |
97 | 97 | |
98 | + desc "Build Debian packages (shorcut)" | |
99 | + task :deb => :debian_packages | |
100 | + | |
98 | 101 | desc 'Test Debian package' |
99 | 102 | task 'debian:test' => :debian_packages do |
100 | 103 | Dir.chdir 'pkg' do | ... | ... |
plugins/anti_spam/controllers/anti_spam_plugin_admin_controller.rb
0 → 100644
... | ... | @@ -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 @@ |
1 | +require 'rakismet' | ... | ... |
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 35 | controller = mock() |
36 | 36 | controller.stubs(:logged_in?).returns(boolean) |
37 | 37 | controller.stubs(:profile).returns(Profile.new) |
38 | - Noosfero::Plugin::Context.new(controller) | |
38 | + controller | |
39 | 39 | end |
40 | 40 | |
41 | 41 | end | ... | ... |
plugins/stoa/test/functional/profile_editor_controller.rb
... | ... | @@ -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 @@ |
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 @@ |
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 | 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 | 713 | function original_image_dimensions(src) { |
687 | 714 | var img = new Image(); |
688 | 715 | img.src = src; | ... | ... |
public/stylesheets/application.css
... | ... | @@ -1069,15 +1069,6 @@ a.comment-picture { |
1069 | 1069 | top: 9px; |
1070 | 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 | 1072 | .msie7 .article-comments-list .comment-balloon { |
1082 | 1073 | margin-top: -15px; |
1083 | 1074 | } |
... | ... | @@ -1271,6 +1262,11 @@ a.comment-picture { |
1271 | 1262 | } |
1272 | 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 | 1270 | .post_comment_box { |
1275 | 1271 | text-align: center; |
1276 | 1272 | padding: 0px 15px 5px 15px; |
... | ... | @@ -3854,6 +3850,9 @@ h1#agenda-title { |
3854 | 3850 | .controller-profile_editor .msie6 a.control-panel-edit-location { |
3855 | 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 | 3856 | /* ==> public/stylesheets/controller_profile_members.css <== */ |
3858 | 3857 | .controller-profile_members .no-boxes { |
3859 | 3858 | margin: 30px | ... | ... |
script/install-dependencies/debian-squeeze.sh
1 | 1 | # needed to run noosfero |
2 | 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 | 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 | 6 | # needed for development |
6 | 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 | 10 | run bundle install | ... | ... |
script/noosfero-plugins
... | ... | @@ -21,6 +21,8 @@ disabled_plugins=$(printf "%s\n" $available_plugins $enabled_plugins_dir | sort |
21 | 21 | # operation defaults |
22 | 22 | quiet=false |
23 | 23 | needs_migrate=false |
24 | +load_paths="$NOOSFERO_DIR/lib:$(echo $NOOSFERO_DIR/vendor/plugins/*/lib | tr ' ' :)" | |
25 | + | |
24 | 26 | |
25 | 27 | _list() { |
26 | 28 | for plugin in $available_plugins; do |
... | ... | @@ -72,11 +74,26 @@ _enable(){ |
72 | 74 | if [ -h "$target" ]; then |
73 | 75 | _say "$plugin already enabled" |
74 | 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 | 97 | fi |
81 | 98 | } |
82 | 99 | ... | ... |
script/production
... | ... | @@ -34,8 +34,6 @@ do_start() { |
34 | 34 | } |
35 | 35 | |
36 | 36 | do_stop() { |
37 | - rake -s solr:stop | |
38 | - | |
39 | 37 | # During Debian upgrades, it is possible that rails is not available (e.g. |
40 | 38 | # Lenny -> Squeeze), so the programs below might fail. If they do, we fall |
41 | 39 | # back to stopping the daemons by manually reading their PID files, killing |
... | ... | @@ -46,6 +44,8 @@ do_stop() { |
46 | 44 | |
47 | 45 | environments_loop stop || |
48 | 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 | 51 | stop_via_pid_file() { | ... | ... |
script/quick-start
... | ... | @@ -21,6 +21,22 @@ run() { |
21 | 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 | 40 | force_install=false |
25 | 41 | if test "$1" = '--force-install'; then |
26 | 42 | force_install=true |
... | ... | @@ -28,9 +44,15 @@ fi |
28 | 44 | if gem which system_timer >/dev/null 2>&1 && which xvfb-run >/dev/null 2>&1 && test "$force_install" = 'false'; then |
29 | 45 | say "Assuming dependencies are already installed. Pass --force-install to force their installation" |
30 | 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 | 56 | fi |
35 | 57 | system=$(echo $(lsb_release -sic) | awk '{print(tolower($1) "-" tolower($2))}') |
36 | 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 | 92 | |
93 | 93 | login_as 'testuser' |
94 | 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 | 96 | end |
97 | 97 | |
98 | 98 | should 'display remove comment button with param view when image' do |
... | ... | @@ -106,8 +106,9 @@ class ContentViewerControllerTest < ActionController::TestCase |
106 | 106 | |
107 | 107 | login_as 'testuser' |
108 | 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 | 113 | should 'not add unneeded params for remove comment button' do |
113 | 114 | profile = create_user('testuser').person |
... | ... | @@ -117,8 +118,8 @@ class ContentViewerControllerTest < ActionController::TestCase |
117 | 118 | comment.save! |
118 | 119 | |
119 | 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 | 123 | end |
123 | 124 | |
124 | 125 | should 'be able to remove comment' do |
... | ... | @@ -1374,12 +1375,16 @@ class ContentViewerControllerTest < ActionController::TestCase |
1374 | 1375 | assert_not_nil assigns(:comment) |
1375 | 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 | 1379 | page = profile.articles.create!(:name => 'myarticle', :body => 'the body of the text') |
1379 | 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 | 1383 | post :view_page, :profile => profile.identifier, :page => [ 'myarticle' ], :comment => { :title => 'title', :body => 'body', :name => "Spammer", :email => 'damn@spammer.com' }, :confirm => 'true' |
1381 | 1384 | comment = Comment.last |
1382 | 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 | 1388 | end |
1384 | 1389 | |
1385 | 1390 | should 'not save a comment if a plugin rejects it' do |
... | ... | @@ -1395,25 +1400,6 @@ class ContentViewerControllerTest < ActionController::TestCase |
1395 | 1400 | end |
1396 | 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 | 1403 | should 'remove email from article followers when unfollow' do |
1418 | 1404 | profile = create_user('testuser').person |
1419 | 1405 | follower_email = 'john@doe.br' |
... | ... | @@ -1426,4 +1412,24 @@ class ContentViewerControllerTest < ActionController::TestCase |
1426 | 1412 | assert_not_includes Article.find(article.id).followers, follower_email |
1427 | 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 | 1435 | end | ... | ... |
... | ... | @@ -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 @@ |
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 | 14 | |
15 | 15 | should 'deliver mail after make an article comment' do |
16 | 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 | 18 | end |
19 | 19 | end |
20 | 20 | |
21 | 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 | 23 | sent = ActionMailer::Base.deliveries.first |
24 | 24 | assert_equal [@profile.email], sent.to |
25 | 25 | end |
26 | 26 | |
27 | 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 | 29 | sent = ActionMailer::Base.deliveries.first |
30 | 30 | assert_match /user_comment_test/, sent.body |
31 | 31 | end |
32 | 32 | |
33 | 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 | 35 | sent = ActionMailer::Base.deliveries.first |
36 | 36 | assert_match /flatline/, sent.body |
37 | 37 | assert_match /flatline@invalid.com/, sent.body |
... | ... | @@ -40,18 +40,18 @@ class CommentNotifierTest < ActiveSupport::TestCase |
40 | 40 | should 'not deliver mail if notify comments is false' do |
41 | 41 | @article.update_attribute(:notify_comments, false) |
42 | 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 | 44 | end |
45 | 45 | end |
46 | 46 | |
47 | 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 | 49 | sent = ActionMailer::Base.deliveries.first |
50 | 50 | assert_match /comment title/, sent.body |
51 | 51 | end |
52 | 52 | |
53 | 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 | 55 | sent = ActionMailer::Base.deliveries.first |
56 | 56 | assert_match /comment body/, sent.body |
57 | 57 | end |
... | ... | @@ -61,7 +61,7 @@ class CommentNotifierTest < ActiveSupport::TestCase |
61 | 61 | assert_equal [], community.notification_emails |
62 | 62 | article = fast_create(Article, :name => 'Article test', :profile_id => community.id, :notify_comments => true) |
63 | 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 | 65 | end |
66 | 66 | end |
67 | 67 | |
... | ... | @@ -70,24 +70,29 @@ class CommentNotifierTest < ActiveSupport::TestCase |
70 | 70 | follower = create_user('follower').person |
71 | 71 | @article.followers += [follower.email] |
72 | 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 | 74 | assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email |
75 | 75 | end |
76 | 76 | |
77 | 77 | should "not deliver follower's mail about new comment to comment's author" do |
78 | 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 | 80 | assert_not_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email |
81 | 81 | end |
82 | 82 | |
83 | 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 | 98 | end | ... | ... |
test/unit/comment_test.rb
... | ... | @@ -398,6 +398,9 @@ class CommentTest < ActiveSupport::TestCase |
398 | 398 | end |
399 | 399 | |
400 | 400 | should 'update article activity when add a comment' do |
401 | + now = Time.now | |
402 | + Time.stubs(:now).returns(now) | |
403 | + | |
401 | 404 | profile = create_user('testuser').person |
402 | 405 | article = create(TinyMceArticle, :profile => profile) |
403 | 406 | |
... | ... | @@ -422,4 +425,142 @@ class CommentTest < ActiveSupport::TestCase |
422 | 425 | assert_not_nil article.activity |
423 | 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 | 566 | end | ... | ... |
test/unit/content_viewer_helper_test.rb
... | ... | @@ -61,9 +61,9 @@ class ContentViewerHelperTest < ActiveSupport::TestCase |
61 | 61 | end |
62 | 62 | |
63 | 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 | 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 | 67 | result = link_to_comments(article) |
68 | 68 | assert_match /One comment/, result |
69 | 69 | end | ... | ... |
test/unit/person_test.rb
... | ... | @@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' |
3 | 3 | class PersonTest < ActiveSupport::TestCase |
4 | 4 | fixtures :profiles, :users, :environments |
5 | 5 | |
6 | - def teardown | |
7 | - Thread.current[:enabled_plugins] = nil | |
8 | - end | |
9 | - | |
10 | 6 | def test_person_must_come_form_the_cration_of_an_user |
11 | 7 | p = Person.new(:environment => Environment.default, :name => 'John', :identifier => 'john') |
12 | 8 | assert !p.valid? | ... | ... |
... | ... | @@ -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 | 8 | @controller.stubs(:profile).returns() |
9 | 9 | @controller.stubs(:request).returns() |
10 | 10 | @controller.stubs(:response).returns() |
11 | - @controller.stubs(:environment).returns(@environment) | |
12 | 11 | @controller.stubs(:params).returns() |
12 | + @manager = Noosfero::Plugin::Manager.new(@environment, @controller) | |
13 | 13 | end |
14 | 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 | 22 | should 'return the intersection between environment\'s enabled plugins and system available plugins' do |
17 | 23 | class Plugin1 < Noosfero::Plugin; end; |
... | ... | @@ -20,7 +26,6 @@ class PluginManagerTest < ActiveSupport::TestCase |
20 | 26 | class Plugin4 < Noosfero::Plugin; end; |
21 | 27 | environment.stubs(:enabled_plugins).returns([Plugin1.to_s, Plugin2.to_s, Plugin4.to_s]) |
22 | 28 | Noosfero::Plugin.stubs(:all).returns([Plugin1.to_s, Plugin3.to_s, Plugin4.to_s]) |
23 | - manager = Noosfero::Plugin::Manager.new(@controller) | |
24 | 29 | plugins = manager.enabled_plugins.map { |instance| instance.class.to_s } |
25 | 30 | assert_equal [Plugin1.to_s, Plugin4.to_s], plugins |
26 | 31 | end |
... | ... | @@ -49,7 +54,6 @@ class PluginManagerTest < ActiveSupport::TestCase |
49 | 54 | |
50 | 55 | p1 = Plugin1.new |
51 | 56 | p2 = Plugin2.new |
52 | - manager = Noosfero::Plugin::Manager.new(@controller) | |
53 | 57 | |
54 | 58 | assert_equal [p1.random_event, p2.random_event], manager.dispatch(:random_event) |
55 | 59 | end | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -3,10 +3,6 @@ require File.dirname(__FILE__) + '/../test_helper' |
3 | 3 | class ProfileTest < ActiveSupport::TestCase |
4 | 4 | fixtures :profiles, :environments, :users, :roles, :domains |
5 | 5 | |
6 | - def teardown | |
7 | - Thread.current[:enabled_plugins] = nil | |
8 | - end | |
9 | - | |
10 | 6 | def test_identifier_validation |
11 | 7 | p = Profile.new |
12 | 8 | p.valid? |
... | ... | @@ -1834,16 +1830,6 @@ class ProfileTest < ActiveSupport::TestCase |
1834 | 1830 | end |
1835 | 1831 | |
1836 | 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 | 1833 | class Plugin1 < Noosfero::Plugin |
1848 | 1834 | def organization_members(profile) |
1849 | 1835 | Person.members_of(Community.find_by_identifier('community1')) |
... | ... | @@ -1855,8 +1841,18 @@ class ProfileTest < ActiveSupport::TestCase |
1855 | 1841 | Person.members_of(Community.find_by_identifier('community2')) |
1856 | 1842 | end |
1857 | 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 | 1857 | assert_includes original_community.members, original_member |
1862 | 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 | 20 | |
21 | 21 | tmpdir = [ '/var/tmp', '/tmp' ].find { |d| File.exists?(d) } |
22 | 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 | 34 | sh "echo \"#{SOLR_MD5SUM} #{SOLR_FILENAME}\" | md5sum -c -" do |ok, res| |
26 | 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 @@ |
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 @@ |
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 @@ |
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,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 @@ |
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 @@ |
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 @@ |
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 @@ |
1 | +--color | ... | ... |
vendor/plugins/rakismet/spec/models/block_params_spec.rb
0 → 100644
... | ... | @@ -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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 @@ |
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 | 35 | \ No newline at end of file | ... | ... |