Commit 67e8ceed271f41557f5b3e17725927058adf0fee

Authored by Rodrigo Souto
2 parents 0e26cea3 146786cb

Merge branch 'master' into pluginize-solr

INSTALL.varnish
@@ -45,6 +45,10 @@ Install the RPAF apache module (or skip this step if not using apache): @@ -45,6 +45,10 @@ Install the RPAF apache module (or skip this step if not using apache):
45 On manual installations, change "/etc/noosfero/*" to 45 On manual installations, change "/etc/noosfero/*" to
46 "{Rails.root}/etc/noosfero/*" 46 "{Rails.root}/etc/noosfero/*"
47 47
  48 +NOTE: it is very important that the *.vcl files are included in that order,
  49 +i.e. *first* include "varnish-noosfero.vcl", and *after*
  50 +"noosfero-accept-language.cvl".
  51 +
48 4c) Restart Varnish 52 4c) Restart Varnish
49 53
50 # invoke-rc.d varnish restart 54 # invoke-rc.d varnish restart
app/controllers/admin/environment_design_controller.rb
@@ -3,7 +3,7 @@ class EnvironmentDesignController < BoxOrganizerController @@ -3,7 +3,7 @@ class EnvironmentDesignController < BoxOrganizerController
3 protect 'edit_environment_design', :environment 3 protect 'edit_environment_design', :environment
4 4
5 def available_blocks 5 def available_blocks
6 - @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock ] 6 + @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
7 end 7 end
8 8
9 end 9 end
app/controllers/public/catalog_controller.rb
@@ -7,7 +7,7 @@ class CatalogController < PublicController @@ -7,7 +7,7 @@ class CatalogController < PublicController
7 def index 7 def index
8 @category = params[:level] ? ProductCategory.find(params[:level]) : nil 8 @category = params[:level] ? ProductCategory.find(params[:level]) : nil
9 @products = @profile.products.from_category(@category).paginate(:order => 'available desc, highlighted desc, name asc', :per_page => 9, :page => params[:page]) 9 @products = @profile.products.from_category(@category).paginate(:order => 'available desc, highlighted desc, name asc', :per_page => 9, :page => params[:page])
10 - @categories = ProductCategory.on_level(params[:level]) 10 + @categories = ProductCategory.on_level(params[:level]).order(:name)
11 end 11 end
12 12
13 protected 13 protected
app/helpers/catalog_helper.rb
@@ -21,7 +21,7 @@ module CatalogHelper @@ -21,7 +21,7 @@ module CatalogHelper
21 21
22 def category_sub_links(category) 22 def category_sub_links(category)
23 sub_categories = [] 23 sub_categories = []
24 - category.children.each do |sub_category| 24 + category.children.order(:name).each do |sub_category|
25 sub_categories << category_link(sub_category, true) 25 sub_categories << category_link(sub_category, true)
26 end 26 end
27 content_tag('ul', sub_categories) if sub_categories.size > 1 27 content_tag('ul', sub_categories) if sub_categories.size > 1
app/models/spammer_logger.rb
@@ -5,10 +5,10 @@ class SpammerLogger &lt; Logger @@ -5,10 +5,10 @@ class SpammerLogger &lt; Logger
5 def self.log(spammer_ip, object=nil) 5 def self.log(spammer_ip, object=nil)
6 if object 6 if object
7 if object.kind_of?(Comment) 7 if object.kind_of?(Comment)
8 - @logger << "[#{Time.now.strftime("%F %T %z")}] Comment-id: #{object.id} IP: #{spammer_ip}\n" 8 + @logger << "[#{Time.now.strftime('%F %T %z')}] Comment-id: #{object.id} IP: #{spammer_ip}\n"
9 end 9 end
10 else 10 else
11 - @logger << "[#{Time.now.strftime("%F %T %z")}] IP: #{spammer_ip}\n" 11 + @logger << "[#{Time.now.strftime('%F %T %z')}] IP: #{spammer_ip}\n"
12 end 12 end
13 end 13 end
14 14
app/models/tags_block.rb
@@ -20,7 +20,8 @@ class TagsBlock &lt; Block @@ -20,7 +20,8 @@ class TagsBlock &lt; Block
20 end 20 end
21 21
22 def content(args={}) 22 def content(args={})
23 - tags = owner.article_tags 23 + is_env = owner.class == Environment
  24 + tags = is_env ? owner.tag_counts : owner.article_tags
24 return '' if tags.empty? 25 return '' if tags.empty?
25 26
26 if limit 27 if limit
@@ -29,18 +30,28 @@ class TagsBlock &lt; Block @@ -29,18 +30,28 @@ class TagsBlock &lt; Block
29 tags_tmp.map{ |k,v| tags[k] = v } 30 tags_tmp.map{ |k,v| tags[k] = v }
30 end 31 end
31 32
  33 + url = is_env ? {:host=>owner.default_hostname, :controller=>'search', :action => 'tag'} :
  34 + owner.public_profile_url.merge(:controller => 'profile', :action => 'tags')
  35 + tagname_option = is_env ? :tag : :id
  36 +
32 block_title(title) + 37 block_title(title) +
33 "\n<div class='tag_cloud'>\n"+ 38 "\n<div class='tag_cloud'>\n"+
34 - tag_cloud( tags, :id,  
35 - owner.public_profile_url.merge(:controller => 'profile', :action => 'tags'),  
36 - :max_size => 16, :min_size => 9 ) + 39 + tag_cloud( tags, tagname_option, url, :max_size => 16, :min_size => 9 ) +
37 "\n</div><!-- end class='tag_cloud' -->\n"; 40 "\n</div><!-- end class='tag_cloud' -->\n";
38 end 41 end
39 42
40 def footer 43 def footer
41 - owner_id = owner.identifier  
42 - lambda do  
43 - link_to s_('tags|View all'), :profile => owner_id, :controller => 'profile', :action => 'tags' 44 + if owner.class == Environment
  45 + lambda do
  46 + link_to s_('tags|View all'),
  47 + :controller => 'search', :action => 'tags'
  48 + end
  49 + else
  50 + owner_id = owner.identifier
  51 + lambda do
  52 + link_to s_('tags|View all'),
  53 + :profile => owner_id, :controller => 'profile', :action => 'tags'
  54 + end
