Commit d779eba4e4ea7f9e0857ff0d6d32f56a9a3e8a54

Authored by Francisco Marcelo de Araújo Lima Júnior
2 parents 909929d8 c6e843e5

Merge branch 'rails3_stable' of gitlab.com:participa/noosfero into rails3_stable

app/helpers/account_helper.rb
@@ -15,12 +15,17 @@ module AccountHelper @@ -15,12 +15,17 @@ module AccountHelper
15 15
16 def suggestion_based_on_username(requested_username='') 16 def suggestion_based_on_username(requested_username='')
17 return "" if requested_username.empty? 17 return "" if requested_username.empty?
  18 +
  19 + requested_username = requested_username.downcase.tr("^#{Profile::IDENTIFIER_FORMAT}", '')
18 usernames = [] 20 usernames = []
  21 + tries = 0
19 3.times do 22 3.times do
20 begin 23 begin
21 valid_name = requested_username + rand(1000).to_s 24 valid_name = requested_username + rand(1000).to_s
22 - end while (usernames.include?(valid_name) || !Person.is_available?(valid_name, environment))  
23 - usernames << valid_name 25 + tries += 1
  26 + invalid = usernames.include?(valid_name) || !Person.is_available?(valid_name, environment)
  27 + end while tries <= 10 && invalid
  28 + usernames << valid_name unless invalid
24 end 29 end
25 usernames 30 usernames
26 end 31 end
app/helpers/application_helper.rb
@@ -1091,10 +1091,10 @@ module ApplicationHelper @@ -1091,10 +1091,10 @@ module ApplicationHelper
1091 link_to_all = nil 1091 link_to_all = nil
1092 if list.count > 5 1092 if list.count > 5
1093 list = list.first(5) 1093 list = list.first(5)
1094 - link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => current_user.login) 1094 + link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => user.identifier)
1095 end 1095 end
1096 link = list.map do |element| 1096 link = list.map do |element|
1097 - link_to(content_tag('strong', [_('<span>Manage</span> %s') % element.short_name(25)]), @environment.top_url + "/myprofile/#{element.identifier}", :class => "icon-menu-"+element.class.identification.underscore, :title => [_('Manage %s') % element.short_name]) 1097 + link_to(content_tag('strong', _('<span>Manage</span> %s') % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s') % element.short_name)
1098 end 1098 end
1099 if link_to_all 1099 if link_to_all
1100 link << link_to_all 1100 link << link_to_all
@@ -1118,15 +1118,15 @@ module ApplicationHelper @@ -1118,15 +1118,15 @@ module ApplicationHelper
1118 pending_tasks_count = '' 1118 pending_tasks_count = ''
1119 count = user ? Task.to(user).pending.count : -1 1119 count = user ? Task.to(user).pending.count : -1
1120 if count > 0 1120 if count > 0
1121 - pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) 1121 + pending_tasks_count = link_to(count.to_s, user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1122 end 1122 end
1123 1123
1124 - (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i style="background-image:url({avatar})"></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + 1124 + (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage'))) +
1125 render_environment_features(:usermenu) + 1125 render_environment_features(:usermenu) +
1126 - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') + 1126 + link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') +
1127 manage_enterprises.to_s + 1127 manage_enterprises.to_s +
1128 manage_communities.to_s + 1128 manage_communities.to_s +
1129 - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :class => 'ctrl-panel', :title => _("Configure your personal account and content")) + 1129 + link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content")) +
1130 pending_tasks_count + 1130 pending_tasks_count +
1131 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) 1131 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
1132 end 1132 end
app/models/environment.rb
@@ -637,6 +637,10 @@ class Environment &lt; ActiveRecord::Base @@ -637,6 +637,10 @@ class Environment &lt; ActiveRecord::Base
637 domain 637 domain
638 end 638 end
639 639
  640 + def admin_url
  641 + { :controller => 'admin_panel', :action => 'index' }
  642 + end
  643 +
640 def top_url 644 def top_url
641 url = 'http://' 645 url = 'http://'
642 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname) 646 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
app/views/account/accept_terms.html.erb
@@ -19,10 +19,18 @@ @@ -19,10 +19,18 @@
19 <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %> 19 <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %>
20 <%= hidden_field_tag :answer, params[:answer] %> 20 <%= hidden_field_tag :answer, params[:answer] %>
21 21
22 - <%= labelled_check_box(environment.terms_of_use_acceptance_text.blank? ? _('I read the terms of use and accepted them') : environment.terms_of_use_acceptance_text, :terms_accepted, '1', false, :onclick => 'toggle_submit_button("submit-accept-terms", this.checked)') %> 22 + <%= labelled_check_box(environment.terms_of_use_acceptance_text.blank? ? _('I read the terms of use and accepted them') : environment.terms_of_use_acceptance_text, :terms_accepted, '1', false, :id => 'accept-terms') %>
23 <% button_bar do %> 23 <% button_bar do %>
24 <%= button 'cancel', _('Cancel'), :controller => 'home', :action => 'index' %> 24 <%= button 'cancel', _('Cancel'), :controller => 'home', :action => 'index' %>
25 <%= submit_button 'forward', _('Continue'), {:disabled => true, :class => 'disabled', :id => 'submit-accept-terms'} %> 25 <%= submit_button 'forward', _('Continue'), {:disabled => true, :class => 'disabled', :id => 'submit-accept-terms'} %>
26 <% end %> 26 <% end %>
27 <% end %> 27 <% end %>
28 </div> 28 </div>
  29 +
  30 +<script type="text/javascript">
  31 + jQuery('#accept-terms').change(function(){
  32 + jQuery("#submit-accept-terms").toggleClass("disabled");
  33 + jQuery("#submit-accept-terms").prop("disabled", !jQuery("#submit-accept-terms").prop("disabled"));
  34 + });
  35 +</script>
  36 +
