Commit bd4954d3143c452fee2a074571ffc66cbc2b2eda
Exists in
master
and in
28 other branches
Merge branch 'master' into next-origin
Conflicts: app/models/category.rb app/models/uploaded_file.rb test/functional/memberships_controller_test.rb test/functional/profile_controller_test.rb vendor/plugins/action_tracker_has_comments/init.rb
Showing
46 changed files
with
389 additions
and
75 deletions
Show diff stats
AUTHORS
@@ -111,6 +111,7 @@ Diego Martinez <diegoamc90@gmail.com> | @@ -111,6 +111,7 @@ Diego Martinez <diegoamc90@gmail.com> | ||
111 | Diego Martinez <diego@diego-K55A.(none)> | 111 | Diego Martinez <diego@diego-K55A.(none)> |
112 | Diego + Renan <renanteruoc@gmail.com> | 112 | Diego + Renan <renanteruoc@gmail.com> |
113 | Fernanda Lopes <nanda.listas+psl@gmail.com> | 113 | Fernanda Lopes <nanda.listas+psl@gmail.com> |
114 | +Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br> | ||
114 | Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)> | 115 | Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)> |
115 | Grazieno Pellegrino <grazieno@gmail.com> | 116 | Grazieno Pellegrino <grazieno@gmail.com> |
116 | Isaac Canan <isaac@intelletto.com.br> | 117 | Isaac Canan <isaac@intelletto.com.br> |
@@ -189,12 +190,14 @@ Renan Teruo + Diego Araujo <renanteruoc@gmail.com> | @@ -189,12 +190,14 @@ Renan Teruo + Diego Araujo <renanteruoc@gmail.com> | ||
189 | Renan Teruo + Diego Araújo <renanteruoc@gmail.com> | 190 | Renan Teruo + Diego Araújo <renanteruoc@gmail.com> |
190 | Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com> | 191 | Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com> |
191 | Renan Teruo + Rafael Manzo <renanteruoc@gmail.com> | 192 | Renan Teruo + Rafael Manzo <renanteruoc@gmail.com> |
193 | +Rodrigo Souto <diguliu@gmail.com> | ||
192 | Rodrigo Souto <rodrigo@colivre.coop.br> | 194 | Rodrigo Souto <rodrigo@colivre.coop.br> |
193 | Ronny Kursawe <kursawe.ronny@googlemail.com> | 195 | Ronny Kursawe <kursawe.ronny@googlemail.com> |
194 | root <root@debian.sdr.serpro> | 196 | root <root@debian.sdr.serpro> |
195 | Samuel R. C. Vale <srcvale@holoscopio.com> | 197 | Samuel R. C. Vale <srcvale@holoscopio.com> |
196 | Valessio Brito <valessio@gmail.com> | 198 | Valessio Brito <valessio@gmail.com> |
197 | vfcosta <vfcosta@gmail.com> | 199 | vfcosta <vfcosta@gmail.com> |
200 | +Vinicius Cubas Brand <viniciuscb@gmail.com> | ||
198 | Visita <visita@debian.(none)> | 201 | Visita <visita@debian.(none)> |
199 | Yann Lugrin <yann.lugrin@liquid-concept.ch> | 202 | Yann Lugrin <yann.lugrin@liquid-concept.ch> |
200 | 203 |
app/controllers/application_controller.rb
@@ -174,8 +174,6 @@ class ApplicationController < ActionController::Base | @@ -174,8 +174,6 @@ class ApplicationController < ActionController::Base | ||
174 | end | 174 | end |
175 | 175 | ||
176 | def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) | 176 | def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) |
177 | - scope = scope.send(options[:filter]) if options[:filter] | ||
178 | - | ||
179 | @plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) || | 177 | @plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) || |
180 | fallback_find_by_contents(asset, scope, query, paginate_options, options) | 178 | fallback_find_by_contents(asset, scope, query, paginate_options, options) |
181 | end | 179 | end |
@@ -183,8 +181,9 @@ class ApplicationController < ActionController::Base | @@ -183,8 +181,9 @@ class ApplicationController < ActionController::Base | ||
183 | private | 181 | private |
184 | 182 | ||
185 | def fallback_find_by_contents(asset, scope, query, paginate_options, options) | 183 | def fallback_find_by_contents(asset, scope, query, paginate_options, options) |
186 | - return {:results => scope.paginate(paginate_options)} if query.blank? | ||
187 | - {:results => scope.like_search(query).paginate(paginate_options)} | 184 | + scope = scope.like_search(query) unless query.blank? |
185 | + scope = scope.send(options[:filter]) unless options[:filter].blank? | ||
186 | + {:results => scope.paginate(paginate_options)} | ||
188 | end | 187 | end |
189 | 188 | ||
190 | end | 189 | end |
app/controllers/public/content_viewer_controller.rb
@@ -55,8 +55,9 @@ class ContentViewerController < ApplicationController | @@ -55,8 +55,9 @@ class ContentViewerController < ApplicationController | ||
55 | 55 | ||
56 | @page = FilePresenter.for @page | 56 | @page = FilePresenter.for @page |
57 | 57 | ||
58 | - unless @page.mime_type == 'text/html' || params[:view] | 58 | + if @page.download? params[:view] |
59 | headers['Content-Type'] = @page.mime_type | 59 | headers['Content-Type'] = @page.mime_type |
60 | + headers.merge! @page.download_headers | ||
60 | data = @page.data | 61 | data = @page.data |
61 | 62 | ||
62 | # TODO test the condition | 63 | # TODO test the condition |
@@ -72,7 +73,7 @@ class ContentViewerController < ApplicationController | @@ -72,7 +73,7 @@ class ContentViewerController < ApplicationController | ||
72 | 73 | ||
73 | #FIXME see a better way to do this. It's not need to pass this variable anymore | 74 | #FIXME see a better way to do this. It's not need to pass this variable anymore |
74 | @comment = Comment.new | 75 | @comment = Comment.new |
75 | - | 76 | + |
76 | if @page.has_posts? | 77 | if @page.has_posts? |
77 | posts = if params[:year] and params[:month] | 78 | posts = if params[:year] and params[:month] |
78 | filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01") | 79 | filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01") |
app/helpers/application_helper.rb
@@ -730,8 +730,15 @@ module ApplicationHelper | @@ -730,8 +730,15 @@ module ApplicationHelper | ||
730 | end | 730 | end |
731 | 731 | ||
732 | def rolename_for(profile, resource) | 732 | def rolename_for(profile, resource) |
733 | - role = profile.role_assignments.find_by_resource_id(resource.id).role | ||
734 | - content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}") | 733 | + roles = profile.role_assignments. |
734 | + where(:resource_id => resource.id). | ||
735 | + sort_by{ |role_assignment| role_assignment.role_id }. | ||
736 | + map(&:role) | ||
737 | + names = [] | ||
738 | + roles.each do |role| | ||
739 | + names << content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}") | ||
740 | + end | ||
741 | + names.join(', ') | ||
735 | end | 742 | end |
736 | 743 | ||
737 | def role_color(role, env_id) | 744 | def role_color(role, env_id) |
app/models/article.rb
@@ -194,7 +194,7 @@ class Article < ActiveRecord::Base | @@ -194,7 +194,7 @@ class Article < ActiveRecord::Base | ||
194 | pending_categorizations.clear | 194 | pending_categorizations.clear |
195 | end | 195 | end |
196 | 196 | ||
197 | - acts_as_taggable | 197 | + acts_as_taggable |
198 | N_('Tag list') | 198 | N_('Tag list') |
199 | 199 | ||
200 | acts_as_filesystem | 200 | acts_as_filesystem |
@@ -274,7 +274,7 @@ class Article < ActiveRecord::Base | @@ -274,7 +274,7 @@ class Article < ActiveRecord::Base | ||
274 | end | 274 | end |
275 | 275 | ||
276 | # returns the data of the article. Must be overriden in each subclass to | 276 | # returns the data of the article. Must be overriden in each subclass to |
277 | - # provide the correct content for the article. | 277 | + # provide the correct content for the article. |
278 | def data | 278 | def data |
279 | body | 279 | body |
280 | end | 280 | end |
@@ -370,6 +370,16 @@ class Article < ActiveRecord::Base | @@ -370,6 +370,16 @@ class Article < ActiveRecord::Base | ||
370 | false | 370 | false |
371 | end | 371 | end |
372 | 372 | ||
373 | + def download? view = nil | ||
374 | + (self.uploaded_file? and not self.image?) or | ||
375 | + (self.image? and view.blank?) or | ||
376 | + (not self.uploaded_file? and self.mime_type != 'text/html') | ||
377 | + end | ||
378 | + | ||
379 | + def download_headers | ||
380 | + {} | ||
381 | + end | ||
382 | + | ||
373 | named_scope :native_translations, :conditions => { :translation_of_id => nil } | 383 | named_scope :native_translations, :conditions => { :translation_of_id => nil } |
374 | 384 | ||
375 | def translatable? | 385 | def translatable? |
app/models/category.rb
@@ -7,13 +7,13 @@ class Category < ActiveRecord::Base | @@ -7,13 +7,13 @@ class Category < ActiveRecord::Base | ||
7 | :slug => 1, | 7 | :slug => 1, |
8 | } | 8 | } |
9 | 9 | ||
10 | - validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('%{fn} cannot be like that.').fix_i18n | 10 | + validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('{fn} cannot be like that.').fix_i18n |
11 | validates_presence_of :name, :environment_id | 11 | validates_presence_of :name, :environment_id |
12 | - validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.').fix_i18n | 12 | + validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('{fn} is already being used by another category.').fix_i18n |
13 | belongs_to :environment | 13 | belongs_to :environment |
14 | 14 | ||
15 | validates_inclusion_of :display_color, :in => 1..15, :allow_nil => true | 15 | validates_inclusion_of :display_color, :in => 1..15, :allow_nil => true |
16 | - validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('%{fn} was already assigned to another category.').fix_i18n | 16 | + validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('{fn} was already assigned to another category.').fix_i18n |
17 | 17 | ||
18 | # Finds all top level categories for a given environment. | 18 | # Finds all top level categories for a given environment. |
19 | named_scope :top_level_for, lambda { |environment| | 19 | named_scope :top_level_for, lambda { |environment| |
app/models/comment.rb
@@ -27,7 +27,7 @@ class Comment < ActiveRecord::Base | @@ -27,7 +27,7 @@ class Comment < ActiveRecord::Base | ||
27 | validates_presence_of :author_id, :if => (lambda { |rec| rec.name.blank? && rec.email.blank? }) | 27 | validates_presence_of :author_id, :if => (lambda { |rec| rec.name.blank? && rec.email.blank? }) |
28 | validates_each :name do |rec,attribute,value| | 28 | validates_each :name do |rec,attribute,value| |
29 | if rec.author_id && (!rec.name.blank? || !rec.email.blank?) | 29 | if rec.author_id && (!rec.name.blank? || !rec.email.blank?) |
30 | - rec.errors.add(:name, _('%{fn} can only be informed for unauthenticated authors').fix_i18n) | 30 | + rec.errors.add(:name, _('{fn} can only be informed for unauthenticated authors').fix_i18n) |
31 | end | 31 | end |
32 | end | 32 | end |
33 | 33 |
app/models/create_enterprise.rb
@@ -40,12 +40,12 @@ class CreateEnterprise < Task | @@ -40,12 +40,12 @@ class CreateEnterprise < Task | ||
40 | 40 | ||
41 | if self.region && self.target | 41 | if self.region && self.target |
42 | unless self.region.validators.include?(self.target) || self.target_type == "Environment" | 42 | unless self.region.validators.include?(self.target) || self.target_type == "Environment" |
43 | - self.errors.add(:target, _('%{fn} is not a validator for the chosen region').fix_i18n) | 43 | + self.errors.add(:target, _('{fn} is not a validator for the chosen region').fix_i18n) |
44 | end | 44 | end |
45 | end | 45 | end |
46 | 46 | ||
47 | if self.status != Task::Status::CANCELLED && self.identifier && Profile.exists?(:identifier => self.identifier) | 47 | if self.status != Task::Status::CANCELLED && self.identifier && Profile.exists?(:identifier => self.identifier) |
48 | - self.errors.add(:identifier, _('%{fn} is already being as identifier by another enterprise, organization or person.').fix_i18n) | 48 | + self.errors.add(:identifier, _('{fn} is already being as identifier by another enterprise, organization or person.').fix_i18n) |
49 | end | 49 | end |
50 | end | 50 | end |
51 | 51 |
app/models/domain.rb
@@ -10,14 +10,14 @@ class Domain < ActiveRecord::Base | @@ -10,14 +10,14 @@ class Domain < ActiveRecord::Base | ||
10 | 10 | ||
11 | # <tt>name</tt> must be sequences of alphanumeric characters (a to z, | 11 | # <tt>name</tt> must be sequences of alphanumeric characters (a to z, |
12 | # 0 to 9), plus '_' or '-', separated by dots. Letters must be lowercase. | 12 | # 0 to 9), plus '_' or '-', separated by dots. Letters must be lowercase. |
13 | - validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed of sequences of lowercase letters (a to z), numbers (0 to 9), "_" and "-", separated by dots.').fix_i18n | 13 | + validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('{fn} must be composed of sequences of lowercase letters (a to z), numbers (0 to 9), "_" and "-", separated by dots.').fix_i18n |
14 | 14 | ||
15 | # checks validations that could not be expressed using Rails' predefined | 15 | # checks validations that could not be expressed using Rails' predefined |
16 | # validations. In particular: | 16 | # validations. In particular: |
17 | # * <tt>name</tt> must not start with 'www.' | 17 | # * <tt>name</tt> must not start with 'www.' |
18 | def validate | 18 | def validate |
19 | if self.name =~ /^www\./ | 19 | if self.name =~ /^www\./ |
20 | - self.errors.add(:name, _('%{fn} must not start with www.').fix_i18n) | 20 | + self.errors.add(:name, _('{fn} must not start with www.').fix_i18n) |
21 | end | 21 | end |
22 | end | 22 | end |
23 | 23 |
app/models/environment.rb
@@ -170,7 +170,7 @@ class Environment < ActiveRecord::Base | @@ -170,7 +170,7 @@ class Environment < ActiveRecord::Base | ||
170 | 170 | ||
171 | # One Environment can be reached by many domains | 171 | # One Environment can be reached by many domains |
172 | has_many :domains, :as => :owner | 172 | has_many :domains, :as => :owner |
173 | - has_many :profiles | 173 | + has_many :profiles, :dependent => :destroy |
174 | 174 | ||
175 | has_many :organizations | 175 | has_many :organizations |
176 | has_many :enterprises | 176 | has_many :enterprises |
@@ -785,13 +785,6 @@ class Environment < ActiveRecord::Base | @@ -785,13 +785,6 @@ class Environment < ActiveRecord::Base | ||
785 | self.save! | 785 | self.save! |
786 | end | 786 | end |
787 | 787 | ||
788 | - after_destroy :destroy_templates | ||
789 | - def destroy_templates | ||
790 | - [enterprise_template, inactive_enterprise_template, community_template, person_template].compact.each do |template| | ||
791 | - template.destroy | ||
792 | - end | ||
793 | - end | ||
794 | - | ||
795 | after_create :create_default_licenses | 788 | after_create :create_default_licenses |
796 | def create_default_licenses | 789 | def create_default_licenses |
797 | License.create!(:name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode', :environment => self) | 790 | License.create!(:name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode', :environment => self) |
app/models/event.rb
@@ -25,7 +25,7 @@ class Event < Article | @@ -25,7 +25,7 @@ class Event < Article | ||
25 | 25 | ||
26 | validates_each :start_date do |event,field,value| | 26 | validates_each :start_date do |event,field,value| |
27 | if event.end_date && event.start_date && event.start_date > event.end_date | 27 | if event.end_date && event.start_date && event.start_date > event.end_date |
28 | - event.errors.add(:start_date, _('%{fn} cannot come before end date.').fix_i18n) | 28 | + event.errors.add(:start_date, _('{fn} cannot come before end date.').fix_i18n) |
29 | end | 29 | end |
30 | end | 30 | end |
31 | 31 |
app/models/image.rb
@@ -17,7 +17,7 @@ class Image < ActiveRecord::Base | @@ -17,7 +17,7 @@ class Image < ActiveRecord::Base | ||
17 | :icon => '20x20!' }, | 17 | :icon => '20x20!' }, |
18 | :max_size => 5.megabytes # remember to update validate message below | 18 | :max_size => 5.megabytes # remember to update validate message below |
19 | 19 | ||
20 | - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n | 20 | + validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n |
21 | 21 | ||
22 | delay_attachment_fu_thumbnails | 22 | delay_attachment_fu_thumbnails |
23 | 23 |
app/models/person.rb
@@ -240,7 +240,7 @@ class Person < Profile | @@ -240,7 +240,7 @@ class Person < Profile | ||
240 | 240 | ||
241 | validates_each :email, :on => :update do |record,attr,value| | 241 | validates_each :email, :on => :update do |record,attr,value| |
242 | if User.find(:first, :conditions => ['email = ? and id != ? and environment_id = ?', value, record.user.id, record.environment.id]) | 242 | if User.find(:first, :conditions => ['email = ? and id != ? and environment_id = ?', value, record.user.id, record.environment.id]) |
243 | - record.errors.add(attr, _('%{fn} is already used by other user').fix_i18n) | 243 | + record.errors.add(attr, _('{fn} is already used by other user').fix_i18n) |
244 | end | 244 | end |
245 | end | 245 | end |
246 | 246 |
app/models/uploaded_file.rb
@@ -72,7 +72,7 @@ class UploadedFile < Article | @@ -72,7 +72,7 @@ class UploadedFile < Article | ||
72 | :thumbnail_class => Thumbnail, | 72 | :thumbnail_class => Thumbnail, |
73 | :max_size => self.max_size | 73 | :max_size => self.max_size |
74 | 74 | ||
75 | - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n | 75 | + validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n |
76 | 76 | ||
77 | delay_attachment_fu_thumbnails | 77 | delay_attachment_fu_thumbnails |
78 | 78 | ||
@@ -112,6 +112,12 @@ class UploadedFile < Article | @@ -112,6 +112,12 @@ class UploadedFile < Article | ||
112 | self.name = self.filename | 112 | self.name = self.filename |
113 | end | 113 | end |
114 | 114 | ||
115 | + def download_headers | ||
116 | + { | ||
117 | + 'Content-Disposition' => "attachment; filename=\"#{self.filename}\"", | ||
118 | + } | ||
119 | + end | ||
120 | + | ||
115 | def data | 121 | def data |
116 | File.read(self.full_filename) | 122 | File.read(self.full_filename) |
117 | end | 123 | end |
app/models/user.rb
@@ -114,7 +114,7 @@ class User < ActiveRecord::Base | @@ -114,7 +114,7 @@ class User < ActiveRecord::Base | ||
114 | before_save :encrypt_password | 114 | before_save :encrypt_password |
115 | validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?}) | 115 | validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?}) |
116 | 116 | ||
117 | - validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('%{fn} must be checked in order to signup.').fix_i18n | 117 | + validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n |
118 | 118 | ||
119 | # Authenticates a user by their login name or email and unencrypted password. Returns the user or nil. | 119 | # Authenticates a user by their login name or email and unencrypted password. Returns the user or nil. |
120 | def self.authenticate(login, password, environment = nil) | 120 | def self.authenticate(login, password, environment = nil) |
app/views/catalog/index.rhtml
@@ -92,7 +92,7 @@ | @@ -92,7 +92,7 @@ | ||
92 | <% end %> | 92 | <% end %> |
93 | <% product.price_details.each do |i| %> | 93 | <% product.price_details.each do |i| %> |
94 | <div class="search-product-input-dots-to-price"> | 94 | <div class="search-product-input-dots-to-price"> |
95 | - <div class="search-product-input-name"><%= i.production_cost.name %></div> | 95 | + <div class="search-product-input-name"><%= i.name %></div> |
96 | <%= price_span i.price, :class => 'search-product-input-price' %> | 96 | <%= price_span i.price, :class => 'search-product-input-price' %> |
97 | </div> | 97 | </div> |
98 | <% end %> | 98 | <% end %> |
app/views/profile/_person_profile.rhtml
@@ -4,7 +4,7 @@ | @@ -4,7 +4,7 @@ | ||
4 | </tr> | 4 | </tr> |
5 | <%= display_field(_('Sex:'), profile, :sex) { |gender| { 'male' => _('Male'), 'female' => _('Female') }[gender] } %> | 5 | <%= display_field(_('Sex:'), profile, :sex) { |gender| { 'male' => _('Male'), 'female' => _('Female') }[gender] } %> |
6 | <%= display_field(_('Date of birth:'), profile, :birth_date) { |date| show_date(date) }%> | 6 | <%= display_field(_('Date of birth:'), profile, :birth_date) { |date| show_date(date) }%> |
7 | - <%= display_field(_('Location:'), profile, :location, true) %> | 7 | + <%= display_field _('Location:'), profile, :location %> |
8 | 8 | ||
9 | <%= display_field(_('Type:'), profile, :privacy_setting, true) %> | 9 | <%= display_field(_('Type:'), profile, :privacy_setting, true) %> |
10 | 10 |
app/views/shared/_list_groups.html.erb
@@ -12,7 +12,9 @@ | @@ -12,7 +12,9 @@ | ||
12 | <%= _('Members: %s') % group.members_count.to_s %> <br/> | 12 | <%= _('Members: %s') % group.members_count.to_s %> <br/> |
13 | <%= _('Created at: %s') % show_date(group.created_at) unless group.enterprise? %> <br/> | 13 | <%= _('Created at: %s') % show_date(group.created_at) unless group.enterprise? %> <br/> |
14 | <% button_bar do %> | 14 | <% button_bar do %> |
15 | - <%= button 'menu-ctrl-panel', _('Control panel of this group'), group.admin_url %> | 15 | + <% if user.has_permission?(:edit_profile, group) %> |
16 | + <%= button 'menu-ctrl-panel', _('Control panel of this group'), group.admin_url %> | ||
17 | + <% end %> | ||
16 | <%= button 'menu-logout', _('Leave community'), group.leave_url(true), :class => 'leave-community' %> | 18 | <%= button 'menu-logout', _('Leave community'), group.leave_url(true), :class => 'leave-community' %> |
17 | <% if (group.community? && user.has_permission?(:destroy_profile, group)) %> | 19 | <% if (group.community? && user.has_permission?(:destroy_profile, group)) %> |
18 | <%= button 'delete', _('Remove'), { :controller => 'profile_editor', :action => 'destroy_profile', :profile => group.identifier } %> | 20 | <%= button 'delete', _('Remove'), { :controller => 'profile_editor', :action => 'destroy_profile', :profile => group.identifier } %> |
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +class RemoveOrphanProfiles < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + profiles = Profile.joins('LEFT JOIN environments ON profiles.environment_id=environments.id').where('environments.id IS NULL') | ||
4 | + profiles.map(&:destroy) | ||
5 | + end | ||
6 | + | ||
7 | + def self.down | ||
8 | + say 'This migration can not be reverted.' | ||
9 | + end | ||
10 | +end |
debian/changelog
1 | +noosfero (0.45.0~rc20131202153818) squeeze-test; urgency=low | ||
2 | + | ||
3 | + * 0.45.0 RC2 | ||
4 | + | ||
5 | + -- Rodrigo Souto <rodrigo@colivre.coop.br> Mon, 02 Dec 2013 15:38:28 -0300 | ||
6 | + | ||
7 | +noosfero (0.44.6) unstable; urgency=low | ||
8 | + | ||
9 | + * 0.44.5 Addendum | ||
10 | + | ||
11 | + -- Rodrigo Souto <rodrigo@colivre.coop.br> Wed, 27 Nov 2013 16:45:02 -0300 | ||
12 | + | ||
13 | +noosfero (0.44.5) unstable; urgency=low | ||
14 | + | ||
15 | + * Bugfix release | ||
16 | + | ||
17 | + -- Rodrigo Souto <rodrigo@colivre.coop.br> Tue, 26 Nov 2013 17:39:39 -0300 | ||
18 | + | ||
1 | noosfero (0.44.4) unstable; urgency=low | 19 | noosfero (0.44.4) unstable; urgency=low |
2 | 20 | ||
3 | * Bugfix release | 21 | * Bugfix release |
features/manage_products.feature
@@ -9,7 +9,7 @@ Feature: manage products | @@ -9,7 +9,7 @@ Feature: manage products | ||
9 | And the following enterprises | 9 | And the following enterprises |
10 | | identifier | owner | name | enabled | | 10 | | identifier | owner | name | enabled | |
11 | | redemoinho | joaosilva | Rede Moinho | true | | 11 | | redemoinho | joaosilva | Rede Moinho | true | |
12 | - And feature "products_for_enterprises" is enabled on environment | 12 | + And feature "products_for_enterprises" is enabled on environment |
13 | 13 | ||
14 | Scenario: display "create new product" button | 14 | Scenario: display "create new product" button |
15 | Given I am logged in as "joaosilva" | 15 | Given I am logged in as "joaosilva" |
gitignore.example
lib/needs_profile.rb
@@ -24,7 +24,7 @@ module NeedsProfile | @@ -24,7 +24,7 @@ module NeedsProfile | ||
24 | @profile ||= environment.profiles.find_by_identifier(params[:profile]) | 24 | @profile ||= environment.profiles.find_by_identifier(params[:profile]) |
25 | if @profile | 25 | if @profile |
26 | profile_hostname = @profile.hostname | 26 | profile_hostname = @profile.hostname |
27 | - if profile_hostname && request.host == @environment.default_hostname | 27 | + if profile_hostname && profile_hostname != request.host |
28 | params.delete(:profile) | 28 | params.delete(:profile) |
29 | redirect_to(Noosfero.url_options.merge(params).merge(:host => profile_hostname)) | 29 | redirect_to(Noosfero.url_options.merge(params).merge(:host => profile_hostname)) |
30 | end | 30 | end |
lib/noosfero.rb
@@ -3,7 +3,7 @@ require 'fast_gettext' | @@ -3,7 +3,7 @@ require 'fast_gettext' | ||
3 | 3 | ||
4 | module Noosfero | 4 | module Noosfero |
5 | PROJECT = 'noosfero' | 5 | PROJECT = 'noosfero' |
6 | - VERSION = '0.44.4' | 6 | + VERSION = '0.45.0~rc20131202153818' |
7 | 7 | ||
8 | def self.pattern_for_controllers_in_directory(dir) | 8 | def self.pattern_for_controllers_in_directory(dir) |
9 | disjunction = controllers_in_directory(dir).join('|') | 9 | disjunction = controllers_in_directory(dir).join('|') |
plugins/pg_search/lib/ext/active_record.rb
@@ -2,8 +2,11 @@ require_dependency 'active_record' | @@ -2,8 +2,11 @@ require_dependency 'active_record' | ||
2 | 2 | ||
3 | class ActiveRecord::Base | 3 | class ActiveRecord::Base |
4 | def self.pg_search_plugin_search(query) | 4 | def self.pg_search_plugin_search(query) |
5 | + query.gsub!(/\|/,' ') | ||
6 | + formatted_query = query.split.map{|w| w += ":*"}.join('|') | ||
7 | + | ||
5 | if defined?(self::SEARCHABLE_FIELDS) | 8 | if defined?(self::SEARCHABLE_FIELDS) |
6 | - where("to_tsvector('simple', #{pg_search_plugin_fields}) @@ to_tsquery('#{query}:*')") | 9 | + where("to_tsvector('simple', #{pg_search_plugin_fields}) @@ to_tsquery('#{formatted_query}')") |
7 | else | 10 | else |
8 | raise "No searchable fields defined for #{self.name}" | 11 | raise "No searchable fields defined for #{self.name}" |
9 | end | 12 | end |
plugins/pg_search/lib/pg_search_plugin.rb
@@ -9,8 +9,9 @@ class PgSearchPlugin < Noosfero::Plugin | @@ -9,8 +9,9 @@ class PgSearchPlugin < Noosfero::Plugin | ||
9 | end | 9 | end |
10 | 10 | ||
11 | def find_by_contents(asset, scope, query, paginate_options={}, options={}) | 11 | def find_by_contents(asset, scope, query, paginate_options={}, options={}) |
12 | - return if query.blank? | ||
13 | - {:results => scope.pg_search_plugin_search(query).paginate(paginate_options)} | 12 | + scope = scope.pg_search_plugin_search(query) unless query.blank? |
13 | + scope = scope.send(options[:filter]) unless options[:filter] | ||
14 | + {:results => scope.paginate(paginate_options)} | ||
14 | end | 15 | end |
15 | 16 | ||
16 | end | 17 | end |
plugins/pg_search/test/unit/pg_search_plugin_test.rb
@@ -14,6 +14,13 @@ class PgSearchPluginTest < ActiveSupport::TestCase | @@ -14,6 +14,13 @@ class PgSearchPluginTest < ActiveSupport::TestCase | ||
14 | assert_includes search(Profile, 'water'), profile | 14 | assert_includes search(Profile, 'water'), profile |
15 | end | 15 | end |
16 | 16 | ||
17 | + should 'locate one or more profiles' do | ||
18 | + profile1 = fast_create(Profile, :identifier => 'administrator') | ||
19 | + profile2 = fast_create(Profile, :identifier => 'debugger') | ||
20 | + assert_includes search(Profile, 'admin deb'), profile1 | ||
21 | + assert_includes search(Profile, 'admin deb'), profile2 | ||
22 | + end | ||
23 | + | ||
17 | # TODO This feature is available only on Postgresql 9.0 | 24 | # TODO This feature is available only on Postgresql 9.0 |
18 | # http://www.postgresql.org/docs/9.0/static/unaccent.html | 25 | # http://www.postgresql.org/docs/9.0/static/unaccent.html |
19 | # should 'ignore accents' do | 26 | # should 'ignore accents' do |
plugins/shopping_cart/controllers/shopping_cart_plugin_controller.rb
@@ -94,10 +94,12 @@ class ShoppingCartPluginController < PublicController | @@ -94,10 +94,12 @@ class ShoppingCartPluginController < PublicController | ||
94 | end | 94 | end |
95 | 95 | ||
96 | def buy | 96 | def buy |
97 | - @cart = cart | ||
98 | - @enterprise = environment.enterprises.find(cart[:enterprise_id]) | ||
99 | - @settings = Noosfero::Plugin::Settings.new(@enterprise, ShoppingCartPlugin) | ||
100 | - render :layout => false | 97 | + if validate_cart_presence |
98 | + @cart = cart | ||
99 | + @enterprise = environment.enterprises.find(cart[:enterprise_id]) | ||
100 | + @settings = Noosfero::Plugin::Settings.new(@enterprise, ShoppingCartPlugin) | ||
101 | + render :layout => false | ||
102 | + end | ||
101 | end | 103 | end |
102 | 104 | ||
103 | def send_request | 105 | def send_request |
plugins/shopping_cart/controllers/shopping_cart_plugin_myprofile_controller.rb
@@ -63,7 +63,7 @@ class ShoppingCartPluginMyprofileController < MyProfileController | @@ -63,7 +63,7 @@ class ShoppingCartPluginMyprofileController < MyProfileController | ||
63 | 63 | ||
64 | def treat_delivery_options(params) | 64 | def treat_delivery_options(params) |
65 | result = {} | 65 | result = {} |
66 | - return result if params.nil? || params[:delivery_options].nil? | 66 | + return result if params.nil? || params[:options].nil? |
67 | params[:options].size.times do |counter| | 67 | params[:options].size.times do |counter| |
68 | if params[:options][counter].present? && params[:prices][counter].present? | 68 | if params[:options][counter].present? && params[:prices][counter].present? |
69 | result[params[:options][counter]] = params[:prices][counter] | 69 | result[params[:options][counter]] = params[:prices][counter] |
plugins/shopping_cart/test/functional/shopping_cart_plugin_controller_test.rb
@@ -187,6 +187,12 @@ class ShoppingCartPluginControllerTest < ActionController::TestCase | @@ -187,6 +187,12 @@ class ShoppingCartPluginControllerTest < ActionController::TestCase | ||
187 | assert !cart?, "cart expected to be empty!" | 187 | assert !cart?, "cart expected to be empty!" |
188 | end | 188 | end |
189 | 189 | ||
190 | + should 'not allow buy without any cart' do | ||
191 | + get :buy | ||
192 | + assert !json_response[:ok] | ||
193 | + assert_equal 2, json_response['error']['code'] | ||
194 | + end | ||
195 | + | ||
190 | private | 196 | private |
191 | 197 | ||
192 | def json_response | 198 | def json_response |
plugins/shopping_cart/test/functional/shopping_cart_plugin_myprofile_controller_test.rb
@@ -51,6 +51,14 @@ class ShoppingCartPluginMyprofileControllerTest < ActionController::TestCase | @@ -51,6 +51,14 @@ class ShoppingCartPluginMyprofileControllerTest < ActionController::TestCase | ||
51 | assert settings.delivery_price == price | 51 | assert settings.delivery_price == price |
52 | end | 52 | end |
53 | 53 | ||
54 | + should 'be able to choose delivery_options' do | ||
55 | + delivery_options = {:options => ['car', 'bike'], :prices => ['20', '5']} | ||
56 | + post :edit, :profile => enterprise.identifier, :settings => {:delivery_options => delivery_options} | ||
57 | + | ||
58 | + assert_equal '20', settings.delivery_options['car'] | ||
59 | + assert_equal '5', settings.delivery_options['bike'] | ||
60 | + end | ||
61 | + | ||
54 | should 'filter the reports correctly' do | 62 | should 'filter the reports correctly' do |
55 | another_enterprise = fast_create(Enterprise) | 63 | another_enterprise = fast_create(Enterprise) |
56 | po1 = ShoppingCartPlugin::PurchaseOrder.create!(:seller => enterprise, :status => ShoppingCartPlugin::PurchaseOrder::Status::OPENED) | 64 | po1 = ShoppingCartPlugin::PurchaseOrder.create!(:seller => enterprise, :status => ShoppingCartPlugin::PurchaseOrder::Status::OPENED) |
plugins/solr/lib/ext/article.rb
@@ -24,7 +24,8 @@ class Article | @@ -24,7 +24,8 @@ class Article | ||
24 | {:slug => :text}, {:body => :text}, | 24 | {:slug => :text}, {:body => :text}, |
25 | {:abstract => :text}, {:filename => :text}, | 25 | {:abstract => :text}, {:filename => :text}, |
26 | # filtered fields | 26 | # filtered fields |
27 | - {:solr_plugin_public => :boolean}, {:environment_id => :integer}, | 27 | + {:solr_plugin_public => :boolean}, {:published => :boolean}, |
28 | + {:environment_id => :integer}, | ||
28 | {:profile_id => :integer}, :language, | 29 | {:profile_id => :integer}, :language, |
29 | {:solr_plugin_category_filter => :integer}, | 30 | {:solr_plugin_category_filter => :integer}, |
30 | # ordered/query-boosted fields | 31 | # ordered/query-boosted fields |
plugins/solr/lib/ext/profile.rb
@@ -28,7 +28,7 @@ class Profile | @@ -28,7 +28,7 @@ class Profile | ||
28 | {:solr_plugin_category_filter => :integer}, | 28 | {:solr_plugin_category_filter => :integer}, |
29 | # ordered/query-boosted fields | 29 | # ordered/query-boosted fields |
30 | {:solr_plugin_name_sortable => :string}, {:user_id => :integer}, | 30 | {:solr_plugin_name_sortable => :string}, {:user_id => :integer}, |
31 | - :enabled, :active, :validated, :public_profile, | 31 | + :enabled, :active, :validated, :public_profile, :visible, |
32 | {:lat => :float}, {:lng => :float}, | 32 | {:lat => :float}, {:lng => :float}, |
33 | :updated_at, :created_at, | 33 | :updated_at, :created_at, |
34 | ], | 34 | ], |
plugins/solr/lib/solr_plugin.rb
@@ -18,16 +18,71 @@ class SolrPlugin < Noosfero::Plugin | @@ -18,16 +18,71 @@ class SolrPlugin < Noosfero::Plugin | ||
18 | true | 18 | true |
19 | end | 19 | end |
20 | 20 | ||
21 | + def solr_search? empty_query, klass | ||
22 | + not empty_query or klass == Product | ||
23 | + end | ||
24 | + | ||
21 | def find_by_contents(asset, scope, query, paginate_options={}, options={}) | 25 | def find_by_contents(asset, scope, query, paginate_options={}, options={}) |
22 | klass = asset_class(asset) | 26 | klass = asset_class(asset) |
23 | - category = options.delete(:category) | ||
24 | - filter = options.delete(:filter) | 27 | + category = options[:category] |
28 | + empty_query = empty_query? query, category | ||
25 | 29 | ||
26 | - return if empty_query?(query, category) && klass != Product | 30 | + unless solr_search? empty_query, klass |
31 | + return options[:filter] ? {:results => scope.send(options[:filter]).paginate(paginate_options)} : nil | ||
32 | + end | ||
27 | 33 | ||
28 | solr_options = solr_options(class_asset(klass), category) | 34 | solr_options = solr_options(class_asset(klass), category) |
29 | - solr_options.merge!(products_options(user)) if klass == Product && empty_query?(query, category) | ||
30 | - klass.find_by_contents(query, paginate_options, solr_options.merge(options)) | 35 | + solr_options[:filter_queries] ||= [] |
36 | + solr_options[:filter_queries] += scopes_to_solr_filters scope, klass, options | ||
37 | + solr_options.merge! products_options(user) if klass == Product and empty_query | ||
38 | + solr_options.merge! options.except(:category, :filter) | ||
39 | + | ||
40 | + scope.find_by_contents query, paginate_options, solr_options | ||
41 | + end | ||
42 | + | ||
43 | + protected | ||
44 | + | ||
45 | + def scopes_to_solr_filters scope, klass = nil, options = {} | ||
46 | + filter_queries = [] | ||
47 | + klass ||= scope.base_class | ||
48 | + solr_fields = klass.configuration[:solr_fields].keys | ||
49 | + scopes_applied = scope.scopes_applied.dup rescue [] #rescue association and class direct filtering | ||
50 | + | ||
51 | + scope.current_scoped_methods[:create].each do |attr, value| | ||
52 | + next unless solr_fields.include? attr.to_sym | ||
53 | + | ||
54 | + # if the filter is present here, then prefer it | ||
55 | + scopes_applied.reject!{ |name| name == attr.to_sym } | ||
56 | + | ||
57 | + filter_queries << "#{attr}:#{value}" | ||
58 | + end | ||
59 | + | ||
60 | + scopes_applied.each do |name| | ||
61 | + next if name.to_s == options[:filter].to_s | ||
62 | + | ||
63 | + has_value = name === Hash | ||
64 | + if has_value | ||
65 | + name, args = name.keys.first, name.values.first | ||
66 | + value = args.first | ||
67 | + end | ||
68 | + | ||
69 | + related_field = nil | ||
70 | + related_field = name if solr_fields.include? name | ||
71 | + related_field = "solr_plugin_#{name}" if solr_fields.include? :"solr_plugin_#{name}" | ||
72 | + | ||
73 | + if has_value | ||
74 | + if related_field | ||
75 | + filter_queries << "#{related_field}:#{value}" | ||
76 | + else | ||
77 | + filter_queries << klass.send("solr_filter_#{name}", *args) | ||
78 | + end | ||
79 | + else | ||
80 | + raise "Undeclared solr field for scope #{name}" if related_field.nil? | ||
81 | + filter_queries << "#{related_field}:true" | ||
82 | + end | ||
83 | + end | ||
84 | + | ||
85 | + filter_queries | ||
31 | end | 86 | end |
32 | 87 | ||
33 | def method_missing method, *args, &block | 88 | def method_missing method, *args, &block |
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +require "#{File.dirname(__FILE__)}/../../test_helper" | ||
2 | + | ||
3 | +class SolrPlugin::PluginTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @plugin = SolrPlugin.new | ||
7 | + end | ||
8 | + attr_reader :plugin | ||
9 | + | ||
10 | + should 'convert scopes to solr filters' do | ||
11 | + person = create_user('test').person | ||
12 | + result = plugin.send :scopes_to_solr_filters, person.files.public.published | ||
13 | + assert_equal result, ["profile_id:#{person.id}", "published:'true'", "solr_plugin_public:true"] | ||
14 | + end | ||
15 | + | ||
16 | +end |
plugins/solr/vendor/plugins/named_scope_with_applied_names/init.rb
0 → 100644
@@ -0,0 +1,57 @@ | @@ -0,0 +1,57 @@ | ||
1 | +require_dependency 'active_record/named_scope' | ||
2 | + | ||
3 | +if Rails::VERSION::STRING < "2.3.99" | ||
4 | + | ||
5 | + module ::ActiveRecord | ||
6 | + | ||
7 | + module NamedScope | ||
8 | + | ||
9 | + module ClassMethods | ||
10 | + | ||
11 | + def named_scope_with_applied_names name, options = {}, &block | ||
12 | + named_scope_without_applied_names name, options, &block | ||
13 | + | ||
14 | + name = name.to_sym | ||
15 | + scopes[name] = lambda do |parent_scope, *args| | ||
16 | + scope = Scope.new(parent_scope, case options | ||
17 | + when Hash | ||
18 | + options | ||
19 | + when Proc | ||
20 | + if self.model_name != parent_scope.model_name | ||
21 | + options.bind(parent_scope).call(*args) | ||
22 | + else | ||
23 | + options.call(*args) | ||
24 | + end | ||
25 | + end, &block) | ||
26 | + scope.scope_name = name | ||
27 | + scope | ||
28 | + end | ||
29 | + end | ||
30 | + alias_method_chain :named_scope, :applied_names | ||
31 | + end | ||
32 | + | ||
33 | + class Scope | ||
34 | + attr_accessor :scope_name, :scopes_applied | ||
35 | + | ||
36 | + def initialize_with_applied_names proxy_scope, options, &block | ||
37 | + initialize_without_applied_names proxy_scope, options, &block | ||
38 | + self.scopes_applied ||= [] | ||
39 | + self.scopes_applied += proxy_scope.send :scopes_applied if Scope === proxy_scope | ||
40 | + | ||
41 | + # unrelated bugfix: use if instead of unless | ||
42 | + if (Scope === proxy_scope || ActiveRecord::Associations::AssociationCollection === proxy_scope) | ||
43 | + @current_scoped_methods_when_defined = proxy_scope.send(:current_scoped_methods) | ||
44 | + end | ||
45 | + end | ||
46 | + alias_method_chain :initialize, :applied_names | ||
47 | + | ||
48 | + def scope_name= name | ||
49 | + @scope_name = name | ||
50 | + self.scopes_applied << @scope_name | ||
51 | + end | ||
52 | + | ||
53 | + end | ||
54 | + | ||
55 | + end | ||
56 | + end | ||
57 | +end |
test/functional/catalog_controller_test.rb
@@ -235,4 +235,18 @@ class CatalogControllerTest < ActionController::TestCase | @@ -235,4 +235,18 @@ class CatalogControllerTest < ActionController::TestCase | ||
235 | assert_equal [pc2, pc1, pc4, pc3], assigns(:categories) | 235 | assert_equal [pc2, pc1, pc4, pc3], assigns(:categories) |
236 | end | 236 | end |
237 | 237 | ||
238 | + should 'use price_detail name instead of production_cost name straight' do | ||
239 | + p1 = fast_create(Product, :product_category_id => @product_category.id, :enterprise_id => @enterprise.id) | ||
240 | + p2 = fast_create(Product, :product_category_id => @product_category.id, :enterprise_id => @enterprise.id) | ||
241 | + Product.any_instance.stubs(:price_described?).returns(true) | ||
242 | + production_cost = fast_create(ProductionCost) | ||
243 | + pd1 = PriceDetail.create!(:product => p1, :production_cost => production_cost) | ||
244 | + pd2 = PriceDetail.create!(:product => p2) | ||
245 | + | ||
246 | + get :index, :profile => @enterprise.identifier | ||
247 | + | ||
248 | + assert_tag :tag => 'div', :attributes => {:class => 'search-product-input-name'}, :content => production_cost.name | ||
249 | + assert_tag :tag => 'div', :attributes => {:class => 'search-product-input-name'}, :content => 'Other costs' | ||
250 | + end | ||
251 | + | ||
238 | end | 252 | end |
test/functional/content_viewer_controller_test.rb
@@ -64,7 +64,20 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -64,7 +64,20 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
64 | assert_response :missing | 64 | assert_response :missing |
65 | end | 65 | end |
66 | 66 | ||
67 | - should 'produce a download-like when article is not text/html' do | 67 | + should 'produce a download-link when article is a uploaded file' do |
68 | + profile = create_user('someone').person | ||
69 | + html = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/500.html', 'text/html'), :profile => profile | ||
70 | + html.save! | ||
71 | + | ||
72 | + get :view_page, :profile => 'someone', :page => [ '500.html' ] | ||
73 | + | ||
74 | + assert_response :success | ||
75 | + assert_match /^text\/html/, @response.headers['Content-Type'] | ||
76 | + assert @response.headers['Content-Disposition'].present? | ||
77 | + assert_match /attachment/, @response.headers['Content-Disposition'] | ||
78 | + end | ||
79 | + | ||
80 | + should 'produce a download-link when article is not text/html' do | ||
68 | 81 | ||
69 | # for example, RSS feeds | 82 | # for example, RSS feeds |
70 | profile = create_user('someone').person | 83 | profile = create_user('someone').person |
@@ -1254,7 +1267,7 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1254,7 +1267,7 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1254 | 1267 | ||
1255 | get 'view_page', :profile => profile.identifier, :page => article.path.split('/') | 1268 | get 'view_page', :profile => profile.identifier, :page => article.path.split('/') |
1256 | assert_tag :tag => 'a', :attributes => { :href => "/#{profile.identifier}/#{article.path}?comment_page=2", :rel => 'next' } | 1269 | assert_tag :tag => 'a', :attributes => { :href => "/#{profile.identifier}/#{article.path}?comment_page=2", :rel => 'next' } |
1257 | - end | 1270 | + end |
1258 | 1271 | ||
1259 | should 'not escape acceptable HTML in list of blog posts' do | 1272 | should 'not escape acceptable HTML in list of blog posts' do |
1260 | login_as('testinguser') | 1273 | login_as('testinguser') |
@@ -1274,9 +1287,7 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1274,9 +1287,7 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1274 | should 'display link to download of non-recognized file types on its page' do | 1287 | should 'display link to download of non-recognized file types on its page' do |
1275 | file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'bin/unknown'), :profile => profile) | 1288 | file = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/test.txt', 'bin/unknown'), :profile => profile) |
1276 | get :view_page, file.url.merge(:view=>:true) | 1289 | get :view_page, file.url.merge(:view=>:true) |
1277 | - assert_tag :tag => 'a', | ||
1278 | - :content => file.filename, | ||
1279 | - :attributes => { :href => file.public_filename } | 1290 | + assert_match /this is a sample text file/, @response.body |
1280 | end | 1291 | end |
1281 | 1292 | ||
1282 | end | 1293 | end |
test/functional/memberships_controller_test.rb
@@ -6,7 +6,7 @@ require 'memberships_controller' | @@ -6,7 +6,7 @@ require 'memberships_controller' | ||
6 | class MembershipsController; def rescue_action(e) raise e end; end | 6 | class MembershipsController; def rescue_action(e) raise e end; end |
7 | 7 | ||
8 | class MembershipsControllerTest < ActionController::TestCase | 8 | class MembershipsControllerTest < ActionController::TestCase |
9 | - | 9 | + |
10 | include ApplicationHelper | 10 | include ApplicationHelper |
11 | 11 | ||
12 | def setup | 12 | def setup |
@@ -22,7 +22,7 @@ class MembershipsControllerTest < ActionController::TestCase | @@ -22,7 +22,7 @@ class MembershipsControllerTest < ActionController::TestCase | ||
22 | def test_local_files_reference | 22 | def test_local_files_reference |
23 | assert_local_files_reference :get, :index, :profile => profile.identifier | 23 | assert_local_files_reference :get, :index, :profile => profile.identifier |
24 | end | 24 | end |
25 | - | 25 | + |
26 | def test_valid_xhtml | 26 | def test_valid_xhtml |
27 | assert_valid_xhtml | 27 | assert_valid_xhtml |
28 | end | 28 | end |
@@ -258,4 +258,23 @@ class MembershipsControllerTest < ActionController::TestCase | @@ -258,4 +258,23 @@ class MembershipsControllerTest < ActionController::TestCase | ||
258 | assert_tag :tag => 'a', :attributes => { :class => 'button icon-cancel with-text', :href => back_to } | 258 | assert_tag :tag => 'a', :attributes => { :class => 'button icon-cancel with-text', :href => back_to } |
259 | end | 259 | end |
260 | 260 | ||
261 | + should 'only display control panel link to members with permission' do | ||
262 | + c1 = fast_create(Community, :name => 'My own community') | ||
263 | + c2 = fast_create(Community, :name => 'Not my community') | ||
264 | + | ||
265 | + owner = fast_create(Person) | ||
266 | + c2.add_admin(owner) | ||
267 | + | ||
268 | + person = Person['testuser'] | ||
269 | + c1.add_admin(person) | ||
270 | + c2.add_member(person) | ||
271 | + | ||
272 | + login_as('testuser') | ||
273 | + get :index, :profile => 'testuser' | ||
274 | + | ||
275 | + assert_template 'index' | ||
276 | + assert_no_tag :tag => 'a', :attributes => { :href => "/myprofile/#{c2.identifier}" } | ||
277 | + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{c1.identifier}" } | ||
278 | + end | ||
279 | + | ||
261 | end | 280 | end |
test/functional/profile_controller_test.rb
@@ -1383,6 +1383,41 @@ class ProfileControllerTest < ActionController::TestCase | @@ -1383,6 +1383,41 @@ class ProfileControllerTest < ActionController::TestCase | ||
1383 | assert_equal "Comment successfully added.", assigns(:message) | 1383 | assert_equal "Comment successfully added.", assigns(:message) |
1384 | end | 1384 | end |
1385 | 1385 | ||
1386 | + should 'display comment in wall if user was removed' do | ||
1387 | + UserStampSweeper.any_instance.stubs(:current_user).returns(profile) | ||
1388 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') | ||
1389 | + to_be_removed = create_user('removed_user').person | ||
1390 | + comment = Comment.create!(:author => to_be_removed, :title => 'Test Comment', :body => 'My author does not exist =(', :source_id => article.id, :source_type => 'Article') | ||
1391 | + to_be_removed.destroy | ||
1392 | + | ||
1393 | + login_as(profile.identifier) | ||
1394 | + get :index, :profile => profile.identifier | ||
1395 | + | ||
1396 | + assert_tag :tag => 'span', :content => '(removed user)', :attributes => {:class => 'comment-user-status comment-user-status-wall icon-user-removed'} | ||
1397 | + end | ||
1398 | + | ||
1399 | + should 'not display spam comments in wall' do | ||
1400 | + UserStampSweeper.any_instance.stubs(:current_user).returns(profile) | ||
1401 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about spam\'s nutritional attributes') | ||
1402 | + comment = Comment.create!(:author => profile, :title => 'Test Comment', :body => 'This article makes me hungry', :source_id => article.id, :source_type => 'Article') | ||
1403 | + comment.spam! | ||
1404 | + login_as(profile.identifier) | ||
1405 | + get :index, :profile => profile.identifier | ||
1406 | + | ||
1407 | + assert !/This article makes me hungry/.match(@response.body), 'Spam comment was shown!' | ||
1408 | + end | ||
1409 | + | ||
1410 | + should 'display comment in wall from non logged users' do | ||
1411 | + UserStampSweeper.any_instance.stubs(:current_user).returns(profile) | ||
1412 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') | ||
1413 | + comment = Comment.create!(:name => 'outside user', :email => 'outside@localhost.localdomain', :title => 'Test Comment', :body => 'My author does not exist =(', :source_id => article.id, :source_type => 'Article') | ||
1414 | + | ||
1415 | + login_as(profile.identifier) | ||
1416 | + get :index, :profile => profile.identifier | ||
1417 | + | ||
1418 | + assert_tag :tag => 'span', :content => '(unauthenticated user)', :attributes => {:class => 'comment-user-status comment-user-status-wall icon-user-unknown'} | ||
1419 | + end | ||
1420 | + | ||
1386 | should 'add locale on mailing' do | 1421 | should 'add locale on mailing' do |
1387 | community = fast_create(Community) | 1422 | community = fast_create(Community) |
1388 | create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) | 1423 | create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) |
test/functional/profile_editor_controller_test.rb
@@ -624,6 +624,7 @@ class ProfileEditorControllerTest < ActionController::TestCase | @@ -624,6 +624,7 @@ class ProfileEditorControllerTest < ActionController::TestCase | ||
624 | 624 | ||
625 | profile.domains << Domain.new(:name => 'myowndomain.net') | 625 | profile.domains << Domain.new(:name => 'myowndomain.net') |
626 | profile.environment.domains << Domain.new(:name => 'myenv.net') | 626 | profile.environment.domains << Domain.new(:name => 'myenv.net') |
627 | + ActionController::TestRequest.any_instance.stubs(:host).returns(profile.hostname) | ||
627 | 628 | ||
628 | get :edit, :profile => profile.identifier | 629 | get :edit, :profile => profile.identifier |
629 | assert_tag :tag => 'select', :attributes => { :name => 'profile_data[preferred_domain_id]' }, :descendant => { :tag => "option", :content => 'myowndomain.net' } | 630 | assert_tag :tag => 'select', :attributes => { :name => 'profile_data[preferred_domain_id]' }, :descendant => { :tag => "option", :content => 'myowndomain.net' } |
@@ -639,6 +640,7 @@ class ProfileEditorControllerTest < ActionController::TestCase | @@ -639,6 +640,7 @@ class ProfileEditorControllerTest < ActionController::TestCase | ||
639 | 640 | ||
640 | profile.domains << Domain.new(:name => 'myowndomain.net') | 641 | profile.domains << Domain.new(:name => 'myowndomain.net') |
641 | profile.environment.domains << Domain.new(:name => 'myenv.net') | 642 | profile.environment.domains << Domain.new(:name => 'myenv.net') |
643 | + ActionController::TestRequest.any_instance.stubs(:host).returns(profile.hostname) | ||
642 | 644 | ||
643 | get :edit, :profile => profile.identifier | 645 | get :edit, :profile => profile.identifier |
644 | assert_tag :tag => "select", :attributes => { :name => 'profile_data[preferred_domain_id]'}, :descendant => { :tag => 'option', :content => '<Select domain>', :attributes => { :value => '' } } | 646 | assert_tag :tag => "select", :attributes => { :name => 'profile_data[preferred_domain_id]'}, :descendant => { :tag => 'option', :content => '<Select domain>', :attributes => { :value => '' } } |
@@ -978,4 +980,13 @@ class ProfileEditorControllerTest < ActionController::TestCase | @@ -978,4 +980,13 @@ class ProfileEditorControllerTest < ActionController::TestCase | ||
978 | assert_equal({}, person.reload.fields_privacy) | 980 | assert_equal({}, person.reload.fields_privacy) |
979 | end | 981 | end |
980 | 982 | ||
983 | + should 'not redirect if the profile_hostname is the same as environment hostname' do | ||
984 | + Person.any_instance.stubs(:hostname).returns('hostname.org') | ||
985 | + Environment.any_instance.stubs(:default_hostname).returns('hostname.org') | ||
986 | + ActionController::TestRequest.any_instance.stubs(:host).returns('hostname.org') | ||
987 | + get :index, :profile => profile.identifier | ||
988 | + assert_response :success | ||
989 | + end | ||
990 | + | ||
991 | + | ||
981 | end | 992 | end |
test/unit/application_helper_test.rb
@@ -143,6 +143,18 @@ class ApplicationHelperTest < ActiveSupport::TestCase | @@ -143,6 +143,18 @@ class ApplicationHelperTest < ActiveSupport::TestCase | ||
143 | assert_tag_in_string rolename_for(member2, community), :tag => 'span', :content => 'Profile Member' | 143 | assert_tag_in_string rolename_for(member2, community), :tag => 'span', :content => 'Profile Member' |
144 | end | 144 | end |
145 | 145 | ||
146 | + should 'rolenames for a member admin' do | ||
147 | + member1 = create_user('usertest1').person | ||
148 | + member2 = create_user('usertest2').person | ||
149 | + community = fast_create(Community, :name => 'new community', :identifier => 'new-community', :environment_id => Environment.default.id) | ||
150 | + community.add_member(member1) | ||
151 | + # member2 is both a admin and a member | ||
152 | + community.add_member(member2) | ||
153 | + community.add_admin(member2) | ||
154 | + assert_tag_in_string rolename_for(member2, community), :tag => 'span', :content => 'Profile Member' | ||
155 | + assert_tag_in_string rolename_for(member2, community), :tag => 'span', :content => 'Profile Administrator' | ||
156 | + end | ||
157 | + | ||
146 | should 'get theme from environment by default' do | 158 | should 'get theme from environment by default' do |
147 | @environment = mock | 159 | @environment = mock |
148 | @environment.stubs(:theme).returns('my-environment-theme') | 160 | @environment.stubs(:theme).returns('my-environment-theme') |
test/unit/environment_test.rb
@@ -293,21 +293,6 @@ class EnvironmentTest < ActiveSupport::TestCase | @@ -293,21 +293,6 @@ class EnvironmentTest < ActiveSupport::TestCase | ||
293 | assert_equal blocks - env_blocks, Block.count | 293 | assert_equal blocks - env_blocks, Block.count |
294 | end | 294 | end |
295 | 295 | ||
296 | - should 'destroy templates' do | ||
297 | - env = fast_create(Environment) | ||
298 | - templates = [mock, mock, mock, mock] | ||
299 | - templates.each do |item| | ||
300 | - item.expects(:destroy) | ||
301 | - end | ||
302 | - | ||
303 | - env.stubs(:person_template).returns(templates[0]) | ||
304 | - env.stubs(:community_template).returns(templates[1]) | ||
305 | - env.stubs(:enterprise_template).returns(templates[2]) | ||
306 | - env.stubs(:inactive_enterprise_template).returns(templates[3]) | ||
307 | - | ||
308 | - env.destroy | ||
309 | - end | ||
310 | - | ||
311 | should 'have boxes and blocks upon creation' do | 296 | should 'have boxes and blocks upon creation' do |
312 | Environment.any_instance.stubs(:create_templates) # avoid creating templates, it's expensive | 297 | Environment.any_instance.stubs(:create_templates) # avoid creating templates, it's expensive |
313 | environment = Environment.create!(:name => 'a test environment') | 298 | environment = Environment.create!(:name => 'a test environment') |
test/unit/profile_test.rb
@@ -1901,4 +1901,11 @@ class ProfileTest < ActiveSupport::TestCase | @@ -1901,4 +1901,11 @@ class ProfileTest < ActiveSupport::TestCase | ||
1901 | assert !profile.may_display_location_to?(user) | 1901 | assert !profile.may_display_location_to?(user) |
1902 | end | 1902 | end |
1903 | 1903 | ||
1904 | + should 'destroy profile if its environment is destroyed' do | ||
1905 | + environment = fast_create(Environment) | ||
1906 | + profile = fast_create(Profile, :environment_id => environment.id) | ||
1907 | + | ||
1908 | + environment.destroy | ||
1909 | + assert_raise(ActiveRecord::RecordNotFound) {profile.reload} | ||
1910 | + end | ||
1904 | end | 1911 | end |
vendor/plugins/action_tracker_has_comments/init.rb
@@ -9,7 +9,18 @@ Rails.configuration.to_prepare do | @@ -9,7 +9,18 @@ Rails.configuration.to_prepare do | ||
9 | 9 | ||
10 | def conditions_for_comments | 10 | def conditions_for_comments |
11 | type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id]) | 11 | type, id = (self.target_type == 'Article' ? ['Article', self.target_id] : [self.class.to_s, self.id]) |
12 | - "source_type = '#{type}' AND source_id = '#{id}' AND reply_of_id IS NULL" | 12 | + "source_type = '#{type}' AND source_id = '#{id}' AND spam IS NOT TRUE AND reply_of_id IS NULL" |
13 | + end | ||
14 | + | ||
15 | + def comments_as_thread | ||
16 | + result = {} | ||
17 | + root = [] | ||
18 | + self.comments.each do |c| | ||
19 | + c.replies = [] | ||
20 | + result[c.id] ||= c | ||
21 | + c.reply_of_id.nil? ? root << c : result[c.reply_of_id].replies << c | ||
22 | + end | ||
23 | + root | ||
13 | end | 24 | end |
14 | 25 | ||
15 | end | 26 | end |