44 end 55 end
45 end 56 end
46 57
app/models/user.rb
@@ -15,7 +15,7 @@ class User &lt; ActiveRecord::Base @@ -15,7 +15,7 @@ class User &lt; ActiveRecord::Base
15 # FIXME ugly workaround 15 # FIXME ugly workaround
16 def self.human_attribute_name(attrib) 16 def self.human_attribute_name(attrib)
17 case attrib.to_sym 17 case attrib.to_sym
18 - when :login: return _('Username') 18 + when :login: return [_('Username'), _('Email')].join(' / ')
19 when :email: return _('e-Mail') 19 when :email: return _('e-Mail')
20 else _(self.superclass.human_attribute_name(attrib)) 20 else _(self.superclass.human_attribute_name(attrib))
21 end 21 end
@@ -116,10 +116,11 @@ class User &lt; ActiveRecord::Base @@ -116,10 +116,11 @@ class User &lt; ActiveRecord::Base
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 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)
121 environment ||= Environment.default 121 environment ||= Environment.default
122 - u = first :conditions => ['login = ? AND environment_id = ? AND activated_at IS NOT NULL', login, environment.id] # need to get the salt 122 + u = self.first :conditions => ['(login = ? OR email = ?) AND environment_id = ? AND activated_at IS NOT NULL',
  123 + login, login, environment.id] # need to get the salt
123 u && u.authenticated?(password) ? u : nil 124 u && u.authenticated?(password) ? u : nil
124 end 125 end
125 126
app/views/account/_signup_form.rhtml
@@ -32,7 +32,8 @@ @@ -32,7 +32,8 @@
32 <span id="signup-domain"><%= environment.default_hostname %>/</span> 32 <span id="signup-domain"><%= environment.default_hostname %>/</span>
33 <div id='signup-login'> 33 <div id='signup-login'>
34 <div id='signup-login-field' class='formfield'> 34 <div id='signup-login-field' class='formfield'>
35 - <%= required text_field(:user, :login, :id => 'user_login', :onchange => 'this.value = convToValidLogin(this.value);') %> 35 + <%= required text_field(:user, :login, :id => 'user_login',
  36 + :onchange => 'this.value = convToValidUsername(this.value);') %>
36 <div id='url-check'><p>&nbsp;</p></div> 37 <div id='url-check'><p>&nbsp;</p></div>
37 </div> 38 </div>
38 <%= content_tag(:small, _('Choose your login name carefully! It will be your network access and you will not be able to change it later.'), :id => 'signup-balloon') %> 39 <%= content_tag(:small, _('Choose your login name carefully! It will be your network access and you will not be able to change it later.'), :id => 'signup-balloon') %>
app/views/account/forgot_password.rhtml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 <% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %> 5 <% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %>
6 6
7 <%= f.text_field :login, 7 <%= f.text_field :login,
8 - :onchange => 'this.value = convToValidLogin( this.value )' %> 8 + :onchange => 'this.value = convToValidUsername( this.value )' %>
9 9
10 <%= f.text_field :email %> 10 <%= f.text_field :email %>
11 11
app/views/catalog/index.rhtml
@@ -7,13 +7,15 @@ @@ -7,13 +7,15 @@
7 7
8 <div class='l-sidebar-left-bar'> 8 <div class='l-sidebar-left-bar'>
9 <ul> 9 <ul>
10 - <% if @categories.size > 0 %> 10 + <% if @categories.present? %>
11 <% @categories.each do |category| %> 11 <% @categories.each do |category| %>
12 <%= category_link(category) %> 12 <%= category_link(category) %>
13 <%= category_sub_links(category) %> 13 <%= category_sub_links(category) %>
14 <% end %> 14 <% end %>
  15 + <% elsif @category.present? %>
  16 + <%= content_tag('li', _('There are no sub-categories for %s') % @category.name, :id => 'catalog-categories-notice') %>
15 <% else %> 17 <% else %>
16 - <%= content_tag('li', _('There are no sub-categories for %s') % @category.name, :style => 'color: #555753; padding-bottom: 0.5em;') %> 18 + <%= content_tag('li', _('There are no categories available.'), :id => 'catalog-categories-notice') %>
17 <% end %> 19 <% end %>
18 </ul> 20 </ul>
19 </div> 21 </div>
app/views/search/_image.html.erb
@@ -28,8 +28,9 @@ @@ -28,8 +28,9 @@
28 <div class="search-gallery-items"> 28 <div class="search-gallery-items">
29 <% r = image.children.find(:all, :order => :updated_at, :conditions => ['type = ?', 'UploadedFile']).last(3) %> 29 <% r = image.children.find(:all, :order => :updated_at, :conditions => ['type = ?', 'UploadedFile']).last(3) %>
30 <% if r.length > 0 %> 30 <% if r.length > 0 %>
31 - <% r.each do |i| %>  
32 - <%= link_to '', i.view_url, :class => "search-image-pic", :style => 'background-image: url(%s)'% i.public_filename(:thumb) %> 31 + <% r.each_index do |i| img = r[i] %>
  32 + <%= link_to '', img.view_url, :class => "search-image-pic pic-num#{i+1}",
  33 + :style => 'background-image: url(%s)'% img.public_filename(:thumb) %>