app/views/blocks/login_block.html.erb
1 -<div class="logged-user-info" style='display: none;'>  
2 - <h2><%= _('Logged in as %s') % '{login}' %></h2>  
3 - <ul>  
4 - <li><%= _('User since {year}/{month}') %></li>  
5 - <li><%= link_to _('Homepage'), '/{login}' %></li>  
6 - </ul>  
7 - <div class="user-actions">  
8 - <%= link_to content_tag('span', _('Logout')), { :controller => 'account', :action => 'logout' }, :class => 'button with-text icon-menu-logout' %> 1 +<% if user.present? %>
  2 + <div class="logged-user-info">
  3 + <h2><%= _('Logged in as %s') % user.identifier %></h2>
  4 + <ul>
  5 + <li><%= _('User since %s/%s') % [user.created_at.month, user.created_at.year] %></li>
  6 + <li><%= link_to _('Homepage'), user.public_profile_url %></li>
  7 + </ul>
  8 + <div class="user-actions">
  9 + <%= link_to content_tag('span', _('Logout')), { :controller => 'account', :action => 'logout' }, :class => 'button with-text icon-menu-logout' %>
  10 + </div>
9 </div> 11 </div>
10 -</div>  
11 -<div class='not-logged-user' style='display: none;'>  
12 - <%= render :file => 'account/login_block' %>  
13 -</div> 12 +<% else %>
  13 + <div class='not-logged-user'>
  14 + <%= render :file => 'account/login_block' %>
  15 + </div>
  16 +<% end%>
app/views/layouts/_user.html.erb
1 <div id="user"> 1 <div id="user">
2 - <span class='logged-in' style='display: none;'>  
3 - <%= usermenu_logged_in %>  
4 - </span>  
5 - <span class='not-logged-in' style='display: none'> 2 + <% user = (session[:user] && User.find_by_id(session[:user])) || nil %>
  3 + <% if user.present? %>
  4 + <% user = user.person %>
  5 + <span class='logged-in'>
  6 + <%= usermenu_logged_in %>
  7 + </span>
  8 + <% else %>
  9 + <span class='not-logged-in'>
  10 + <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>
  11 + <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_exec(&content) }.join("") %>
6 12
7 - <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %>  
8 - <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_exec(&content) }.join("") %> 13 + <div id='inlineLoginBox' style='display: none;'>
  14 + <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>
  15 + </div>
9 16
10 - <div id='inlineLoginBox' style='display: none;'>  
11 - <%= render :file => 'account/login', :locals => { :is_thickbox => true } %>  
12 - </div>  
13 -  
14 - <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>  
15 - <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%>  
16 - <% end %>  
17 -  
18 - </span> 17 + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %>
  18 + <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%>
  19 + <% end %>
  20 + </span>
  21 + <% end %>
19 <form action="/search" id="top-search" class="search_form clean" method="get"> 22 <form action="/search" id="top-search" class="search_form clean" method="get">
20 <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" /> 23 <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" />
21 <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div> 24 <div><%=_('Press <strong>Enter</strong> to send the search query.')%></div>
app/views/profile_editor/edit.html.erb
@@ -53,7 +53,7 @@ @@ -53,7 +53,7 @@
53 53
54 <%= 54 <%=
55 @plugins.dispatch(:profile_editor_extras).map do |content| 55 @plugins.dispatch(:profile_editor_extras).map do |content|
56 - if content.respond_to?(:call) then instance_eval(&content).html_safe else content.html_safe end 56 + content.kind_of?(Proc) ? self.instance_exec(&content) : content
57 end.join("\n") 57 end.join("\n")
58 %> 58 %>
59 59
features/admin_categories.feature
@@ -40,11 +40,11 @@ Feature: manage categories @@ -40,11 +40,11 @@ Feature: manage categories
40 Scenario: admin user could hide the category tree 40 Scenario: admin user could hide the category tree
41 Given I follow "Administration" 41 Given I follow "Administration"
42 And I follow "Categories" 42 And I follow "Categories"
43 - When I follow "Show" and wait while it hides 43 + When I follow "Show"
44 Then I should see "Vegetarian" 44 Then I should see "Vegetarian"
45 And I should see "Steak" 45 And I should see "Steak"
46 - When I follow "Hide" and wait while it hides  
47 - Then "Vegetarian" should not be visible within "div" 46 + When I follow "Hide"
  47 + Then I should not see "Vegetarian"
48 And "Steak" should not be visible within "div" 48 And "Steak" should not be visible within "div"
49 49
50 @selenium 50 @selenium
@@ -52,7 +52,6 @@ Feature: manage categories @@ -52,7 +52,6 @@ Feature: manage categories
52 Given the following category 52 Given the following category
53 | parent | name | display_in_menu | 53 | parent | name | display_in_menu |
54 | Steak | Pig | true | 54 | Steak | Pig | true |
55 - And I am on the homepage  
56 When I follow "Administration" 55 When I follow "Administration"
57 And I follow "Categories" 56 And I follow "Categories"
58 Then I should see "Food Show" 57 Then I should see "Food Show"
features/edit_image.feature
@@ -19,8 +19,8 @@ Feature: edit_image @@ -19,8 +19,8 @@ Feature: edit_image
19 Scenario: dont offer to edit external link if no image 19 Scenario: dont offer to edit external link if no image
20 Given the following files 20 Given the following files
21 | owner | file | mime | 21 | owner | file | mime |
22 - | morgoth | test.txt | text/plain |  
23 - When I go to edit "test.txt" by morgoth 22 + | morgoth | test_another.txt | text/plain |
  23 + When I go to edit "test_another.txt" by morgoth
