[#325] add abibity to create fork with different name

This commit is contained in:
Alexander Machehin 2013-11-19 17:02:05 +06:00
parent 2899728a33
commit 188c3be355
11 changed files with 98 additions and 25 deletions

View File

@ -0,0 +1,19 @@
$(document).ready(function() {
var fork_name = $('#fork_name');
var forks_path = $('#possible_forks_path');
fork_name.keyup(function(){
$.ajax({
type: 'GET',
url: forks_path.val(),
data: 'name=' + fork_name.val(),
success: function(data){
$('#forks_list').html(data);
},
error: function(data){
alert('error'); // TODO remove
}
});
});
});

View File

@ -279,3 +279,10 @@ table.blame td.message .message {
background: #ECECEC; background: #ECECEC;
color: #000; color: #000;
} }
.fork_name {
height: 20px;
margin-left: 10px;
width: 450px;
padding: 0 5px;
}

View File

@ -66,7 +66,7 @@ class Api::V1::ProjectsController < Api::V1::BaseController
def fork def fork
owner = (Group.find params[:group_id] if params[:group_id].present?) || current_user owner = (Group.find params[:group_id] if params[:group_id].present?) || current_user
authorize! :write, owner if owner.class == Group authorize! :write, owner if owner.class == Group
if forked = @project.fork(owner) and forked.valid? if forked = @project.fork(owner, params[:fork_name]) and forked.valid?
render_json_response forked, 'Project has been forked successfully' render_json_response forked, 'Project has been forked successfully'
else else
render_validation_error forked, 'Project has not been forked' render_validation_error forked, 'Project has not been forked'

View File

@ -2,7 +2,7 @@
class Projects::ProjectsController < Projects::BaseController class Projects::ProjectsController < Projects::BaseController
include ProjectsHelper include ProjectsHelper
before_filter :authenticate_user! before_filter :authenticate_user!
load_and_authorize_resource :id_param => :project_name # to force member actions load load_and_authorize_resource :id_param => :project_name, :collection => :possible_forks # to force member actions load
def index def index
@projects = Project.accessible_by(current_ability, :membered) @projects = Project.accessible_by(current_ability, :membered)
@ -68,7 +68,7 @@ class Projects::ProjectsController < Projects::BaseController
def fork def fork
owner = (Group.find params[:group] if params[:group].present?) || current_user owner = (Group.find params[:group] if params[:group].present?) || current_user
authorize! :write, owner if owner.class == Group authorize! :write, owner if owner.class == Group
if forked = @project.fork(owner) and forked.valid? if forked = @project.fork(owner, params[:fork_name]) and forked.valid?
redirect_to forked, :notice => t("flash.project.forked") redirect_to forked, :notice => t("flash.project.forked")
else else
flash[:warning] = t("flash.project.fork_error") flash[:warning] = t("flash.project.fork_error")
@ -77,6 +77,11 @@ class Projects::ProjectsController < Projects::BaseController
end end
end end
def possible_forks
render :partial => 'projects/git/base/forks', :layout => false,
:locals => { :owner => current_user, :name => (params[:name].presence || @project.name) }
end
def sections def sections
if request.post? if request.post?
if @project.update_attributes(params[:project]) if @project.update_attributes(params[:project])

View File

@ -189,8 +189,10 @@ class Project < ActiveRecord::Base
build_list.save build_list.save
end end
def fork(new_owner) def fork(new_owner, new_name)
new_name = new_name.presence || name
dup.tap do |c| dup.tap do |c|
c.name = new_name
c.parent_id = id c.parent_id = id
c.owner = new_owner c.owner = new_owner
c.updated_at = nil; c.created_at = nil # :id = nil c.updated_at = nil; c.created_at = nil # :id = nil

View File