33 <% end %> 34 <% end %>
34 <% else %> 35 <% else %>
35 <div class="search-no-image"><span><%= _('No image') %></span></div> 36 <div class="search-no-image"><span><%= _('No image') %></span></div>
db/migrate/20130304200849_add_default_value_to_product_highlighted.rb 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +class AddDefaultValueToProductHighlighted < ActiveRecord::Migration
  2 + def self.up
  3 + change_column :products, :highlighted, :boolean, :default => false
  4 + execute('UPDATE products SET highlighted=(0>1) WHERE highlighted IS NULL;')
  5 + end
  6 +
  7 + def self.down
  8 + say 'This migraiton is not reversible!'
  9 + end
  10 +end
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # 9 #
10 # It's strongly recommended to check this file into your version control system. 10 # It's strongly recommended to check this file into your version control system.
11 11
12 -ActiveRecord::Schema.define(:version => 20130111232201) do 12 +ActiveRecord::Schema.define(:version => 20130304200849) do
13 13
14 create_table "abuse_reports", :force => true do |t| 14 create_table "abuse_reports", :force => true do |t|
15 t.integer "reporter_id" 15 t.integer "reporter_id"
@@ -415,7 +415,7 @@ ActiveRecord::Schema.define(:version =&gt; 20130111232201) do @@ -415,7 +415,7 @@ ActiveRecord::Schema.define(:version =&gt; 20130111232201) do
415 t.datetime "updated_at" 415 t.datetime "updated_at"
416 t.decimal "discount" 416 t.decimal "discount"
417 t.boolean "available", :default => true 417 t.boolean "available", :default => true
418 - t.boolean "highlighted" 418 + t.boolean "highlighted", :default => false
419 t.integer "unit_id" 419 t.integer "unit_id"
420 t.integer "image_id" 420 t.integer "image_id"
421 end 421 end
debian/changelog
  1 +noosfero (0.41.1) unstable; urgency=low
  2 +
  3 + * Bugfixes release
  4 +
  5 + -- Rodrigo Souto <rodrigo@colivre.coop.br> Fri, 08 Mar 2013 11:33:11 -0300
  6 +
1 noosfero (0.41.0) unstable; urgency=low 7 noosfero (0.41.0) unstable; urgency=low
2 8
3 * Features version with anti spam-bot measures 9 * Features version with anti spam-bot measures
features/browse_catalogs.feature
@@ -18,7 +18,7 @@ Feature: browse catalogs @@ -18,7 +18,7 @@ Feature: browse catalogs
18 18
19 Scenario: display titles 19 Scenario: display titles
20 Then I should see "Associação de Artesanato de Bonito" 20 Then I should see "Associação de Artesanato de Bonito"
21 - And I should see "Products/Services" within "#product-list" 21 + And I should see "Products/Services"
22 22
23 Scenario: display the simplest possible product 23 Scenario: display the simplest possible product
24 Given the following products 24 Given the following products
features/signup.feature
@@ -3,6 +3,7 @@ Feature: signup @@ -3,6 +3,7 @@ Feature: signup
3 I want to sign up to the site 3 I want to sign up to the site
4 So I can have fun using its features 4 So I can have fun using its features
5 5
  6 +@selenium
6 Scenario: successfull registration 7 Scenario: successfull registration
7 Given I am on the homepage 8 Given I am on the homepage
8 When I follow "Login" 9 When I follow "Login"
@@ -13,6 +14,7 @@ Feature: signup @@ -13,6 +14,7 @@ Feature: signup
13 | Password | secret | 14 | Password | secret |
14 | Password confirmation | secret | 15 | Password confirmation | secret |
15 | Full name | José da Silva | 16 | Full name | José da Silva |
  17 + And wait for the captcha signup time
16 And I press "Create my account" 18 And I press "Create my account"
17 Then I should not be logged in 19 Then I should not be logged in
18 And I should receive an e-mail on josesilva@example.com 20 And I should receive an e-mail on josesilva@example.com
@@ -36,6 +38,7 @@ Feature: signup @@ -36,6 +38,7 @@ Feature: signup
36 And I go to signup page 38 And I go to signup page
37 Then I should be on Joao Silva's control panel 39 Then I should be on Joao Silva's control panel
38 40
  41 + @selenium
39 Scenario: user cannot register without a name 42 Scenario: user cannot register without a name
40 Given I am on the homepage 43 Given I am on the homepage
41 And I follow "Login" 44 And I follow "Login"
@@ -44,6 +47,7 @@ Feature: signup @@ -44,6 +47,7 @@ Feature: signup
44 And I fill in "Username" with "josesilva" 47 And I fill in "Username" with "josesilva"
45 And I fill in "Password" with "secret" 48 And I fill in "Password" with "secret"
46 And I fill in "Password confirmation" with "secret" 49 And I fill in "Password confirmation" with "secret"
  50 + And wait for the captcha signup time
47 And I press "Create my account" 51 And I press "Create my account"
48 Then I should see "Name can't be blank" 52 Then I should see "Name can't be blank"
49 53
features/step_definitions/noosfero_steps.rb
@@ -538,6 +538,7 @@ end @@ -538,6 +538,7 @@ end
538 538
539 Then /^I should receive an e-mail on (.*)$/ do |address| 539 Then /^I should receive an e-mail on (.*)$/ do |address|
540 last_mail = ActionMailer::Base.deliveries.last 540 last_mail = ActionMailer::Base.deliveries.last
  541 + last_mail.nil?.should be_false
541 last_mail['to'].to_s.should == address 542 last_mail['to'].to_s.should == address
542 end 543 end
543 544
@@ -748,3 +749,8 @@ Given /^the profile (.*) is configured to (.*) after login$/ do |profile, option @@ -748,3 +749,8 @@ Given /^the profile (.*) is configured to (.*) after login$/ do |profile, option
748 profile.redirection_after_login = redirection 749 profile.redirection_after_login = redirection
749 profile.save 750 profile.save
750 end 751 end
  752 +
  753 +When /^wait for the captcha signup time$/ do
  754 + environment = Environment.default
  755 + sleep environment.min_signup_delay + 1
  756 +end
gitignore.example
@@ -11,6 +11,7 @@ config/mongrel_cluster.yml @@ -11,6 +11,7 @@ config/mongrel_cluster.yml
11 config/solr.yml 11 config/solr.yml
12 config/plugins 12 config/plugins
13 config/thin.yml 13 config/thin.yml
  14 +config/local.rb
