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 | 99 | def destroy |
100 | 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 | 105 | project.destroy |
106 | - UsersProject.set_callback(:destroy, :after, :update_repository) | |
107 | 106 | |
108 | 107 | respond_to do |format| |
109 | 108 | format.html { redirect_to root_path } | ... | ... |
app/models/group.rb
... | ... | @@ -13,9 +13,11 @@ |
13 | 13 | |
14 | 14 | class Group < Namespace |
15 | 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 | 21 | end |
20 | 22 | |
21 | 23 | def users | ... | ... |
app/models/users_project.rb
... | ... | @@ -23,11 +23,13 @@ class UsersProject < ActiveRecord::Base |
23 | 23 | belongs_to :user |
24 | 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 | 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 | 33 | validates :project_access, inclusion: { in: [GUEST, REPORTER, DEVELOPER, MASTER] }, presence: true |
32 | 34 | validates :project, presence: true |
33 | 35 | |
... | ... | @@ -36,76 +38,84 @@ class UsersProject < ActiveRecord::Base |
36 | 38 | scope :in_project, ->(project) { where(project_id: project.id) } |
37 | 39 | |
38 | 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 | 49 | end |
53 | 50 | end |
51 | + Gitlab::Gitolite.new.update_repositories(Project.where(id: project_ids)) | |
54 | 52 | end |
55 | 53 | |
56 | - target_project.update_repository | |
57 | 54 | true |
58 | 55 | rescue |
59 | 56 | false |
60 | 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 | 87 | end |
67 | 88 | |
68 | 89 | def bulk_delete(project, user_ids) |
69 | 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 | 93 | users_project.destroy |
72 | 94 | end |
95 | + | |
96 | + project.update_repository | |
73 | 97 | end |
74 | 98 | end |
75 | 99 | |
76 | 100 | def bulk_update(project, user_ids, project_access) |
77 | 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 | 103 | users_project.project_access = project_access |
104 | + users_project.skip_git = true | |
80 | 105 | users_project.save |
81 | 106 | end |
107 | + project.update_repository | |
82 | 108 | end |
83 | 109 | end |
84 | 110 | |
111 | + # TODO: depreceate in future in favor of add_users_into_projects | |
85 | 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 | 114 | end |
97 | 115 | |
116 | + # TODO: depreceate in future in favor of add_users_into_projects | |
98 | 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 | 119 | end |
110 | 120 | |
111 | 121 | def access_roles |
... | ... | @@ -133,4 +143,8 @@ class UsersProject < ActiveRecord::Base |
133 | 143 | def repo_access_human |
134 | 144 | self.class.access_roles.invert[self.project_access] |
135 | 145 | end |
146 | + | |
147 | + def skip_git? | |
148 | + !!@skip_git | |
149 | + end | |
136 | 150 | end | ... | ... |
app/roles/team.rb
... | ... | @@ -34,19 +34,20 @@ module Team |
34 | 34 | # with same access role by user ids |
35 | 35 | def add_users_ids_to_team(users_ids, access_role) |
36 | 36 | UsersProject.bulk_import(self, users_ids, access_role) |
37 | - self.update_repository | |
38 | 37 | end |
39 | 38 | |
40 | 39 | # Update multiple project users |
41 | 40 | # to same access role by user ids |
42 | 41 | def update_users_ids_to_role(users_ids, access_role) |
43 | 42 | UsersProject.bulk_update(self, users_ids, access_role) |
44 | - self.update_repository | |
45 | 43 | end |
46 | 44 | |
47 | 45 | # Delete multiple users from project by user ids |
48 | 46 | def delete_users_ids_from_team(users_ids) |
49 | 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 | 52 | end |
52 | 53 | end | ... | ... |
app/views/groups/_new_group_member.html.haml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | %h6 1. Choose people you want in the team |
6 | 6 | .clearfix |
7 | 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 | 10 | %h6 2. Set access level for them |
11 | 11 | .clearfix | ... | ... |
app/views/groups/_new_member.html.haml
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | %h6 1. Choose people you want in the team |
6 | 6 | .clearfix |
7 | 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 | 10 | %h6 2. Set access level for them |
11 | 11 | .clearfix | ... | ... |
app/views/team_members/import.html.haml
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | %p.slead Choose project you want to use as team source: |
10 | 10 | .padded |
11 | 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 | 14 | .actions |
15 | 15 | = submit_tag 'Import', class: "btn save-btn" | ... | ... |