@ -1,11 +1,12 @@
- if owner.own_projects.exists? :name => @project.name - if owner.own_projects.exists? :name => name
- is_group = owner.class == Group ? "(#{t 'activerecord.models.group'})" : '' - is_group = owner.class == Group ? "(#{t 'activerecord.models.group'})" : ''
%p.center %p.center
=t 'layout.projects.already_exists' =t 'layout.projects.already_exists'
=link_to "#{owner.uname}/#{@project.name} #{is_group}", project_path(owner, @project.name) =link_to "#{owner.uname}/#{name} #{is_group}", project_path(owner, name)
- else - else
= form_for @project, :url => fork_project_path(@project), :html => { :class => :form, :multipart => true, :method => :post } do |f| = form_for @project, :url => fork_project_path(@project), :html => { :class => :form, :multipart => true, :method => :post } do |f|
= hidden_field_tag :group, owner.id if owner.class == Group = hidden_field_tag :group, owner.id if owner.class == Group
= hidden_field_tag :fork_name, name, :name => 'fork_name'
=f.submit t('layout.projects.fork_to', :to => "#{owner.uname} #{is_group}"), :class => 'btn btn-primary disabled', 'data-loading-text' => t('layout.processing'), :id => 'create_fork' =f.submit t('layout.projects.fork_to', :to => "#{owner.uname} #{is_group}"), :class => 'btn btn-primary disabled', 'data-loading-text' => t('layout.processing'), :id => 'create_fork'
:javascript :javascript

View File

@ -1,3 +1,5 @@
= hidden_field_tag :possible_forks_path, possible_forks_project_path(@project)
- if can? :write, @project - if can? :write, @project
.r{:style => "display: block"} .r{:style => "display: block"}
=link_to t("projects.pull_requests.show.pull"), new_project_pull_request_path(@project, :treeish => @treeish), :id => 'send_pull_request', :class => 'button' =link_to t("projects.pull_requests.show.pull"), new_project_pull_request_path(@project, :treeish => @treeish), :id => 'send_pull_request', :class => 'button'
@ -8,11 +10,12 @@
.modal-header .modal-header
%a.close{"data-dismiss" => "modal"} × %a.close{"data-dismiss" => "modal"} ×
%h3=t 'layout.projects.fork_modal_header' %h3=t 'layout.projects.fork_modal_header'
.modal-body.modal-body-fork = hidden_field_tag :possible_forks, possible_forks_project_path(@project)
=render 'choose_fork', :owner => current_user %div
%hr.bootstrap = Project.human_attribute_name :name
- Group.can_own_project(current_user).each do |group| = text_field_tag 'fork_name', @project.name, :id => 'fork_name', :class => 'fork_name'
=render 'choose_fork', :owner => group #forks_list.modal-body.modal-body-fork
%hr.bootstrap = render 'forks', :owner => current_user, :name => @project.name
- if @project.is_package && can?(:create, @project.build_lists.new) - if @project.is_package && can?(:create, @project.build_lists.new)
.r{:style => "display: block"}= link_to t('layout.projects.new_build_list'), new_project_build_list_path(@project), :class => 'button' .r{:style => "display: block"}= link_to t('layout.projects.new_build_list'), new_project_build_list_path(@project), :class => 'button'

View File

@ -0,0 +1,5 @@
=render 'projects/git/base/choose_fork', :owner => current_user, :name => name
%hr.bootstrap
- Group.can_own_project(current_user).each do |group|
=render 'projects/git/base/choose_fork', :owner => group, :name => name
%hr.bootstrap

View File

@ -344,6 +344,7 @@ Rosa::Application.routes.draw do
delete '/' => 'projects#destroy' delete '/' => 'projects#destroy'
# Member # Member
post '/fork' => 'projects#fork', :as => :fork_project post '/fork' => 'projects#fork', :as => :fork_project
get '/possible_forks' => 'projects#possible_forks', :as => :possible_forks_project
get '/sections' => 'projects#sections', :as => :sections_project get '/sections' => 'projects#sections', :as => :sections_project
post '/sections' => 'projects#sections' post '/sections' => 'projects#sections'
delete '/remove_user' => 'projects#remove_user', :as => :remove_user_project delete '/remove_user' => 'projects#remove_user', :as => :remove_user_project

