diff --git a/app/models/ability.rb b/app/models/ability.rb index 498b83caa..439959391 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -147,8 +147,13 @@ class Ability end def relation_exists_for(target, roles) - target.relations.exists?(:actor_id => @user.id, :actor_type => 'User', :role => roles) or - target.relations.exists?(:actor_id => @user.group_ids, :actor_type => 'Group', :role => roles) + rel = target.relations + is_owner_group = target.owner.class == Group + groups = @user.groups + groups = groups.where('groups.id != ?', target.owner.id) if is_owner_group + rel.exists?(:actor_id => @user.id, :actor_type => 'User', :role => roles) or # user is member + (@user.groups.exists?(:id => target.owner.id, :relations =>{:role => roles}) and is_owner_group) or # user group is owner + rel.exists?(:actor_id => groups, :actor_type => 'Group', :role => roles) # user group is member end def local_reader?(target) diff --git a/app/models/user.rb b/app/models/user.rb index 19771bdd5..3498c44eb 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -129,4 +129,23 @@ class User < ActiveRecord::Base false end end + + def best_role target + rel = target.relations + is_owner_group = target.owner.class == Group + gr = self.groups + gr = gr.where('groups.id != ?', target.owner.id) if is_owner_group + roles = [] + if is_owner_group + owner_group = self.groups.where(:id => target.owner.id).first + roles += owner_group.actors.where(:actor_id => self) if owner_group # user group is owner + end + roles += rel.where(:actor_id => self.id, :actor_type => 'User') # user is member + roles += rel.where(:actor_id => gr, :actor_type => 'Group') # user group is member + roles = roles.map(&:role).uniq + return 'admin' if roles.include? 'admin' + return 'writer' if roles.include? 'writer' + return 'reader' if roles.include? 'reader' + raise "unknown user #{self.uname} roles #{roles}" + end end diff --git a/app/views/projects/projects/_project.html.haml b/app/views/projects/projects/_project.html.haml index 537a266b6..f5514643f 100644 --- a/app/views/projects/projects/_project.html.haml +++ b/app/views/projects/projects/_project.html.haml @@ -11,7 +11,7 @@ %td - c = participant_class(alone_member, project) %span{:class => c, :title => t("layout.relations.#{c}")} - = t("layout.collaborators.role_names.#{project.relations.by_user_through_groups(current_user).first.role}") + = t("layout.collaborators.role_names.#{current_user.best_role project}") %td.td5 - unless project.owner == current_user or !alone_member = link_to remove_user_project_path(project), :method => :delete, :confirm => t("layout.confirm") do diff --git a/app/views/projects/projects/_project.json.jbuilder b/app/views/projects/projects/_project.json.jbuilder index 92e639a63..4052c1171 100644 --- a/app/views/projects/projects/_project.json.jbuilder +++ b/app/views/projects/projects/_project.json.jbuilder @@ -5,7 +5,7 @@ json.project do |proj| proj.description project.description proj.link project_path(project) - proj.role t("layout.collaborators.role_names.#{project.relations.by_user_through_groups(current_user).first.role}").force_encoding(Encoding::UTF_8) + proj.role t("layout.collaborators.role_names.#{current_user.best_role project}").force_encoding(Encoding::UTF_8) proj.leave_link remove_user_project_path(project) unless project.owner == current_user or !alone_member? project proj.rights_class participant_class(alone_member?(project), project) diff --git a/spec/controllers/projects/projects_controller_spec.rb b/spec/controllers/projects/projects_controller_spec.rb index e16d3b55e..a94cced96 100644 --- a/spec/controllers/projects/projects_controller_spec.rb +++ b/spec/controllers/projects/projects_controller_spec.rb @@ -79,6 +79,7 @@ describe Projects::ProjectsController do end it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' end context 'for writer user' do @@ -136,20 +137,115 @@ describe Projects::ProjectsController do response.should redirect_to(forbidden_path) end - it 'should not be able to edit project' do - description = @project.description - put :update, :project=>{:description =>"hack"}, :owner_name => @project.owner.uname, :project_name => @project.name - response.should redirect_to(forbidden_path) - Project.find(@project.id).description.should == description + it_should_behave_like 'user without update rights' + end + + context 'for group' do + before(:each) do + @group = FactoryGirl.create(:group) + @group_user = FactoryGirl.create(:user) + @project.relations.destroy_all + set_session_for(@group_user) end - it 'should not be able to edit project sections' do - has_wiki, has_issues = @project.has_wiki, @project.has_issues - post :sections, :project =>{:has_wiki => !has_wiki, :has_issues => !has_issues}, :owner_name => @project.owner.uname, :project_name => @project.name - response.should redirect_to(forbidden_path) - project = Project.find(@project.id) - project.has_wiki.should == has_wiki - project.has_issues.should == has_issues + context 'owner of the project' do + before(:each) do + @project.update_attribute :owner, @group + @project.relations.create :actor_id => @project.owner.id, :actor_type => @project.owner.class.to_s, :role => 'admin' + end + + context 'reader user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'reader') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' + + it 'should has reader role to group project' do + @group_user.best_role(@project).should eql('reader') # Need this? + end + + context 'user should has best role' do + before(:each) do + @project.relations.create :actor_id => @group_user.id, :actor_type => @group_user.class.to_s, :role => 'admin' + end + it_should_behave_like 'projects user with admin rights' + end + end + + context 'admin user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'admin') + end + + it_should_behave_like 'projects user with admin rights' + it_should_behave_like 'projects user with reader rights' + end + end + + context 'member of the project' do + context 'with admin rights' do + before(:each) do + @project.relations.create :actor_id => @group.id, :actor_type => @group.class.to_s, :role => 'admin' + end + + context 'reader user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'reader') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'projects user with admin rights' + + context 'user should has best role' do + before(:each) do + @project.relations.create :actor_id => @group_user.id, :actor_type => @group_user.class.to_s, :role => 'reader' + end + it_should_behave_like 'projects user with admin rights' + end + end + + context 'admin user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'admin') + end + + it_should_behave_like 'projects user with admin rights' + it_should_behave_like 'projects user with reader rights' + end + end + + context 'with reader rights' do + before(:each) do + @project.relations.create :actor_id => @group.id, :actor_type => @group.class.to_s, :role => 'reader' + end + + context 'reader user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'reader') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' + + context 'user should has best role' do + before(:each) do + @project.relations.create :actor_id => @group_user.id, :actor_type => @group_user.class.to_s, :role => 'admin' + end + it_should_behave_like 'projects user with admin rights' + end + end + + context 'admin user' do + before(:each) do + @group.actors.create(:actor_id => @group_user.id, :actor_type => 'User', :role => 'admin') + end + + it_should_behave_like 'projects user with reader rights' + it_should_behave_like 'user without update rights' + end + end end end end diff --git a/spec/support/shared_examples/projects_controller.rb b/spec/support/shared_examples/projects_controller.rb index 0562f06d8..0e4b4aff2 100644 --- a/spec/support/shared_examples/projects_controller.rb +++ b/spec/support/shared_examples/projects_controller.rb @@ -1,11 +1,12 @@ # -*- encoding : utf-8 -*- shared_examples_for 'projects user with reader rights' do - it_should_behave_like 'user with rights to view projects' + include_examples 'user with rights to view projects' # nested shared_examples_for dont work it 'should be able to fork project' do post :fork, :owner_name => @project.owner.uname, :project_name => @project.name response.should redirect_to(project_path(Project.last)) end + end shared_examples_for 'projects user with admin rights' do @@ -21,3 +22,21 @@ shared_examples_for 'user with rights to view projects' do response.should render_template(:index) end end + +shared_examples_for 'user without update rights' do + it 'should not be able to edit project' do + description = @project.description + put :update, :project=>{:description =>"hack"}, :owner_name => @project.owner.uname, :project_name => @project.name + Project.find(@project.id).description.should == description + response.should redirect_to(forbidden_path) + end + + it 'should not be able to edit project sections' do + has_wiki, has_issues = @project.has_wiki, @project.has_issues + post :sections, :project =>{:has_wiki => !has_wiki, :has_issues => !has_issues}, :owner_name => @project.owner.uname, :project_name => @project.name + project = Project.find(@project.id) + project.has_wiki.should == has_wiki + project.has_issues.should == has_issues + response.should redirect_to(forbidden_path) + end +end