24 Then I should not see "External link" 24 Then I should not see "External link"
25 25
26 Scenario: display tag list field when editing file 26 Scenario: display tag list field when editing file
features/edit_profile.feature
@@ -12,9 +12,7 @@ Feature: edit profile @@ -12,9 +12,7 @@ Feature: edit profile
12 | birth_date | 12 | birth_date |
13 When I go to joao's control panel 13 When I go to joao's control panel
14 And I follow "Edit Profile" 14 And I follow "Edit Profile"
15 - And I select "November" from "profile_data_birth_date_2i"  
16 - And I select "15" from "profile_data_birth_date_3i"  
17 - And I select "1980" from "profile_data_birth_date_1i" 15 + And I select "1980-11-15" from "profile_data_birth_date"
18 And I press "Save" 16 And I press "Save"
19 Then I should not see "Birth date is invalid" 17 Then I should not see "Birth date is invalid"
20 And I should not see "Birth date is mandatory" 18 And I should not see "Birth date is mandatory"
@@ -25,9 +23,7 @@ Feature: edit profile @@ -25,9 +23,7 @@ Feature: edit profile
25 | birth_date | 23 | birth_date |
26 When I go to joao's control panel 24 When I go to joao's control panel
27 And I follow "Edit Profile" 25 And I follow "Edit Profile"
28 - And I select "November" from "profile_data_birth_date_2i"  
29 - And I select "15" from "profile_data_birth_date_3i"  
30 - And I select "1980" from "profile_data_birth_date_1i" 26 + And I select "1980-11-15" from "profile_data_birth_date"
31 And I press "Save" 27 And I press "Save"
32 Then I should not see "Birth date is invalid" 28 Then I should not see "Birth date is invalid"
33 And I should not see "Birth date is mandatory" 29 And I should not see "Birth date is mandatory"
features/forum.feature
@@ -165,7 +165,7 @@ Feature: forum @@ -165,7 +165,7 @@ Feature: forum
165 | article | author | title | body | 165 | article | author | title | body |
166 | Post one | joaosilva | Hi all | Hi all | 166 | Post one | joaosilva | Hi all | Hi all |
167 When I go to /joaosilva/forum 167 When I go to /joaosilva/forum
168 - Then I should see "Joao" linking to "http://localhost/joaosilva/" 168 + Then I should see "Joao Silva" within ".forum-post-last-answer"
169 169
170 @selenium 170 @selenium
171 Scenario: community member should be able to see the discussion topic button 171 Scenario: community member should be able to see the discussion topic button
features/plugins.feature
@@ -13,46 +13,39 @@ Feature: plugins @@ -13,46 +13,39 @@ Feature: plugins
13 | login | name | 13 | login | name |
14 | joaosilva | Joao Silva | 14 | joaosilva | Joao Silva |
15 And I am logged in as "joaosilva" 15 And I am logged in as "joaosilva"
16 - And the following plugin  
17 - | klass |  
18 - | TestPlugin |  
19 - And the following events of TestPlugin  
20 - | event | body |  
21 - | control_panel_buttons | proc { {:title => 'Test plugin button', :icon => '', :url => ''} } |  
22 - | profile_tabs | proc { {:title => 'Test plugin tab', :id => 'test_plugin', :content => proc {'Test plugin random content'} } } |  
23 16
24 Scenario: a user must see the plugin\'s button in the control panel if the plugin is enabled 17 Scenario: a user must see the plugin\'s button in the control panel if the plugin is enabled
25 - Given plugin Test is enabled on environment 18 + Given plugin Foo is enabled on environment
26 And I go to joaosilva's control panel 19 And I go to joaosilva's control panel
27 - Then I should see "Test plugin button" 20 + Then I should see "Foo plugin button"
28 21
29 Scenario: a user must see the plugin\'s tab in in the profile if the plugin is enabled 22 Scenario: a user must see the plugin\'s tab in in the profile if the plugin is enabled
30 - Given plugin Test is enabled on environment 23 + Given plugin Foo is enabled on environment
31 And I am on joaosilva's profile 24 And I am on joaosilva's profile
32 - Then I should see "Test plugin tab" 25 + Then I should see "Foo plugin tab"
33 26
34 Scenario: a user must not see the plugin\'s button in the control panel if the plugin is disabled 27 Scenario: a user must not see the plugin\'s button in the control panel if the plugin is disabled
35 - Given plugin Test is disabled on environment 28 + Given plugin Foo is disabled on environment
36 And I go to joaosilva's control panel 29 And I go to joaosilva's control panel
37 - Then I should not see "Test plugin button" 30 + Then I should not see "Foo plugin button"
38 31
39 Scenario: a user must not see the plugin\'s tab in in the profile if the plugin is disabled 32 Scenario: a user must not see the plugin\'s tab in in the profile if the plugin is disabled
40 - Given plugin Test is disabled on environment 33 + Given plugin Foo is disabled on environment
41 And I am on joaosilva's profile 34 And I am on joaosilva's profile
42 - Then I should not see "Test plugin tab" 35 + Then I should not see "Foo plugin tab"
43 36
44 Scenario: an admin should be able to deactivate a plugin 37 Scenario: an admin should be able to deactivate a plugin
45 - Given plugin Test is enabled on environment 38 + Given plugin Foo is enabled on environment
46 And I am logged in as admin 39 And I am logged in as admin
47 When I go to admin_user's control panel 40 When I go to admin_user's control panel
48 - Then I should see "Test plugin button" 41 + Then I should see "Foo plugin button"
49 When I go to admin_user's profile 42 When I go to admin_user's profile
50 - Then I should see "Test plugin tab" 43 + Then I should see "Foo plugin tab"
51 And I go to the environment control panel 44 And I go to the environment control panel
52 And I follow "Plugins" 45 And I follow "Plugins"
53 - And I uncheck "Test plugin" 46 + And I uncheck "Foo"
54 And I press "Save changes" 47 And I press "Save changes"
55 When I go to admin_user's control panel 48 When I go to admin_user's control panel
56 - Then I should not see "Test plugin button" 49 + Then I should not see "Foo plugin button"
57 When I go to admin_user's profile 50 When I go to admin_user's profile
58 - Then I should not see "Test plugin tab" 51 + Then I should not see "Foo plugin tab"
features/profile_domain.feature
@@ -55,7 +55,7 @@ Feature: domain for profile @@ -55,7 +55,7 @@ Feature: domain for profile
55 Scenario: access community by domain 55 Scenario: access community by domain
56 Given I go to the search communities page 56 Given I go to the search communities page
57 When I follow "Sample Community" within ".search-profile-item" 57 When I follow "Sample Community" within ".search-profile-item"
58 - Then the page title should be "Sample Community - Colivre.net" 58 + Then the page title should be "Sample Community"
59 59
60 # This test is not working because the community domain isn't at all different 60 # This test is not working because the community domain isn't at all different
61 # from the environment (localhost / 127.0.0.1) 61 # from the environment (localhost / 127.0.0.1)
features/suggest_article.feature
@@ -12,6 +12,7 @@ Feature: suggest article @@ -12,6 +12,7 @@ Feature: suggest article
12 | sample-community | Sample Community | 12 | sample-community | Sample Community |
13 And "Joao Silva" is admin of "Sample Community" 13 And "Joao Silva" is admin of "Sample Community"
14 14
  15 + @selenium