View File

@ -62,6 +62,17 @@ shared_examples_for 'api projects user with fork rights' do
it 'ensures that project has been forked' do it 'ensures that project has been forked' do
lambda { post :fork, :id => @project.id, :format => :json }.should change{ Project.count }.by(1) lambda { post :fork, :id => @project.id, :format => :json }.should change{ Project.count }.by(1)
end end
it 'should be able to perform fork action with different name' do
post :fork, :id => @project.id, :fork_name => (@project.name + '_forked'), :format => :json
response.should be_success
end
it 'ensures that project has been forked' do
new_name = @project.name + '_forked'
lambda { post :fork, :id => @project.id, :fork_name => new_name, :format => :json }.should
change{ Project.where(:name => new_name).count }.by(1)
end
end end
shared_examples_for 'api projects user with fork rights for hidden project' do shared_examples_for 'api projects user with fork rights for hidden project' do
@ -334,17 +345,37 @@ describe Api::V1::ProjectsController do
it_should_behave_like 'api projects user without admin rights' it_should_behave_like 'api projects user without admin rights'
it_should_behave_like 'api projects user without owner rights' it_should_behave_like 'api projects user without owner rights'
it 'group writer should be able to fork project to their group' do context 'group writer' do
it 'should be able to fork project to their group' do
group = FactoryGirl.create(:group) group = FactoryGirl.create(:group)
group.actors.create(:actor_type => 'User', :actor_id => @user.id, :role => 'writer') group.actors.create(:actor_type => 'User', :actor_id => @user.id, :role => 'writer')
lambda {post :fork, :id => @project.id, :group_id => group.id}.should change{ Project.count }.by(1) lambda {post :fork, :id => @project.id, :group_id => group.id}.should change{ Project.count }.by(1)
end end
it 'group reader should not be able to fork project to their group' do it 'should be able to fork project with different name to their group' do
group = FactoryGirl.create(:group)
group.actors.create(:actor_type => 'User', :actor_id => @user.id, :role => 'writer')
new_name = @project.name + '_forked'
lambda { post :fork, :id => @project.id, :group_id => group.id, :fork_name => new_name }.should
change { Project.where(:name => new_name).count }.by(1)
end
end
context 'group reader' do
it 'should not be able to fork project to their group' do
group = FactoryGirl.create(:group) group = FactoryGirl.create(:group)
group.actors.create(:actor_type => 'User', :actor_id => @user.id, :role => 'reader') group.actors.create(:actor_type => 'User', :actor_id => @user.id, :role => 'reader')
lambda {post :fork, :id => @project.id, :group_id => group.id}.should change{ Project.count }.by(0) lambda {post :fork, :id => @project.id, :group_id => group.id}.should change{ Project.count }.by(0)
end end
it 'should not be able to fork project with different name to their group' do
group = FactoryGirl.create(:group)
new_name = @project.name + '_forked'
group.actors.create(:actor_type => 'User', :actor_id => @user.id, :role => 'reader')
lambda { post :fork, :id => @project.id, :group_id => group.id, :fork_name => new_name }.should
change{ Project.where(:name => new_name.count) }.by(0)
end
end
end end
context 'for admin' do context 'for admin' do

View File

@ -21,11 +21,10 @@ shared_examples_for 'projects user with reader rights' do
:group => group.id}.should change{ Project.count }.by(1) :group => group.id}.should change{ Project.count }.by(1)
end end
# it 'should be able to view project' do it 'should be able to fork project with different name' do
# get :show, :owner_name => @project.owner.uname, :project_name => @project.name post :fork, :owner_name => @project.owner.uname, :project_name => @project.name, :fork_name => 'another_name'
# assigns(:project).should eq @project response.should redirect_to(project_path(Project.where(:name => 'another_name').last))
# end end
end end
shared_examples_for 'projects user with project admin rights' do shared_examples_for 'projects user with project admin rights' do