14 index 15 index
15 locale 16 locale
16 log 17 log
lib/noosfero.rb
@@ -2,7 +2,7 @@ require &#39;fast_gettext&#39; @@ -2,7 +2,7 @@ require &#39;fast_gettext&#39;
2 2
3 module Noosfero 3 module Noosfero
4 PROJECT = 'noosfero' 4 PROJECT = 'noosfero'
5 - VERSION = '0.41.0' 5 + VERSION = '0.41.1'
6 6
7 def self.pattern_for_controllers_in_directory(dir) 7 def self.pattern_for_controllers_in_directory(dir)
8 disjunction = controllers_in_directory(dir).join('|') 8 disjunction = controllers_in_directory(dir).join('|')
lib/noosfero/core_ext/string.rb
@@ -11,12 +11,52 @@ class String @@ -11,12 +11,52 @@ class String
11 [ 'ó', 'ò', 'ô', 'ö', 'õ', 'º' ] => 'o', 11 [ 'ó', 'ò', 'ô', 'ö', 'õ', 'º' ] => 'o',
12 [ 'Ú', 'Ù', 'Û', 'Ü' ] => 'U', 12 [ 'Ú', 'Ù', 'Û', 'Ü' ] => 'U',
13 [ 'ú', 'ù', 'û', 'ü' ] => 'u', 13 [ 'ú', 'ù', 'û', 'ü' ] => 'u',
  14 + [ 'ß' ] => 'ss',
14 [ 'Ç' ] => 'C', 15 [ 'Ç' ] => 'C',
15 [ 'ç' ] => 'c', 16 [ 'ç' ] => 'c',
16 [ 'Ñ' ] => 'N', 17 [ 'Ñ' ] => 'N',
17 [ 'ñ' ] => 'n', 18 [ 'ñ' ] => 'n',
18 [ 'Ÿ' ] => 'Y', 19 [ 'Ÿ' ] => 'Y',
19 [ 'ÿ' ] => 'y', 20 [ 'ÿ' ] => 'y',
  21 +# Cyrillic alphabet transliteration
  22 + [ 'а', 'А' ] => 'a',
  23 + [ 'б', 'Б' ] => 'b',
  24 + [ 'в', 'В' ] => 'v',
  25 + [ 'г', 'Г' ] => 'g',
  26 + [ 'д', 'Д' ] => 'd',
  27 + [ 'е', 'Е' ] => 'e',
  28 + [ 'ё', 'Ё' ] => 'yo',
  29 + [ 'ж', 'Ж' ] => 'zh',
  30 + [ 'з', 'З' ] => 'z',
  31 + [ 'и', 'И' ] => 'i',
  32 + [ 'й', 'Й' ] => 'y',
  33 + [ 'к', 'К' ] => 'k',
  34 + [ 'л', 'Л' ] => 'l',
  35 + [ 'м', 'М' ] => 'm',
  36 + [ 'н', 'Н' ] => 'n',
  37 + [ 'о', 'О' ] => 'o',
  38 + [ 'п', 'П' ] => 'p',
  39 + [ 'р', 'Р' ] => 'r',
  40 + [ 'с', 'С' ] => 's',
  41 + [ 'т', 'Т' ] => 't',
  42 + [ 'у', 'У' ] => 'u',
  43 + [ 'ф', 'Ф' ] => 'f',
  44 + [ 'х', 'Х' ] => 'h',
  45 + [ 'ц', 'Ц' ] => 'ts',
  46 + [ 'ч', 'Ч' ] => 'ch',
  47 + [ 'ш', 'Ш' ] => 'sh',
  48 + [ 'щ', 'Щ' ] => 'sch',
  49 + [ 'э', 'Э' ] => 'e',
  50 + [ 'ю', 'Ю' ] => 'yu',
  51 + [ 'я', 'Я' ] => 'ya',
  52 + [ 'ы', 'Ы' ] => 'i',
  53 + [ 'ь', 'Ь' ] => '',
  54 + [ 'ъ', 'Ъ' ] => '',
  55 +# Ukrainian lovely letters
  56 + [ 'і', 'І' ] => 'i',
  57 + [ 'ї', 'Ї' ] => 'yi',
  58 + [ 'є', 'Є' ] => 'ye',
  59 + [ 'ґ', 'Ґ' ] => 'g',
20 } 60 }
21 61
22 # transliterate a string (assumed to contain UTF-8 data) 62 # transliterate a string (assumed to contain UTF-8 data)
plugins/custom_forms/lib/custom_forms_plugin/field.rb
@@ -4,7 +4,7 @@ class CustomFormsPlugin::Field &lt; ActiveRecord::Base @@ -4,7 +4,7 @@ class CustomFormsPlugin::Field &lt; ActiveRecord::Base
4 validates_presence_of :form, :name 4 validates_presence_of :form, :name
5 validates_uniqueness_of :slug, :scope => :form_id 5 validates_uniqueness_of :slug, :scope => :form_id
6 6
7 - belongs_to :form, :class_name => 'CustomFormsPlugin::Form', :dependent => :destroy 7 + belongs_to :form, :class_name => 'CustomFormsPlugin::Form'
8 has_many :answers, :class_name => 'CustomFormsPlugin::Answer' 8 has_many :answers, :class_name => 'CustomFormsPlugin::Answer'
9 9
10 serialize :choices, Hash 10 serialize :choices, Hash
plugins/custom_forms/lib/custom_forms_plugin/form.rb
1 class CustomFormsPlugin::Form < Noosfero::Plugin::ActiveRecord 1 class CustomFormsPlugin::Form < Noosfero::Plugin::ActiveRecord
2 belongs_to :profile 2 belongs_to :profile
3 3
4 - has_many :fields, :class_name => 'CustomFormsPlugin::Field' 4 + has_many :fields, :class_name => 'CustomFormsPlugin::Field', :dependent => :destroy
5 has_many :submissions, :class_name => 'CustomFormsPlugin::Submission' 5 has_many :submissions, :class_name => 'CustomFormsPlugin::Submission'
6 6
7 serialize :access 7 serialize :access
plugins/custom_forms/test/unit/custom_forms_plugin/field_test.rb
@@ -60,5 +60,16 @@ class CustomFormsPlugin::FieldTest &lt; ActiveSupport::TestCase @@ -60,5 +60,16 @@ class CustomFormsPlugin::FieldTest &lt; ActiveSupport::TestCase
60 assert_equal 2, field.choices['Second'] 60 assert_equal 2, field.choices['Second']
61 assert_equal 3, field.choices['Third'] 61 assert_equal 3, field.choices['Third']
62 end 62 end
  63 +
  64 + should 'not destroy form after removing a field' do
  65 + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))
  66 + license_field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form)
  67 + url_field = CustomFormsPlugin::Field.create!(:name => 'URL', :form => form)
  68 +
  69 + assert_no_difference CustomFormsPlugin::Form, :count do
  70 + url_field.destroy
  71 + end
  72 + assert_equal form.fields, [license_field]
  73 + end
