Commit e37a043df76adff70456ca3aa6a66735fd0c4585

Authored by Dmitriy Zaporozhets
1 parent 151ada76

Get rid of skipping callbacks in production code. Dont trigger gitolite more tha…

…n once on import in group
app/controllers/projects_controller.rb
@@ -99,11 +99,10 @@ class ProjectsController < ProjectResourceController @@ -99,11 +99,10 @@ class ProjectsController < ProjectResourceController
99 def destroy 99 def destroy
100 return access_denied! unless can?(current_user, :remove_project, project) 100 return access_denied! unless can?(current_user, :remove_project, project)
101 101
102 - # Disable the UsersProject update_repository call, otherwise it will be  
103 - # called once for every person removed from the project  
104 - UsersProject.skip_callback(:destroy, :after, :update_repository) 102 + # Delete team first in order to prevent multiple gitolite calls
  103 + project.truncate_team
  104 +
105 project.destroy 105 project.destroy
106 - UsersProject.set_callback(:destroy, :after, :update_repository)  
107 106
108 respond_to do |format| 107 respond_to do |format|
109 format.html { redirect_to root_path } 108 format.html { redirect_to root_path }
app/models/group.rb
@@ -13,9 +13,11 @@ @@ -13,9 +13,11 @@
13 13
14 class Group < Namespace 14 class Group < Namespace
15 def add_users_to_project_teams(user_ids, project_access) 15 def add_users_to_project_teams(user_ids, project_access)
16 - projects.each do |project|  
17 - project.add_users_ids_to_team(user_ids, project_access)  
18 - end 16 + UsersProject.add_users_into_projects(
  17 + projects.map(&:id),
  18 + user_ids,
  19 + project_access
  20 + )
19 end 21 end
20 22
21 def users 23 def users
app/models/users_project.rb
@@ -23,11 +23,13 @@ class UsersProject &lt; ActiveRecord::Base @@ -23,11 +23,13 @@ class UsersProject &lt; ActiveRecord::Base
23 belongs_to :user 23 belongs_to :user
24 belongs_to :project 24 belongs_to :project
25 25
26 - after_save :update_repository  
27 - after_destroy :update_repository 26 + attr_accessor :skip_git
  27 +
  28 + after_save :update_repository, unless: :skip_git?
  29 + after_destroy :update_repository, unless: :skip_git?
28 30
29 validates :user, presence: true 31 validates :user, presence: true
30 - validates :user_id, uniqueness: { :scope => [:project_id], message: "already exists in project" } 32 + validates :user_id, uniqueness: { scope: [:project_id], message: "already exists in project" }
31 validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true 33 validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true
32 validates :project, presence: true 34 validates :project, presence: true
33 35
@@ -36,76 +38,84 @@ class UsersProject &lt; ActiveRecord::Base @@ -36,76 +38,84 @@ class UsersProject &lt; ActiveRecord::Base
36 scope :in_project, ->(project) { where(project_id: project.id) } 38 scope :in_project, ->(project) { where(project_id: project.id) }
37 39
38 class << self 40 class << self
39 - def import_team(source_project, target_project)  
40 - UsersProject.without_repository_callback do  
41 - UsersProject.transaction do  
42 - team = source_project.users_projects.all  
43 -  
44 - team.each do |tm|  
45 - # Skip if user already present in team  
46 - next if target_project.users.include?(tm.user)  
47 -  
48 - new_tm = tm.dup  
49 - new_tm.id = nil  
50 - new_tm.project_id = target_project.id  
51 - new_tm.save 41 + def add_users_into_projects(project_ids, user_ids, project_access)
  42 + UsersProject.transaction do
  43 + project_ids.each do |project_id|
  44 + user_ids.each do |user_id|
  45 + users_project = UsersProject.new(project_access: project_access, user_id: user_id)
  46 + users_project.project_id = project_id
  47 + users_project.skip_git = true
  48 + users_project.save
52 end 49 end
53 end 50 end
  51 + Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids))
54 end 52 end
55 53
56 - target_project.update_repository  
57 true 54 true
58 rescue 55 rescue
59 false 56 false
60 end 57 end
61 58
62 - def without_repository_callback  
63 - UsersProject.skip_callback(:destroy, :after, :update_repository)  
64 - yield  
65 - UsersProject.set_callback(:destroy, :after, :update_repository) 59 + def import_team(source_project, target_project)
  60 + source_team = source_project.users_projects.all
  61 + target_team = target_project.users_projects.all
  62 + target_user_ids = target_team.map(&:user_id)
  63 +
  64 + source_team.reject! do |tm|
  65 + # Skip if user already present in team
  66 + target_user_ids.include?(tm.user_id)
  67 + end
  68 +
  69 + source_team.map! do |tm|
  70 + new_tm = tm.dup
  71 + new_tm.id = nil
  72 + new_tm.project_id = target_project.id
  73 + new_tm.skip_git = true
  74 + new_tm
  75 + end
  76 +
  77 + UsersProject.transaction do
  78 + source_team.each do |tm|
  79 + tm.save
  80 + end
  81 + target_project.update_repository
  82 + end
  83 +
  84 + true
  85 + rescue
  86 + false
66 end 87 end
67 88
68 def bulk_delete(project, user_ids) 89 def bulk_delete(project, user_ids)
69 UsersProject.transaction do 90 UsersProject.transaction do
70 - UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| 91 + UsersProject.where(user_id: user_ids, project_id: project.id).each do |users_project|
  92 + users_project.skip_git = true
71 users_project.destroy 93 users_project.destroy
72 end 94 end
  95 +
  96 + project.update_repository