15 Scenario: highlight an article before approval of a suggested article 16 Scenario: highlight an article before approval of a suggested article
16 Given someone suggested the following article to be published 17 Given someone suggested the following article to be published
17 | target | article_name | article_body | name | email | 18 | target | article_name | article_body | name | email |
@@ -19,6 +20,7 @@ Feature: suggest article @@ -19,6 +20,7 @@ Feature: suggest article
19 When I am logged in as "joaosilva" 20 When I am logged in as "joaosilva"
20 And I go to sample-community's control panel 21 And I go to sample-community's control panel
21 And I follow "Process requests" 22 And I follow "Process requests"
  23 + And I choose "Accept"
22 And I should see "suggested the publication of the article" 24 And I should see "suggested the publication of the article"
23 Then I should see "Highlight this article" within ".task_box" 25 Then I should see "Highlight this article" within ".task_box"
24 26
features/support/selenium.rb
@@ -21,6 +21,7 @@ Before(&#39;@ignore-hidden-elements&#39;) do @@ -21,6 +21,7 @@ Before(&#39;@ignore-hidden-elements&#39;) do
21 end 21 end
22 22
23 Capybara.default_wait_time = 30 23 Capybara.default_wait_time = 30
  24 +Capybara.server_host = "localhost"
24 25
25 After do 26 After do
26 DatabaseCleaner.clean 27 DatabaseCleaner.clean
lib/api/api.rb
@@ -16,6 +16,7 @@ module API @@ -16,6 +16,7 @@ module API
16 mount V1::Communities 16 mount V1::Communities
17 mount V1::People 17 mount V1::People
18 mount V1::Enterprises 18 mount V1::Enterprises
  19 + mount V1::Categories
19 mount Session 20 mount Session
20 21
21 end 22 end
lib/api/entities.rb
@@ -59,8 +59,18 @@ module API @@ -59,8 +59,18 @@ module API
59 59
60 class User < Grape::Entity 60 class User < Grape::Entity
61 root 'users', 'user' 61 root 'users', 'user'
  62 + expose :id
62 expose :login 63 expose :login
63 expose :person, :using => Profile 64 expose :person, :using => Profile
  65 + expose :permissions do |user, options|
  66 + output = {}
  67 + user.person.role_assignments.map do |role_assigment|
  68 + if role_assigment.resource.respond_to?(:identifier)
  69 + output[role_assigment.resource.identifier] = role_assigment.role.permissions
  70 + end
  71 + end
  72 + output
  73 + end
64 end 74 end
65 75
66 class UserLogin < User 76 class UserLogin < User
lib/api/v1/articles.rb
@@ -65,8 +65,12 @@ module API @@ -65,8 +65,12 @@ module API
65 # POST api/v1/communites/:community_id/articles?private_toke=234298743290432&article[name]=title&article[body]=body 65 # POST api/v1/communites/:community_id/articles?private_toke=234298743290432&article[name]=title&article[body]=body
66 post do 66 post do
67 community = environment.communities.find(params[:community_id]) 67 community = environment.communities.find(params[:community_id])
68 - article = community.articles.build(params[:article].merge(:last_changed_by => current_person))  
69 - article.type= params[:type].nil? ? 'TinyMceArticle' : params[:type] 68 + klass_type= params[:content_type].nil? ? 'TinyMceArticle' : params[:content_type]
  69 + article = klass_type.constantize.new(params[:article])
  70 + article.last_changed_by = current_person
  71 + article.created_by= current_person
  72 + article.profile = community
  73 +
70 if !article.save 74 if !article.save
71 render_api_errors!(article.errors.full_messages) 75 render_api_errors!(article.errors.full_messages)
72 end 76 end
lib/api/v1/categories.rb 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +module API
  2 + module V1
  3 + class Categories < Grape::API
  4 + before { detect_stuff_by_domain }
  5 + before { authenticate! }
  6 +
  7 + resource :categories do
  8 +
  9 + get do
  10 + type = params[:category_type]
  11 + categories = type.nil? ? environment.categories : environment.categories.find(:all, :conditions => {:type => type})
  12 + present categories, :with => Entities::Category
  13 + end
  14 +
  15 + desc "Return the category by id"
  16 + get ':id' do
  17 + present environment.categories.find(params[:id]), :with => Entities::Category
  18 + end
  19 +
  20 + end
  21 +
  22 + end
  23 + end
  24 +end
lib/api/v1/users.rb
@@ -15,6 +15,17 @@ module API @@ -15,6 +15,17 @@ module API
15 present environment.users.find(params[:id]), :with => Entities::User 15 present environment.users.find(params[:id]), :with => Entities::User
16 end 16 end
17 17
  18 + get ":id/permissions" do
  19 + user = environment.users.find(params[:id])
  20 + output = {}
  21 + user.person.role_assignments.map do |role_assigment|
  22 + if role_assigment.resource.respond_to?(:identifier) && role_assigment.resource.identifier == params[:profile]
  23 + output[:permissions] = role_assigment.role.permissions
  24 + end
  25 + end
  26 + present output
  27 + end
  28 +
18 end 29 end
19 30
20 end 31 end
lib/noosfero.rb
@@ -52,7 +52,7 @@ module Noosfero @@ -52,7 +52,7 @@ module Noosfero
52 end 52 end
53 53
54 def self.identifier_format 54 def self.identifier_format
55 - '[a-z0-9][a-z0-9~.]*([_-][a-z0-9~.]+)*' 55 + '[a-z0-9][a-z0-9~.]*([_\-][a-z0-9~.]+)*'
56 end 56 end
57 57
58 def self.default_hostname 58 def self.default_hostname
lib/noosfero/sample_data_helper.rb
@@ -11,13 +11,13 @@ module Noosfero::SampleDataHelper @@ -11,13 +11,13 @@ module Noosfero::SampleDataHelper
11 11
12 def save(obj, &block) 12 def save(obj, &block)
13 begin 13 begin
14 - if obj.save  
15 - print '.'  
16 - instance_eval &block if block  
17 - return obj  
18 - else  
19 - print 'F'  
20 - end 14 + if obj.save
  15 + print '.'
  16 + instance_eval &block if block
  17 + return obj
  18 + else
  19 + print 'F'
  20 + end
21 rescue 21 rescue
22 print 'E' 22 print 'E'
23 end 23 end
plugins/foo/lib/foo_plugin.rb
@@ -8,4 +8,12 @@ class FooPlugin &lt; Noosfero::Plugin @@ -8,4 +8,12 @@ class FooPlugin &lt; Noosfero::Plugin
8 _("A sample plugin to test autoload craziness.") 8 _("A sample plugin to test autoload craziness.")
9 end 9 end
10 10
  11 + def control_panel_buttons
  12 + {:title => 'Foo plugin button', :icon => '', :url => ''}
  13 + end
  14 +
  15 + def profile_tabs
  16 + {:title => 'Foo plugin tab', :id => 'foo_plugin', :content => lambda {'Foo plugin random content'} }
  17 + end
  18 +
11 end 19 end
public/javascripts/application.js
@@ -518,16 +518,11 @@ jQuery(function($) { @@ -518,16 +518,11 @@ jQuery(function($) {
518 $.getJSON('/account/user_data', function userDataCallBack(data) { 518 $.getJSON('/account/user_data', function userDataCallBack(data) {
519 if (data.login) { 519 if (data.login) {
520 // logged in 520 // logged in
521 - loggedInDataCallBack(data);  
522 - addManageEnterprisesToOldStyleMenu(data);  
523 if (data.chat_enabled) { 521 if (data.chat_enabled) {
524 setInterval(function(){ $.getJSON('/account/user_data', chatOnlineUsersDataCallBack)}, 10000); 522 setInterval(function(){ $.getJSON('/account/user_data', chatOnlineUsersDataCallBack)}, 10000);
525 } 523 }
526 $('head').append('<meta content="authenticity_token" name="csrf-param" />'); 524 $('head').append('<meta content="authenticity_token" name="csrf-param" />');
527 $('head').append('<meta content="'+$.cookie("_noosfero_.XSRF-TOKEN")+'" name="csrf-token" />'); 525 $('head').append('<meta content="'+$.cookie("_noosfero_.XSRF-TOKEN")+'" name="csrf-token" />');
528 - } else {  
529 - // not logged in  
530 - $('#user .not-logged-in, .login-block .not-logged-user').fadeIn();  
531 } 526 }
532 if (data.notice) { 527 if (data.notice) {
533 display_notice(data.notice); 528 display_notice(data.notice);
@@ -536,45 +531,6 @@ jQuery(function($) { @@ -536,45 +531,6 @@ jQuery(function($) {
536 $(window).trigger("userDataLoaded", data); 531 $(window).trigger("userDataLoaded", data);
537 }); 532 });
538 533
539 - function loggedInDataCallBack(data) {  
540 - // logged in  
541 - $('body').addClass('logged-in');  
542 - $('#user .logged-in, .login-block .logged-user-info').each(function() {  
543 - $(this).find('a[href]').each(function() {  
544 - var new_href = $(this).attr('href').replace('{login}', data.login);  
545 - if (data.email_domain) {  
546 - new_href = new_href.replace('{email_domain}', data.email_domain);  
547 - }  
548 - $(this).attr('href', new_href);  
549 - });  
550 - var html = $(this).html()  
551 - .replace(/{login}/g, data.login)  
552 - .replace('{avatar}', data.avatar)  
553 - .replace('{month}', data.since_month)  
554 - .replace('{year}', data.since_year);  
555 - $(this).html(html).fadeIn();  
556 - if (data.is_admin) {  
557 - $('#user .admin-link').show();  
558 - }  
559 - if (data.email_domain) {  
560 - $('#user .webmail-link').show();  
561 - }  
562 - });  
563 - }  
564 -  
565 - function addManageEnterprisesToOldStyleMenu(data) {  
566 - if ($('#manage-enterprises-link-template').length > 0) {  
567 - $.each(data.enterprises, function(index, enterprise) {  
568 - var item = $('<li>' + $('#manage-enterprises-link-template').html() + '</li>');  
569 - item.find('a[href]').each(function() {  
570 - $(this).attr('href', '/myprofile/' + enterprise.identifier);  
571 - });  
572 - item.html(item.html().replace('{name}', enterprise.name));  
573 - item.insertAfter('#manage-enterprises-link-template');  
574 - });  
575 - }  
576 - }  
577 -  
578 function chatOnlineUsersDataCallBack(data) { 534 function chatOnlineUsersDataCallBack(data) {
579 if ($('#chat-online-users').length == 0) { 535 if ($('#chat-online-users').length == 0) {
580 return; 536 return;
script/sample-articles
@@ -13,14 +13,16 @@ print &quot;Creating some TinyMce articles: &quot; @@ -13,14 +13,16 @@ print &quot;Creating some TinyMce articles: &quot;
13 for subject in SUBJECTS 13 for subject in SUBJECTS
14 rand(20).times do |i| 14 rand(20).times do |i|
15 profile = profiles.sample 15 profile = profiles.sample
  16 + name = "%s #{subject}" % profile.name
  17 + next if profile.articles.where(:slug => name.to_slug).first
16 article = TinyMceArticle.new( 18 article = TinyMceArticle.new(
17 - :name => "%s #{subject}" % profile.name,  
18 - :body => "%s #{subject}" % profile.name, 19 + :name => name,
  20 + :body => name,
19 :tag_list => [TAGS.sample, TAGS.sample], 21 :tag_list => [TAGS.sample, TAGS.sample],
20 :profile => profile 22 :profile => profile
21 ) 23 )
22 save article do 24 save article do
23 - categories.sample.articles << article 25 + article.add_category categories.sample
24 end 26 end
25 end 27 end
26 end 28 end
@@ -30,9 +32,11 @@ print &quot;Creating some galleries: &quot; @@ -30,9 +32,11 @@ print &quot;Creating some galleries: &quot;
30 for subject in SUBJECTS 32 for subject in SUBJECTS
31 rand(20).times do |i| 33 rand(20).times do |i|
32 profile = profiles.sample 34 profile = profiles.sample
  35 + name = "Gallery %s #{subject}" % profile.name
  36 + next if profile.articles.where(:slug => name.to_slug).first
33 save Gallery.new( 37 save Gallery.new(
34 - :name => "Gallery %s #{subject}" % profile.name,  
35 - :body => "Gallery %s #{subject}" % profile.name, 38 + :name => name,
  39 + :body => name,
36 :tag_list => [TAGS.sample, TAGS.sample], 40 :tag_list => [TAGS.sample, TAGS.sample],
37 :profile => profile 41 :profile => profile
38 ) 42 )
@@ -43,16 +47,20 @@ done @@ -43,16 +47,20 @@ done
43 print "Creating some events: " 47 print "Creating some events: "
44 for subject in EVENT_SUBJECTS 48 for subject in EVENT_SUBJECTS
45 for theme in THEMES 49 for theme in THEMES
  50 + profile = profiles.sample
  51 + name = subject % theme
  52 + next if profile.articles.where(:slug => name.to_slug).first
46 event = Event.new( 53 event = Event.new(
47 - :name => subject % theme,  
48 - :profile => profiles.sample, 54 + :name => name,
  55 + :profile => profile,
49 :start_date => Date.today + (-30 + rand(60)).days, 56 :start_date => Date.today + (-30 + rand(60)).days,
50 :tag_list => [TAGS.sample, TAGS.sample] 57 :tag_list => [TAGS.sample, TAGS.sample]
51 ) 58 )
52 save event do 59 save event do
53 - categories.sample.events << event  
54 - categories.sample.events << event  
55 - categories.sample.events << event 60 + 3.times do
  61 + category = categories.sample
  62 + event.add_category category
  63 + end
56 end 64 end
57 end 65 end
58 end 66 end
script/sample-enterprises
@@ -32,9 +32,12 @@ groups.each do |group| @@ -32,9 +32,12 @@ groups.each do |group|
32 :lat => rand_position(:lat), 32 :lat => rand_position(:lat),
33 :lng => rand_position(:lng) 33 :lng => rand_position(:lng)
34 ) 34 )
  35 + next if Profile[enterprise.identifier]
35 save enterprise do 36 save enterprise do
36 - categories.sample.enterprises << enterprise  
37 - categories.sample.enterprises << enterprise 37 + 2.times do
  38 + category = categories.sample
  39 + enterprise.add_category category
  40 + end
38 end 41 end
39 end 42 end
40 end 43 end
@@ -43,7 +46,6 @@ done @@ -43,7 +46,6 @@ done
43 46
44 EnterpriseActivation.find(:all, :conditions => ['created_at > ?', start_time]).each do |activation| 47 EnterpriseActivation.find(:all, :conditions => ['created_at > ?', start_time]).each do |activation|
45 enterprise = activation.enterprise 48 enterprise = activation.enterprise
46 - puts [activation.code, enterprise.name, enterprise.foundation_year].join(';')  
47 end 49 end
48 50
49 ze = Person['ze'] 51 ze = Person['ze']
script/sample-products
@@ -12,10 +12,14 @@ for thing in THINGS @@ -12,10 +12,14 @@ for thing in THINGS
12 for color in COLORS 12 for color in COLORS
13 name = [color, thing].join(' ') 13 name = [color, thing].join(' ')
14 rand(10).times do |i| 14 rand(10).times do |i|
15 - save Product.new(  
16 - :name => name,  
17 - :profile => enterprises.sample, :price => (i * 13.7),  
18 - ) 15 + profile = enterprises.sample
  16 + next if profile.products.where(:name => name).first
  17 + product = Product.new
  18 + product.name = name
  19 + product.profile_id = profile.id
  20 + product.price = (i * 13.7)
  21 + product.product_category_id = categories.sample.id
  22 + save product
19 end 23 end
20 end 24 end
21 end 25 end
script/sample-profiles
@@ -64,7 +64,7 @@ for name in NAMES @@ -64,7 +64,7 @@ for name in NAMES
64 if categories.present? 64 if categories.present?
65 2.times do 65 2.times do
66 category = categories.sample 66 category = categories.sample
67 - category.people << user.person unless category.people.include?(user.person) 67 + user.person.add_category category unless category.people.include?(user.person)
68 end 68 end
69 end 69 end
70 end 70 end
@@ -149,7 +149,7 @@ for verb in VERBS @@ -149,7 +149,7 @@ for verb in VERBS
149 if categories.present? 149 if categories.present?
150 2.times do 150 2.times do
151 category = categories.sample 151 category = categories.sample
152 - category.communities << community unless category.communities.include?(community) 152 + community.add_category category unless category.communities.include?(community)
153 end 153 end
154 end 154 end
155 end 155 end
test/functional/cms_controller_test.rb
@@ -653,10 +653,10 @@ class CmsControllerTest &lt; ActionController::TestCase @@ -653,10 +653,10 @@ class CmsControllerTest &lt; ActionController::TestCase
653 assert_match /<img.*align="right".*\/>/, saved.body 653 assert_match /<img.*align="right".*\/>/, saved.body
654 end 654 end
655 655
656 - should 'not be able to add image with alignment when textile' do 656 + should 'be able to add image with alignment when textile' do
657 post :new, :type => 'TextileArticle', :profile => profile.identifier, :article => { :name => 'image-alignment', :body => "the text of the article with image <img src='#' align='right'/> right align..." } 657 post :new, :type => 'TextileArticle', :profile => profile.identifier, :article => { :name => 'image-alignment', :body => "the text of the article with image <img src='#' align='right'/> right align..." }
658 saved = TextileArticle.find_by_name('image-alignment') 658 saved = TextileArticle.find_by_name('image-alignment')
659 - assert_no_match /align="right"/, saved.body 659 + assert_match /align="right"/, saved.body
660 end 660 end
661 661
662 should 'be able to create a new event document' do 662 should 'be able to create a new event document' do
test/functional/profile_controller_test.rb
@@ -154,7 +154,7 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -154,7 +154,7 @@ class ProfileControllerTest &lt; ActionController::TestCase
154 community = Community.create!(:name => 'my test community') 154 community = Community.create!(:name => 'my test community')
155 community.add_admin(@profile) 155 community.add_admin(@profile)
156 get :index, :profile => community.identifier 156 get :index, :profile => community.identifier
157 - assert_tag :tag => 'a', :attributes => { :href => /\/myprofile\/\{login\}/ }, :content => 'Control panel' 157 + assert_tag :tag => 'a', :attributes => { :href => /\/myprofile\/my-test-community/ }, :content => 'Control panel'
158 end 158 end
159 159
160 should 'show create community in own profile' do 160 should 'show create community in own profile' do
test/functional/profile_editor_controller_test.rb
@@ -211,14 +211,14 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase @@ -211,14 +211,14 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase
211 211
212 should 'back when update community info fail' do 212 should 'back when update community info fail' do
213 org = fast_create(Community) 213 org = fast_create(Community)
214 - Community.any_instance.stubs(:update_attributes!).returns(false) 214 + Community.any_instance.stubs(:update_attributes).returns(false)
215 post :edit, :profile => org.identifier 215 post :edit, :profile => org.identifier
216 assert_template 'edit' 216 assert_template 'edit'
217 end 217 end
218 218
219 should 'back when update enterprise info fail' do 219 should 'back when update enterprise info fail' do
220 org = fast_create(Enterprise) 220 org = fast_create(Enterprise)
221 - Enterprise.any_instance.stubs(:update_attributes!).returns(false) 221 + Enterprise.any_instance.stubs(:update_attributes).returns(false)
222 post :edit, :profile => org.identifier 222 post :edit, :profile => org.identifier
223 assert_template 'edit' 223 assert_template 'edit'
224 end 224 end
@@ -744,7 +744,7 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase @@ -744,7 +744,7 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase
744 should 'not crash if identifier is left blank' do 744 should 'not crash if identifier is left blank' do
745 c = fast_create(Community) 745 c = fast_create(Community)
746 assert_nothing_raised do 746 assert_nothing_raised do
747 - post :edit, :profile => c.identifier, :profile_data => c.attributes.merge('identifier' => '') 747 + post :edit, :profile => c.identifier, :profile_data => {:identifier => ''}
748 end 748 end
749 end 749 end
750 750
@@ -894,6 +894,23 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase @@ -894,6 +894,23 @@ class ProfileEditorControllerTest &lt; ActionController::TestCase
894 assert_tag :tag => 'input', :attributes => {:id => 'field_added_by_plugin', :value => 'value_of_field_added_by_plugin'} 894 assert_tag :tag => 'input', :attributes => {:id => 'field_added_by_plugin', :value => 'value_of_field_added_by_plugin'}
895 end 895 end
896 896
  897 + should 'add extra content with block provided by plugins on edit' do
  898 + class TestProfileEditPlugin < Noosfero::Plugin
  899 + def profile_editor_extras
  900 + lambda do
  901 + render :text => "<input id='field_added_by_plugin' value='value_of_field_added_by_plugin'/>"
  902 + end
  903 + end
  904 + end
  905 + Noosfero::Plugin.stubs(:all).returns([TestProfileEditPlugin.to_s])
  906 +
  907 + Noosfero::Plugin::Manager.any_instance.stubs(:enabled_plugins).returns([TestProfileEditPlugin.new])
  908 +
  909 + get :edit, :profile => profile.identifier
  910 +
  911 + assert_tag :tag => 'input', :attributes => {:id => 'field_added_by_plugin', :value => 'value_of_field_added_by_plugin'}
  912 + end
  913 +
897 should 'show image upload field from profile editor' do 914 should 'show image upload field from profile editor' do
898 env = Environment.default 915 env = Environment.default
899 env.custom_person_fields = { } 916 env.custom_person_fields = { }
test/integration/manage_documents_test.rb
@@ -9,7 +9,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest @@ -9,7 +9,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest
9 user.activate 9 user.activate
10 10
11 login('myuser', 'myuser') 11 login('myuser', 'myuser')
12 - assert_tag :tag => 'a', :attributes => { :href => "#{user.environment.top_url}/myprofile\/{login}" } 12 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{user.login}" }
13 13
14 get '/myprofile/myuser' 14 get '/myprofile/myuser'
15 assert_response :success 15 assert_response :success
@@ -40,7 +40,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest @@ -40,7 +40,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest
40 article.save! 40 article.save!
41 41
42 login('myuser', 'myuser') 42 login('myuser', 'myuser')
43 - assert_tag :tag => 'a', :attributes => { :href => "#{profile.environment.top_url}\/myprofile\/{login}" } 43 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}" }
44 44
45 get '/myprofile/myuser' 45 get '/myprofile/myuser'
46 assert_response :success 46 assert_response :success
@@ -75,7 +75,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest @@ -75,7 +75,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest
75 75
76 login('myuser', 'myuser') 76 login('myuser', 'myuser')
77 77
78 - assert_tag :tag => 'a', :attributes => { :href => "#{profile.environment.top_url}\/myprofile\/{login}" } 78 + assert_tag :tag => 'a', :attributes => { :href => "/myprofile/#{profile.identifier}" }
79 get '/myprofile/myuser' 79 get '/myprofile/myuser'
80 assert_response :success 80 assert_response :success
81 81
test/unit/account_helper_test.rb
@@ -18,4 +18,19 @@ class AccountHelperTest &lt; ActiveSupport::TestCase @@ -18,4 +18,19 @@ class AccountHelperTest &lt; ActiveSupport::TestCase
18 end 18 end
19 end 19 end
20 20
  21 + should 'remove chars which are not allowed' do
  22 + stubs(:environment).returns(Environment.default)
  23 + suggestions = suggestion_based_on_username('z/%&#e')
  24 + suggestions.each do |suggestion|
  25 + assert_no_match /.*%&#.*/, suggestion
  26 + end
  27 + end
  28 +
  29 + should 'return empty suggestions if do not find any identifier available' do
  30 + stubs(:environment).returns(Environment.default)
  31 + Person.stubs(:is_available?).returns(false)
  32 + suggestions = suggestion_based_on_username('z/%&#e')
  33 + assert_equal [], suggestions
  34 + end
  35 +
21 end 36 end
test/unit/api_test.rb
@@ -82,4 +82,26 @@ class APITest &lt; ActiveSupport::TestCase @@ -82,4 +82,26 @@ class APITest &lt; ActiveSupport::TestCase
82 assert_includes json["users"].map { |a| a["login"] }, user.login 82 assert_includes json["users"].map { |a| a["login"] }, user.login
83 end 83 end
84 84
  85 + should 'list user permissions' do
  86 + community = fast_create(Community)
  87 + community.add_admin(user.person)
  88 + get "/api/v1/users/#{user.id}/?#{params.to_query}"
  89 + json = JSON.parse(last_response.body)
  90 + assert_includes json["user"]["permissions"], community.identifier
  91 + end
  92 +
  93 + should 'list categories' do
  94 + category = fast_create(Category)
  95 + get "/api/v1/categories/?#{params.to_query}"
  96 + json = JSON.parse(last_response.body)
  97 + assert_includes json["categories"].map { |c| c["name"] }, category.name
  98 + end
  99 +
  100 + should 'get category by id' do
  101 + category = fast_create(Category)
  102 + get "/api/v1/categories/#{category.id}/?#{params.to_query}"
  103 + json = JSON.parse(last_response.body)
  104 + assert_equal category.name, json["category"]["name"]
  105 + end
  106 +
85 end 107 end