diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index 6b4baa981..207b4ca8d 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -10,6 +10,38 @@ class Api::V1::BaseController < ApplicationController protected + def add_member_to_subject(subject) + class_name = subject.class.name.downcase + if member.present? && subject.add_member(member) + render_json_response subject, "#{member.class.to_s} '#{member.id}' has been added to #{class_name} successfully" + else + render_validation_error subject, "Member has not been added to #{class_name}" + end + end + + def remove_member_from_subject(subject) + class_name = subject.class.name.downcase + if member.present? && subject.remove_member(member) + render_json_response subject, "#{member.class.to_s} '#{member.id}' has been removed from #{class_name} successfully" + else + render_validation_error subject, "Member has not been removed from #{class_name}" + end + end + + def destroy_subject(subject) + subject.destroy # later with resque + render_json_response subject, "#{subject.class.name} has been destroyed successfully" + end + + def update_subject(subject) + class_name = subject.class.name + if subject.update_attributes(params[class_name.downcase.to_sym] || {}) + render_json_response subject, "#{class_name} has been updated successfully" + else + render_validation_error subject, "#{class_name} has not been updated" + end + end + def paginate_params per_page = params[:per_page].to_i per_page = 20 if per_page < 1 @@ -36,4 +68,13 @@ class Api::V1::BaseController < ApplicationController render_json_response(subject, message, 422) end + private + + def member + if @member.blank? && %w(User Group).include?(params[:type]) + @member = params[:type].constantize.where(:id => params[:member_id]).first + end + @member + end + end diff --git a/app/controllers/api/v1/platforms_controller.rb b/app/controllers/api/v1/platforms_controller.rb index ff37d009a..007237092 100644 --- a/app/controllers/api/v1/platforms_controller.rb +++ b/app/controllers/api/v1/platforms_controller.rb @@ -33,11 +33,7 @@ class Api::V1::PlatformsController < Api::V1::BaseController platform_params = params[:platform] || {} owner = User.where(:id => platform_params[:owner_id]).first platform_params[:owner] = owner if owner - if @platform.update_attributes(platform_params) - render_json_response @platform, 'Platform has been updated successfully' - else - render_validation_error @platform, 'Platform has not been updated' - end + update_subject @platform end def members @@ -45,19 +41,11 @@ class Api::V1::PlatformsController < Api::V1::BaseController end def add_member - if member.present? && @platform.add_member(member) - render_json_response @platform, "#{member.class.to_s} '#{member.id}' has been added to platform successfully" - else - render_validation_error @platform, 'Member has not been added to platform' - end + add_member_to_subject @platform end def remove_member - if member.present? && @platform.remove_member(member) - render_json_response @platform, "#{member.class.to_s} '#{member.id}' has been removed from platform successfully" - else - render_validation_error @platform, 'Member has not been removed from platform' - end + remove_member_from_subject @platform end def clone @@ -77,21 +65,7 @@ class Api::V1::PlatformsController < Api::V1::BaseController end def destroy - @platform.destroy # later with resque - render_json_response @platform, 'Platform has been destroyed successfully' - end - - private - - def member - return @member if @member - if params[:type] == 'User' - member = User - elsif params[:type] == 'Group' - member = Group - end - @member = member.where(:id => params[:member_id]).first if member - @member ||= '' + destroy_subject @platform end end diff --git a/app/controllers/api/v1/repositories_controller.rb b/app/controllers/api/v1/repositories_controller.rb index 92546fe97..c438478d7 100644 --- a/app/controllers/api/v1/repositories_controller.rb +++ b/app/controllers/api/v1/repositories_controller.rb @@ -7,7 +7,57 @@ class Api::V1::RepositoriesController < Api::V1::BaseController load_and_authorize_resource :repository, :through => :platform, :shallow => true def show - end -end + def update + update_subject @repository + end + + def add_member + add_member_to_subject @repository + end + + def remove_member + remove_member_from_subject @repository + end + + def destroy + destroy_subject @repository + end + + def add_project + project = Project.where(:id => params[:project_id]).first + if project + begin + @repository.projects << project + render_json_response @repository, "Project '#{project.id}' has been added to repository successfully" + rescue ActiveRecord::RecordInvalid + render_validation_error @repository, t('flash.repository.project_not_added') + end + else + render_validation_error @repository, "Project has not been added to repository" + end + end + + def remove_project + project_id = params[:project_id] + ProjectToRepository.where(:project_id => project_id, :repository_id => @repository.id).destroy_all + render_json_response @repository, "Project '#{project_id}' has been removed from repository successfully" + end + + def signatures + key_pair = @repository.key_pair + key_pair.destroy if key_pair + key_pair = @repository.build_key_pair(params[:repository]) + key_pair.user_id = current_user.id + if key_pair.save + render_json_response @repository, 'Signatures have been updated for repository successfully' + else + message = 'Signatures have not been updated for repository' + errors = key_pair.errors.full_messages.join('. ') + (message << '. ' << errors) if errors.present? + render_json_response @repository, message, 422 + end + end + +end \ No newline at end of file diff --git a/app/controllers/platforms/repositories_controller.rb b/app/controllers/platforms/repositories_controller.rb index 7afc34a21..8767fbb94 100644 --- a/app/controllers/platforms/repositories_controller.rb +++ b/app/controllers/platforms/repositories_controller.rb @@ -131,8 +131,7 @@ class Platforms::RepositoriesController < Platforms::BaseController end def remove_project - @project = Project.find(params[:project_id]) - ProjectToRepository.where(:project_id => @project.id, :repository_id => @repository.id).destroy_all + ProjectToRepository.where(:project_id => params[:project_id], :repository_id => @repository.id).destroy_all redirect_to platform_repository_path(@platform, @repository), :notice => t('flash.repository.project_removed') end diff --git a/app/models/ability.rb b/app/models/ability.rb index 24c4a7a6a..382673bc5 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -100,7 +100,7 @@ class Ability can [:read, :projects_list], Repository, :platform => {:owner_type => 'Group', :owner_id => user.group_ids} can([:read, :projects_list], Repository, read_relations_for('repositories', 'platforms')) {|repository| local_reader? repository.platform} can([:create, :edit, :update, :destroy, :projects_list, :add_project, :remove_project], Repository) {|repository| local_admin? repository.platform} - can([:remove_members, :remove_member, :add_member], Repository) {|repository| owner?(repository.platform) || local_admin?(repository.platform)} + can([:remove_members, :remove_member, :add_member, :signatures], Repository) {|repository| owner?(repository.platform) || local_admin?(repository.platform)} can([:add_project, :remove_project], Repository) {|repository| repository.members.exists?(:id => user.id)} can(:clear, Platform) {|platform| local_admin?(platform) && platform.personal?} can([:change_visibility, :settings, :destroy, :edit, :update], Repository) {|repository| owner? repository.platform} diff --git a/app/models/project.rb b/app/models/project.rb index 1c8bc74a9..43baaa007 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -54,7 +54,7 @@ class Project < ActiveRecord::Base where("(projects.owner_id in (?) AND projects.owner_type = 'Group') OR (projects.owner_id in (?) AND projects.owner_type = 'User')", group_owner_ids, user_owner_ids) } - + before_validation :truncate_name, :on => :create before_create :set_maintainer after_save :attach_to_personal_repository @@ -177,6 +177,10 @@ class Project < ActiveRecord::Base protected + def truncate_name + self.name = name.strip if name + end + def attach_to_personal_repository owner_rep = self.owner.personal_repository if is_package diff --git a/config/routes.rb b/config/routes.rb index 8d741e135..3737aaa83 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -32,7 +32,15 @@ Rosa::Application.routes.draw do put :clear } end - resources :repositories, :only => [:show] + resources :repositories, :only => [:show, :update, :destroy] do + member { + put :add_member + delete :remove_member + put :add_project + delete :remove_project + put :signatures + } + end resources :projects, :only => [:show] do collection { get :get_id } member { diff --git a/spec/controllers/api/v1/platforms_controller_spec.rb b/spec/controllers/api/v1/platforms_controller_spec.rb index fc906dbae..682bce637 100644 --- a/spec/controllers/api/v1/platforms_controller_spec.rb +++ b/spec/controllers/api/v1/platforms_controller_spec.rb @@ -52,7 +52,7 @@ shared_examples_for 'api platform user with writer rights' do delete :remove_member, {:member_id => member.id, :type => 'User', :id => @platform.id}, :format => :json end - it 'should be able to perform update action' do + it 'should be able to perform remove_member action' do response.should be_success end it 'ensures that member has been removed from platform' do diff --git a/spec/controllers/api/v1/repositories_controller_spec.rb b/spec/controllers/api/v1/repositories_controller_spec.rb index 7ca1dffc4..1aa7b8ffb 100644 --- a/spec/controllers/api/v1/repositories_controller_spec.rb +++ b/spec/controllers/api/v1/repositories_controller_spec.rb @@ -35,6 +35,209 @@ shared_examples_for "api repository user without show rights" do end end +shared_examples_for 'api repository user with writer rights' do + + context 'api repository user with update rights' do + before do + put :update, {:repository => {:description => 'new description'}, :id => @repository.id}, :format => :json + end + + it 'should be able to perform update action' do + response.should be_success + end + it 'ensures that repository has been updated' do + @repository.reload + @repository.description.should == 'new description' + end + end + + context 'api repository user with add_member rights' do + let(:member) { FactoryGirl.create(:user) } + before do + put :add_member, {:member_id => member.id, :type => 'User', :id => @repository.id}, :format => :json + end + + it 'should be able to perform add_member action' do + response.should be_success + end + it 'ensures that new member has been added to repository' do + @repository.members.should include(member) + end + end + + context 'api repository user with remove_member rights' do + let(:member) { FactoryGirl.create(:user) } + before do + @repository.add_member(member) + delete :remove_member, {:member_id => member.id, :type => 'User', :id => @repository.id}, :format => :json + end + + it 'should be able to perform remove_member action' do + response.should be_success + end + it 'ensures that member has been removed from repository' do + @repository.members.should_not include(member) + end + end + + context 'api repository user with destroy rights' do + it 'should be able to perform destroy action for main platform' do + delete :destroy, :id => @repository.id, :format => :json + response.should be_success + end + it 'ensures that repository of main platform has been destroyed' do + lambda { delete :destroy, :id => @repository.id, :format => :json }.should change{ Repository.count }.by(-1) + end + it 'should not be able to perform destroy action for repository of personal platform' do + delete :destroy, :id => @personal_repository.id, :format => :json + response.should_not be_success + end + it 'ensures that repository of personal platform has not been destroyed' do + lambda { delete :destroy, :id => @personal_repository.id, :format => :json }.should_not change{ Repository.count } + end + end + + context 'api repository user with add_project rights' do + before { put :add_project, :id => @repository.id, :project_id => @project.id, :format => :json } + it 'should be able to perform add_project action' do + response.should be_success + end + it 'ensures that project has been added to repository' do + @repository.projects.should include(@project) + end + end + + context 'api repository user with remove_project rights' do + before do + @repository.projects << @project + delete :remove_project, :id => @repository.id, :project_id => @project.id, :format => :json + end + it 'should be able to perform remove_project action' do + response.should be_success + end + it 'ensures that project has been removed from repository' do + @repository.reload + @repository.projects.should_not include(@project) + end + end + + context 'api repository user with update signatures rights' do + before do + stub_key_pairs_calls + put :signatures, :id => @repository.id, :repository => {:public => 'iampublic', :secret => 'iamsecret'}, :format => :json + end + it 'should be able to perform signatures action' do + response.should be_success + end + it 'ensures that signatures has been updated' do + @repository.key_pair.should_not be_nil + end + end + +end + +shared_examples_for 'api repository user without writer rights' do + + context 'api repository user without update rights' do + before do + put :update, {:repository => {:description => 'new description'}, :id => @repository.id}, :format => :json + end + + it 'should not be able to perform update action' do + response.should_not be_success + end + it 'ensures that repository has not been updated' do + @repository.reload + @repository.description.should_not == 'new description' + end + end + + context 'api repository user without add_member rights' do + let(:member) { FactoryGirl.create(:user) } + before do + put :add_member, {:member_id => member.id, :type => 'User', :id => @repository.id}, :format => :json + end + + it 'should not be able to perform add_member action' do + response.should_not be_success + end + it 'ensures that new member has not been added to repository' do + @repository.members.should_not include(member) + end + end + + context 'api repository user without remove_member rights' do + let(:member) { FactoryGirl.create(:user) } + before do + @repository.add_member(member) + delete :remove_member, {:member_id => member.id, :type => 'User', :id => @repository.id}, :format => :json + end + + it 'should be able to perform update action' do + response.should_not be_success + end + it 'ensures that member has not been removed from repository' do + @repository.members.should include(member) + end + end + + context 'api repository user without destroy rights' do + it 'should not be able to perform destroy action for repository of main platform' do + delete :destroy, :id => @repository.id, :format => :json + response.should_not be_success + end + it 'ensures that repository of main platform has not been destroyed' do + lambda { delete :destroy, :id => @repository.id, :format => :json }.should_not change{ Repository.count } + end + it 'should not be able to perform destroy action for repository of personal platform' do + delete :destroy, :id => @personal_repository.id, :format => :json + response.should_not be_success + end + it 'ensures that repository of personal platform has not been destroyed' do + lambda { delete :destroy, :id => @personal_repository.id, :format => :json }.should_not change{ Repository.count } + end + end + + context 'api repository user without add_project rights' do + before { put :add_project, :id => @repository.id, :project_id => @project.id, :format => :json } + it 'should not be able to perform add_project action' do + response.should_not be_success + end + it 'ensures that project has not been added to repository' do + @repository.projects.should_not include(@project) + end + end + + context 'api repository user without remove_project rights' do + before do + @repository.projects << @project + delete :remove_project, :id => @repository.id, :project_id => @project.id, :format => :json + end + it 'should not be able to perform remove_project action' do + response.should_not be_success + end + it 'ensures that project has not been removed from repository' do + @repository.reload + @repository.projects.should include(@project) + end + end + + context 'api repository user without update signatures rights' do + before do + stub_key_pairs_calls + put :signatures, :id => @repository.id, :repository => {:public => 'iampublic', :secret => 'iamsecret'}, :format => :json + end + it 'should not be able to perform signatures action' do + response.should_not be_success + end + it 'ensures that signatures has not been updated' do + @repository.key_pair.should be_nil + end + end + +end + + describe Api::V1::RepositoriesController do before(:each) do stub_symlink_methods @@ -52,8 +255,11 @@ describe Api::V1::RepositoriesController do response.status.should == 401 end - it_should_behave_like 'api repository user without reader rights for hidden platform' if APP_CONFIG['anonymous_access'] - it_should_behave_like 'api repository user with show rights' if APP_CONFIG['anonymous_access'] + if APP_CONFIG['anonymous_access'] + it_should_behave_like 'api repository user without reader rights for hidden platform' + it_should_behave_like 'api repository user with show rights' + end + it_should_behave_like 'api repository user without writer rights' end context 'for admin' do @@ -64,6 +270,7 @@ describe Api::V1::RepositoriesController do it_should_behave_like 'api repository user with reader rights' it_should_behave_like 'api repository user with reader rights for hidden platform' + it_should_behave_like 'api repository user with writer rights' end context 'for platform owner user' do @@ -77,6 +284,7 @@ describe Api::V1::RepositoriesController do it_should_behave_like 'api repository user with reader rights' it_should_behave_like 'api repository user with reader rights for hidden platform' + it_should_behave_like 'api repository user with writer rights' end context 'for user' do @@ -88,5 +296,6 @@ describe Api::V1::RepositoriesController do it_should_behave_like 'api repository user with reader rights' it_should_behave_like 'api repository user without reader rights for hidden platform' it_should_behave_like 'api repository user with show rights' + it_should_behave_like 'api repository user without writer rights' end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index ab13f6ae3..c2892dec4 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -9,17 +9,35 @@ describe Project do @child_child_project = @child_project.fork(FactoryGirl.create(:user)) end - context 'for destroy root' do - before do - @root_project.destroy + context 'for destroy' do + let!(:root_project) { FactoryGirl.create(:project) } + let!(:child_project) { root_project.fork(FactoryGirl.create(:user)) } + let!(:child_child_project) { child_project.fork(FactoryGirl.create(:user)) } + + context 'root project' do + before { root_project.destroy } + + it "should not be delete child" do + Project.where(:id => child_project).count.should == 1 + end + + it "should not be delete child of the child" do + Project.where(:id => child_child_project).count.should == 1 + end end - it "should not be delete child" do - Project.where(:id => @child_project).count.should == 1 - end + pending 'when will be available :orphan_strategy => :adopt' do + context 'middle node' do + before{ child_project.destroy } - it "should not be delete child of the child" do - Project.where(:id => @child_child_project).count.should == 1 + it "should set root project as a parent for orphan child" do + Project.find(child_child_project).ancestry == root_project + end + + it "should not be delete child of the child" do + Project.where(:id => child_child_project).count.should == 1 + end + end end end @@ -48,19 +66,17 @@ describe Project do end end - # uncommit when will be available :orphan_strategy => :adopt + context 'truncates project name before validation' do + let!(:project) { FactoryGirl.build(:project, :name => ' test_name ') } - #context 'for destroy middle node' do - # before(:each) do - # @child_project.destroy - # end + it 'ensures that validation passed' do + project.valid?.should be_true + end + + it 'ensures that name has been truncated' do + project.valid? + project.name.should == 'test_name' + end + end - # it "should set root project as a parent for orphan child" do - # Project.find(@child_child_project).ancestry == @root_project - # end - - # it "should not be delete child of the child" do - # Project.where(:id => @child_child_project).count.should == 1 - # end - #end end