Commit bd4954d3143c452fee2a074571ffc66cbc2b2eda
Exists in
master
and in
22 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 |