Commit e37a043df76adff70456ca3aa6a66735fd0c4585
1 parent
151ada76
Exists in
master
and in
4 other branches
Get rid of skipping callbacks in production code. Dont trigger gitolite more tha…
…n once on import in group
Showing
7 changed files
with
72 additions
and
56 deletions
Show diff stats
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 < ActiveRecord::Base | @@ -23,11 +23,13 @@ class UsersProject < 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 < ActiveRecord::Base | @@ -36,76 +38,84 @@ class UsersProject < 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 < ActiveRecord::Base | @@ -133,4 +143,8 @@ class UsersProject < 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" |