73 end 97 end
74 end 98 end
75 99
76 def bulk_update(project, user_ids, project_access) 100 def bulk_update(project, user_ids, project_access)
77 UsersProject.transaction do 101 UsersProject.transaction do
78 - UsersProject.where(:user_id => user_ids, :project_id => project.id).each do |users_project| 102 + UsersProject.where(user_id: user_ids, project_id: project.id).each do |users_project|
79 users_project.project_access = project_access 103 users_project.project_access = project_access
  104 + users_project.skip_git = true
80 users_project.save 105 users_project.save
81 end 106 end
  107 + project.update_repository
82 end 108 end
83 end 109 end
84 110
  111 + # TODO: depreceate in future in favor of add_users_into_projects
85 def bulk_import(project, user_ids, project_access) 112 def bulk_import(project, user_ids, project_access)
86 - UsersProject.transaction do  
87 - user_ids.each do |user_id|  
88 - users_project = UsersProject.new(  
89 - project_access: project_access,  
90 - user_id: user_id  
91 - )  
92 - users_project.project = project  
93 - users_project.save  
94 - end  
95 - end 113 + add_users_into_projects([project.id], user_ids, project_access)
96 end 114 end
97 115
  116 + # TODO: depreceate in future in favor of add_users_into_projects
98 def user_bulk_import(user, project_ids, project_access) 117 def user_bulk_import(user, project_ids, project_access)
99 - UsersProject.transaction do  
100 - project_ids.each do |project_id|  
101 - users_project = UsersProject.new(  
102 - project_access: project_access,  
103 - )  
104 - users_project.project_id = project_id  
105 - users_project.user_id = user.id  
106 - users_project.save  
107 - end  
108 - end 118 + add_users_into_projects(project_ids, [user.id], project_access)
109 end 119 end
110 120
111 def access_roles 121 def access_roles
@@ -133,4 +143,8 @@ class UsersProject &lt; ActiveRecord::Base @@ -133,4 +143,8 @@ class UsersProject &lt; ActiveRecord::Base
133 def repo_access_human 143 def repo_access_human
134 self.class.access_roles.invert[self.project_access] 144 self.class.access_roles.invert[self.project_access]
135 end 145 end
  146 +
  147 + def skip_git?
  148 + !!@skip_git
  149 + end
136 end 150 end
app/roles/team.rb
@@ -34,19 +34,20 @@ module Team @@ -34,19 +34,20 @@ module Team
34 # with same access role by user ids 34 # with same access role by user ids
35 def add_users_ids_to_team(users_ids, access_role) 35 def add_users_ids_to_team(users_ids, access_role)
36 UsersProject.bulk_import(self, users_ids, access_role) 36 UsersProject.bulk_import(self, users_ids, access_role)
37 - self.update_repository  
38 end 37 end
39 38
40 # Update multiple project users 39 # Update multiple project users
41 # to same access role by user ids 40 # to same access role by user ids
42 def update_users_ids_to_role(users_ids, access_role) 41 def update_users_ids_to_role(users_ids, access_role)
43 UsersProject.bulk_update(self, users_ids, access_role) 42 UsersProject.bulk_update(self, users_ids, access_role)
44 - self.update_repository  
45 end 43 end
46 44
47 # Delete multiple users from project by user ids 45 # Delete multiple users from project by user ids
48 def delete_users_ids_from_team(users_ids) 46 def delete_users_ids_from_team(users_ids)
49 UsersProject.bulk_delete(self, users_ids) 47 UsersProject.bulk_delete(self, users_ids)
50 - self.update_repository 48 + end
  49 +
  50 + def truncate_team
  51 + UsersProject.bulk_delete(self, self.users.map(&:id))
51 end 52 end
52 end 53 end
app/views/groups/_new_group_member.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 %h6 1. Choose people you want in the team 5 %h6 1. Choose people you want in the team
6 .clearfix 6 .clearfix
7 = f.label :user_ids, "People" 7 = f.label :user_ids, "People"
8 - .input= select_tag(:user_ids, options_from_collection_for_select(User.active, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) 8 + .input= select_tag(:user_ids, options_from_collection_for_select(User.active.order('name ASC'), :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true})
9 9
10 %h6 2. Set access level for them 10 %h6 2. Set access level for them
11 .clearfix 11 .clearfix
app/views/groups/_new_member.html.haml
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 %h6 1. Choose people you want in the team 5 %h6 1. Choose people you want in the team
6 .clearfix 6 .clearfix
7 = f.label :user_ids, "People" 7 = f.label :user_ids, "People"
8 - .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) 8 + .input= select_tag(:user_ids, options_from_collection_for_select(User.not_in_project(@project).order('name').all, :id, :name), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true})
9 9
10 %h6 2. Set access level for them 10 %h6 2. Set access level for them
11 .clearfix 11 .clearfix
app/views/team_members/import.html.haml
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 %p.slead Choose project you want to use as team source: 9 %p.slead Choose project you want to use as team source:
10 .padded 10 .padded
11 = label_tag :source_project_id, "Project" 11 = label_tag :source_project_id, "Project"
12 - .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.projects, :id, :name), prompt: "Select project", class: "chosen xxlarge", required: true) 12 + .input= select_tag(:source_project_id, options_from_collection_for_select(current_user.authorized_projects, :id, :name_with_namespace), prompt: "Select project", class: "chosen xxlarge", required: true)
13 13
14 .actions 14 .actions
15 = submit_tag 'Import', class: "btn save-btn" 15 = submit_tag 'Import', class: "btn save-btn"