63 end 74 end
64 75
plugins/custom_forms/test/unit/custom_forms_plugin/form_test.rb
@@ -169,4 +169,15 @@ class CustomFormsPlugin::FormTest &lt; ActiveSupport::TestCase @@ -169,4 +169,15 @@ class CustomFormsPlugin::FormTest &lt; ActiveSupport::TestCase
169 assert_includes scope, f2 169 assert_includes scope, f2
170 assert_not_includes scope, f3 170 assert_not_includes scope, f3
171 end 171 end
  172 +
  173 + should 'destroy fields after removing a form' do
  174 + form = CustomFormsPlugin::Form.create!(:name => 'Free Software', :profile => fast_create(Profile))
  175 + license_field = CustomFormsPlugin::Field.create!(:name => 'License', :form => form)
  176 + url_field = CustomFormsPlugin::Field.create!(:name => 'URL', :form => form)
  177 +
  178 + assert_difference CustomFormsPlugin::Field, :count, -2 do
  179 + form.destroy
  180 + end
  181 + end
  182 +
172 end 183 end
plugins/require_auth_to_comment/public/hide_comment_form.js
1 (function($) { 1 (function($) {
2 $(window).bind('userDataLoaded', function(event, data) { 2 $(window).bind('userDataLoaded', function(event, data) {
3 - if (data.login || $('meta[name=profile.allow_unauthenticated_comments]').length > 0) { 3 + if (data.login || $('meta[name="profile.allow_unauthenticated_comments"]').length > 0) {
4 $('.post-comment-button').show(); 4 $('.post-comment-button').show();
5 $('#page-comment-form').show(); 5 $('#page-comment-form').show();
6 $('.comment-footer').show(); 6 $('.comment-footer').show();
plugins/shopping_cart/public/style.css
@@ -209,7 +209,7 @@ label.error { @@ -209,7 +209,7 @@ label.error {
209 padding-left: 5px; 209 padding-left: 5px;
210 } 210 }
211 211
212 -#order-filter { 212 +#cart-order-filter {
213 background-color: #ccc; 213 background-color: #ccc;
214 border: 1px solid #aaa; 214 border: 1px solid #aaa;
215 border-radius: 5px; 215 border-radius: 5px;
plugins/shopping_cart/views/shopping_cart_plugin_myprofile/reports.html.erb
@@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
6 <% status_collection = [[nil, _('All')]] %> 6 <% status_collection = [[nil, _('All')]] %>
7 <% status_collection += status.map{|s| [pos+=1, s] } %> 7 <% status_collection += status.map{|s| [pos+=1, s] } %>
8 8
9 -<% form_tag({}, {:id => 'order-filter'}) do %> 9 +<% form_tag({}, {:id => 'cart-order-filter'}) do %>
10 <%= labelled_text_field(_('From')+' ', :from, @from.strftime("%Y-%m-%d"), :id => 'from', :size => 9) %> 10 <%= labelled_text_field(_('From')+' ', :from, @from.strftime("%Y-%m-%d"), :id => 'from', :size => 9) %>
11 <%= labelled_text_field(_('to')+' ', :to, @to.strftime("%Y-%m-%d"), :id => 'to', :size => 9) %> 11 <%= labelled_text_field(_('to')+' ', :to, @to.strftime("%Y-%m-%d"), :id => 'to', :size => 9) %>
12 <span style="white-space:nowrap"><%= labelled_select(_('Status')+' ', :filter_status, :first, :last, @status, status_collection)%></span> 12 <span style="white-space:nowrap"><%= labelled_select(_('Status')+' ', :filter_status, :first, :last, @status, status_collection)%></span>
plugins/spaminator/lib/spaminator_plugin/spaminator.rb
@@ -15,12 +15,12 @@ class SpaminatorPlugin::Spaminator @@ -15,12 +15,12 @@ class SpaminatorPlugin::Spaminator
15 def initialize_logger(environment) 15 def initialize_logger(environment)
16 logdir = File.join(RAILS_ROOT, 'log', SpaminatorPlugin.name.underscore) 16 logdir = File.join(RAILS_ROOT, 'log', SpaminatorPlugin.name.underscore)
17 File.makedirs(logdir) if !File.exist?(logdir) 17 File.makedirs(logdir) if !File.exist?(logdir)
18 - logpath = File.join(logdir, "#{environment.name.to_slug}_#{ENV['RAILS_ENV']}_#{Time.now.strftime("%F_%T")}.log") 18 + logpath = File.join(logdir, "#{environment.name.to_slug}_#{ENV['RAILS_ENV']}_#{Time.now.strftime('%F_%T')}.log")
19 @logger = Logger.new(logpath) 19 @logger = Logger.new(logpath)
20 end 20 end
21 21
22 def log(message) 22 def log(message)
23 - @logger << "[#{Time.now.strftime("%F %T %z")}] #{message}\n" 23 + @logger << "[#{Time.now.strftime('%F %T %z')}] #{message}\n"
24 end 24 end
25 end 25 end
26 26
po/pt/noosfero.po
@@ -5497,7 +5497,7 @@ msgstr &quot;Produto destacado&quot; @@ -5497,7 +5497,7 @@ msgstr &quot;Produto destacado&quot;
5497 #: app/views/catalog/index.rhtml:42 app/views/search/_image.rhtml:35 5497 #: app/views/catalog/index.rhtml:42 app/views/search/_image.rhtml:35
5498 #: app/views/search/_image.rhtml:47 5498 #: app/views/search/_image.rhtml:47
5499 msgid "No image" 5499 msgid "No image"
5500 -msgstr "Nenhum imagem" 5500 +msgstr "Nenhuma imagem"
5501 5501
5502 #: app/views/catalog/index.rhtml:52 5502 #: app/views/catalog/index.rhtml:52
5503 msgid "from " 5503 msgid "from "
public/javascripts/application.js
@@ -29,7 +29,14 @@ function focus_first_field() { @@ -29,7 +29,14 @@ function focus_first_field() {
29 29
30 /* * * Convert a string to a valid login name * * */ 30 /* * * Convert a string to a valid login name * * */
31 function convToValidLogin( str ) { 31 function convToValidLogin( str ) {
32 - return convToValidIdentifier(str, '') 32 + if (str.indexOf('@') == -1)
  33 + return convToValidUsername(str);
  34 + else
  35 + return convToValidEmail(str);
  36 +}
  37 +
  38 +function convToValidUsername( str ) {
  39 + return convToValidIdentifier(str, '');
33 } 40 }
34 41
35 /* * * Convert a string to a valid login name * * */ 42 /* * * Convert a string to a valid login name * * */
@@ -46,6 +53,18 @@ function convToValidIdentifier( str, sep ) { @@ -46,6 +53,18 @@ function convToValidIdentifier( str, sep ) {
46 .replace( /[^-_a-z0-9.]+/g, sep ) 53 .replace( /[^-_a-z0-9.]+/g, sep )
47 } 54 }
48 55
  56 +function convToValidEmail( str ) {
  57 + return str.toLowerCase()
  58 + .replace( /á|à|ã|â/g, "a" )
  59 + .replace( /é|ê/g, "e" )
  60 + .replace( /í/g, "i" )
  61 + .replace( /ó|ô|õ|ö/g, "o" )
  62 + .replace( /ú|ũ|ü/g, "u" )
  63 + .replace( /ñ/g, "n" )
  64 + .replace( /ç/g, "c" )
  65 + .replace( /[^@a-z0-9!#$%&'*+-/=?^_`{|}~.]+/g, '' )
  66 +}
  67 +
49 function updateUrlField(name_field, id) { 68 function updateUrlField(name_field, id) {
50 url_field = $(id); 69 url_field = $(id);
51 old_url_value = url_field.value; 70 old_url_value = url_field.value;
public/stylesheets/application.css
@@ -2715,6 +2715,11 @@ div#activation_enterprise label, div#activation_enterprise input, div#activation @@ -2715,6 +2715,11 @@ div#activation_enterprise label, div#activation_enterprise input, div#activation
2715 padding: 0; 2715 padding: 0;
2716 } 2716 }
2717 2717
  2718 +#catalog-categories-notice {
  2719 + color: #555753;
  2720 + padding-bottom: 0.5em;
  2721 +}
  2722 +
2718 /* * * Show Product * * * * * * * * * * * * */ 2723 /* * * Show Product * * * * * * * * * * * * */
2719 2724
2720 .controller-catalog #show_product .product-pic { 2725 .controller-catalog #show_product .product-pic {
public/stylesheets/search.css
@@ -756,10 +756,18 @@ li.search-product-item hr { @@ -756,10 +756,18 @@ li.search-product-item hr {
756 min-height: 98px; 756 min-height: 98px;
757 position: absolute; 757 position: absolute;
758 } 758 }
  759 +.search-gallery .search-content-first-column {
  760 + width: 190px;
  761 +}
  762 +
759 .search-content-second-column { 763 .search-content-second-column {
760 margin-left: 140px; 764 margin-left: 140px;
761 width: auto; 765 width: auto;
762 } 766 }
  767 +.search-gallery .search-content-second-column {
  768 + margin-left: 200px;
  769 +}
  770 +
763 .search-content-second-column tr:hover { 771 .search-content-second-column tr:hover {
764 background-color: none; 772 background-color: none;
765 } 773 }
@@ -827,15 +835,45 @@ a.search-image-pic { @@ -827,15 +835,45 @@ a.search-image-pic {
827 display: table-cell; 835 display: table-cell;
828 vertical-align: middle; 836 vertical-align: middle;
829 } 837 }
  838 +
830 .search-gallery-items a.search-image-pic { 839 .search-gallery-items a.search-image-pic {
831 float:left; 840 float:left;
832 margin:0 2px; 841 margin:0 2px;
833 } 842 }
  843 +
  844 +
834 .search-gallery .search-gallery-items { 845 .search-gallery .search-gallery-items {
835 float: left; 846 float: left;
836 - margin: 0 10px 0 0; 847 + margin: 0;
837 min-width: 130px; 848 min-width: 130px;
  849 + position: relative;
838 } 850 }
  851 +
  852 +.search-gallery .search-gallery-items a.search-image-pic {
  853 + border: none;
  854 + border-radius: 0;
  855 + box-shadow: none;
  856 + width: 62px;
  857 + margin: 0px 0px 1px 1px;
  858 + background-size: cover;
  859 + background-position: 50% 10%;
  860 + float: none;
  861 +}
  862 +
  863 +.search-gallery .search-gallery-items a.search-image-pic.pic-num1,
  864 +.search-gallery .search-gallery-items a.search-image-pic.pic-num2 {
  865 + display: block;
  866 + width: 60px;
  867 + height: 49px;
  868 +}
  869 +.search-gallery .search-gallery-items a.search-image-pic.pic-num3 {
  870 + width: 130px;
  871 + height: 99px;
  872 + position: absolute;
  873 + left: 61px;
  874 + top: 0px;
  875 +}
  876 +
839 .search-content-first-column .search-image-container .search-image-pic 877 .search-content-first-column .search-image-container .search-image-pic
840 .search-uploaded-file-first-column .search-image-container .search-image-pic { 878 .search-uploaded-file-first-column .search-image-container .search-image-pic {
841 display: block; 879 display: block;
script/sample-profiles
@@ -5,20 +5,24 @@ include Noosfero::SampleDataHelper @@ -5,20 +5,24 @@ include Noosfero::SampleDataHelper
5 categories = $environment.categories 5 categories = $environment.categories
6 6
7 places = [ 7 places = [
8 - { :country=>'BR', :city=>'Salvador', 8 + { :country=>'BR', :state=>'Bahia', :city=>'Salvador',
9 :lat=>-12.94032, :lng=>-38.58398 }, 9 :lat=>-12.94032, :lng=>-38.58398 },
10 - { :country=>'BR', :city=>'São Paulo', 10 + { :country=>'BR', :state=>'Bahia', :city=>'Feira de Santana',
  11 + :lat=>-12.25547, :lng=>-38.95430 },
  12 + { :country=>'BR', :state=>'São Paulo', :city=>'São Paulo',
11 :lat=>-23.54894, :lng=>-46.63881 }, 13 :lat=>-23.54894, :lng=>-46.63881 },
12 - { :country=>'BR', :city=>'Rio de Janeiro',  
13 - :lat=>-22.90353, :lng=>-43.20958 },  
14 - { :country=>'AR', :city=>'Buenos Aires', 14 + { :country=>'BR', :state=>'Rio de Janeiro', :city=>'Petrópolis',
  15 + :lat=>-22.50462, :lng=>-43.18232 },
  16 + { :country=>'AR', :state=>'A.C.', :city=>'Buenos Aires',
15 :lat=>-34.61088, :lng=>-58.39782 }, 17 :lat=>-34.61088, :lng=>-58.39782 },
16 - { :country=>'AR', :city=>'Mar del Plata', 18 + { :country=>'AR', :state=>'Buenos Aires', :city=>'Mar del Plata',
17 :lat=>-37.98317, :lng=>-57.59513 }, 19 :lat=>-37.98317, :lng=>-57.59513 },
18 - { :country=>'MX', :city=>'Acapulco', 20 + { :country=>'MX', :state=>'Guerrero', :city=>'Acapulco',
19 :lat=>16.86369, :lng=>-99.88151 }, 21 :lat=>16.86369, :lng=>-99.88151 },
20 - { :country=>'US', :city=>'Los Angeles', 22 + { :country=>'US', :state=>'California', :city=>'Los Angeles',
21 :lat=>34.02307, :lng=>-118.24310 }, 23 :lat=>34.02307, :lng=>-118.24310 },
  24 + { :country=>'US', :state=>'Florida', :city=>'Jacksonville',
  25 + :lat=>30.33217, :lng=>-81.65566 },
22 { :country=>'IT', :city=>'Roma', 26 { :country=>'IT', :city=>'Roma',
23 :lat=>41.89512, :lng=>12.48184 }, 27 :lat=>41.89512, :lng=>12.48184 },
24 { :country=>'IN', :city=>'Mumbai', 28 { :country=>'IN', :city=>'Mumbai',
@@ -51,12 +55,17 @@ for name in NAMES @@ -51,12 +55,17 @@ for name in NAMES
51 user.person.name = full_name 55 user.person.name = full_name
52 place = places[rand(places.length)] 56 place = places[rand(places.length)]
53 user.person.data[:country] = place[:country] 57 user.person.data[:country] = place[:country]
  58 + user.person.state = place[:state]
54 user.person.city = place[:city] 59 user.person.city = place[:city]
55 user.person.lat = place[:lat] + (rand/100)-0.005 60 user.person.lat = place[:lat] + (rand/100)-0.005
56 user.person.lng = place[:lng] + (rand/100)-0.005 61 user.person.lng = place[:lng] + (rand/100)-0.005
57 user.person.save! 62 user.person.save!
58 - categories.rand.people << user.person  
59 - categories.rand.people << user.person 63 + if categories.present?
  64 + 2.times do
  65 + category = categories.rand
  66 + category.people << user.person unless category.people.include?(user.person)
  67 + end
  68 + end
60 end 69 end
61 end 70 end
62 end 71 end
@@ -89,12 +98,8 @@ guest = User.new({ @@ -89,12 +98,8 @@ guest = User.new({
89 :password_confirmation => 'test', 98 :password_confirmation => 'test',
90 :environment => $environment, 99 :environment => $environment,
91 }) 100 })
92 -save guest do  
93 - 5.times do  
94 - communities.rand.add_admin(guest.person)  
95 - communities.rand.add_member(guest.person)  
96 - end  
97 -end 101 +save guest
  102 +
98 done 103 done
99 104
100 print "Activating users: " 105 print "Activating users: "
@@ -128,14 +133,32 @@ for verb in VERBS @@ -128,14 +133,32 @@ for verb in VERBS
128 for stuff in STUFF 133 for stuff in STUFF
129 name = [verb, stuff].join(' ') 134 name = [verb, stuff].join(' ')
130 community = Community.new(:name => name, :environment => $environment) 135 community = Community.new(:name => name, :environment => $environment)
  136 + if rand(2)==1 # not all communities must have a place
  137 + place = places[rand(places.length)]
  138 + community.data[:country] = place[:country]
  139 + community.state = place[:state]
  140 + community.city = place[:city]
  141 + end
131 save community do 142 save community do
132 communities << community 143 communities << community
133 rand(10).times do 144 rand(10).times do
134 - community.add_member(people.rand) 145 + person = people.rand
  146 + community.add_member(person) unless community.members.include?(person)
  147 + end
  148 + if categories.present?
  149 + 2.times do
  150 + category = categories.rand
  151 + category.communities << community unless category.communities.include?(community)
  152 + end
135 end 153 end
136 - categories.rand.communities << community  
137 - categories.rand.communities << community  
138 end 154 end
139 end 155 end
140 end 156 end
  157 +
  158 +5.times do
  159 + community = communities.rand
  160 + community.add_member(guest.person) unless community.members.include?(guest.person)
  161 + community.add_admin(guest.person) unless community.admins.include?(guest.person)
  162 +end
  163 +
141 done 164 done
test/functional/catalog_controller_test.rb
@@ -224,4 +224,21 @@ class CatalogControllerTest &lt; ActionController::TestCase @@ -224,4 +224,21 @@ class CatalogControllerTest &lt; ActionController::TestCase
224 assert_tag :tag => 'li', :attributes => {:id => "product-#{p2.id}", :class => /not-available/} 224 assert_tag :tag => 'li', :attributes => {:id => "product-#{p2.id}", :class => /not-available/}
225 end 225 end
226 226
  227 + should 'sort categories by name' do
  228 + environment = @enterprise.environment
  229 + environment.categories.destroy_all
  230 + pc1 = ProductCategory.create!(:name => "Drinks", :environment => environment)
  231 + pc2 = ProductCategory.create!(:name => "Bananas", :environment => environment)
  232 + pc3 = ProductCategory.create!(:name => "Sodas", :environment => environment)
  233 + pc4 = ProductCategory.create!(:name => "Pies", :environment => environment)
  234 + p1 = fast_create(Product, :product_category_id => pc1.id, :enterprise_id => @enterprise.id)
  235 + p2 = fast_create(Product, :product_category_id => pc2.id, :enterprise_id => @enterprise.id)
  236 + p3 = fast_create(Product, :product_category_id => pc3.id, :enterprise_id => @enterprise.id)
  237 + p4 = fast_create(Product, :product_category_id => pc4.id, :enterprise_id => @enterprise.id)
  238 +
  239 + get :index, :profile => @enterprise.identifier
  240 +
  241 + assert_equal [pc2, pc1, pc4, pc3], assigns(:categories)
  242 + end
  243 +
227 end 244 end
test/functional/environment_design_controller_test.rb
@@ -6,7 +6,7 @@ class EnvironmentDesignController; def rescue_action(e) raise e end; end @@ -6,7 +6,7 @@ class EnvironmentDesignController; def rescue_action(e) raise e end; end
6 6
7 class EnvironmentDesignControllerTest < ActionController::TestCase 7 class EnvironmentDesignControllerTest < ActionController::TestCase
8 8
9 - ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock ] 9 + ALL_BLOCKS = [ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
10 10
11 def setup 11 def setup
12 @controller = EnvironmentDesignController.new 12 @controller = EnvironmentDesignController.new
@@ -175,6 +175,16 @@ class EnvironmentDesignControllerTest &lt; ActionController::TestCase @@ -175,6 +175,16 @@ class EnvironmentDesignControllerTest &lt; ActionController::TestCase
175 assert_tag :tag => 'input', :attributes => { :id => 'block_address' } 175 assert_tag :tag => 'input', :attributes => { :id => 'block_address' }
176 end 176 end
177 177
  178 + should 'be able to edit TagsBlock' do
  179 + login_as(create_admin_user(Environment.default))
  180 + b = TagsBlock.create!
  181 + e = Environment.default
  182 + e.boxes.create!
  183 + e.boxes.first.blocks << b
  184 + get :edit, :id => b.id
  185 + assert_tag :tag => 'input', :attributes => { :id => 'block_title' }
  186 + end
  187 +
178 should 'create back link to environment control panel' do 188 should 'create back link to environment control panel' do
179 Environment.default.boxes.create!.blocks << CommunitiesBlock.new 189 Environment.default.boxes.create!.blocks << CommunitiesBlock.new
180 Environment.default.boxes.create!.blocks << EnterprisesBlock.new 190 Environment.default.boxes.create!.blocks << EnterprisesBlock.new
test/unit/article_test.rb
@@ -1347,6 +1347,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1347,6 +1347,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1347 a = profile.articles.create!(:name => 'a test article', :last_changed_by => author) 1347 a = profile.articles.create!(:name => 'a test article', :last_changed_by => author)
1348 assert_equal author.name, a.author_name 1348 assert_equal author.name, a.author_name
1349 author.destroy 1349 author.destroy
  1350 + a.reload
1350 a.author_name = 'some name' 1351 a.author_name = 'some name'
1351 assert_equal 'some name', a.author_name 1352 assert_equal 'some name', a.author_name
1352 end 1353 end
test/unit/tags_block_test.rb
@@ -22,9 +22,22 @@ class TagsBlockTest &lt; ActiveSupport::TestCase @@ -22,9 +22,22 @@ class TagsBlockTest &lt; ActiveSupport::TestCase
22 end 22 end
23 23
24 should 'generate links to tags' do 24 should 'generate links to tags' do
25 - assert_match /profile\/testinguser\/tags\/first-tag/, block.content 25 + assert_match /profile\/testinguser\/tags\/first-tag/, block.content
26 assert_match /profile\/testinguser\/tags\/second-tag/, block.content 26 assert_match /profile\/testinguser\/tags\/second-tag/, block.content
27 - assert_match /profile\/testinguser\/tags\/third-tag/, block.content 27 + assert_match /profile\/testinguser\/tags\/third-tag/, block.content
  28 + end
  29 +
  30 + should 'generate links to tags on a environment page' do
  31 + @otheruser = create_user('othertestinguser').person
  32 + @otheruser.articles.build(:name => 'article A', :tag_list => 'other-tag').save!
  33 + @otheruser.articles.build(:name => 'article B', :tag_list => 'other-tag, second-tag').save!
  34 + box = Box.create!(:owner => Environment.default)
  35 + @block = TagsBlock.create!(:box => box)
  36 +
  37 + assert_match /\/tag\/first-tag" [^>]+"3 items"/, block.content
  38 + assert_match /\/tag\/second-tag" [^>]+"3 items"/, block.content
  39 + assert_match /\/tag\/third-tag" [^>]+"one item"/, block.content
  40 + assert_match /\/tag\/other-tag" [^>]+"2 items"/, block.content
28 end 41 end
29 42
30 should 'return (none) when no tags to display' do 43 should 'return (none) when no tags to display' do
test/unit/user_test.rb
@@ -53,6 +53,8 @@ class UserTest &lt; ActiveSupport::TestCase @@ -53,6 +53,8 @@ class UserTest &lt; ActiveSupport::TestCase
53 53
54 def test_should_authenticate_user 54 def test_should_authenticate_user
55 assert_equal users(:johndoe), User.authenticate('johndoe', 'test') 55 assert_equal users(:johndoe), User.authenticate('johndoe', 'test')
  56 + assert_equal users(:johndoe), User.authenticate('johndoe@localhost.localdomain', 'test')
  57 + assert_equal nil, User.authenticate('wrongemail@localhost', 'test')
56 end 58 end
57 59
58 def test_should_authenticate_user_of_nondefault_environment 60 def test_should_authenticate_user_of_nondefault_environment