Skip to content

Commit 2912c1d

Browse files
author
root
committed
Handle Redmine groups in ProtectedBranches
1 parent 245597e commit 2912c1d

15 files changed

+216
-46
lines changed

Diff for: app/helpers/repository_protected_branches_helper.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
module RepositoryProtectedBranchesHelper
22

33
def protected_branch_available_users
4-
@project.member_principals.map(&:user).uniq.sort
4+
@project.member_principals.map(&:principal).select { |m| m.class.name == 'User' }.uniq.sort
5+
end
6+
7+
def protected_branch_available_groups
8+
@project.member_principals.map(&:principal).select { |m| m.class.name == 'Group' }.uniq.sort
59
end
610

711
end

Diff for: app/models/protected_branches_member.rb

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class ProtectedBranchesMember < ActiveRecord::Base
2+
unloadable
3+
4+
## Relations
5+
belongs_to :protected_branch, class_name: 'RepositoryProtectedBranche'
6+
belongs_to :principal
7+
8+
## Callbacks
9+
after_destroy :remove_dependent_objects
10+
11+
12+
private
13+
14+
15+
def remove_dependent_objects
16+
return unless principal.class.name == 'Group'
17+
principal.users.each do |user|
18+
member = self.class.find_by_principal_id_and_inherited_by(user.id, principal.id)
19+
member.destroy! unless member.nil?
20+
end
21+
end
22+
23+
end

Diff for: app/models/protected_branches_user.rb

-7
This file was deleted.

Diff for: app/models/repository_protected_branche.rb

+75-3
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ class RepositoryProtectedBranche < ActiveRecord::Base
77
acts_as_list
88

99
## Attributes
10-
attr_accessible :path, :permissions, :position, :user_ids
10+
attr_accessible :path, :permissions, :position, :user_ids, :group_ids
1111

1212
## Relations
1313
belongs_to :repository
14-
has_many :protected_branches_users, foreign_key: :protected_branch_id, dependent: :destroy
15-
has_many :users, through: :protected_branches_users
14+
has_many :protected_branches_members, foreign_key: :protected_branch_id, dependent: :destroy
15+
has_many :members, through: :protected_branches_members, source: :principal
1616

1717
## Validations
1818
validates :repository_id, presence: true
@@ -36,8 +36,80 @@ def clone_from(parent)
3636
end
3737

3838

39+
# Accessors
40+
#
41+
def users
42+
members.select { |m| m.class.name == 'User' }.uniq
43+
end
44+
45+
46+
def groups
47+
members.select { |m| m.class.name == 'Group' }
48+
end
49+
50+
3951
def allowed_users
4052
users.map { |u| u.gitolite_identifier }.sort
4153
end
4254

55+
56+
# Mass assignment
57+
#
58+
def user_ids=(ids)
59+
current_ids = users.map(&:id)
60+
create_member(ids, current_ids, 'User')
61+
end
62+
63+
64+
def group_ids=(ids)
65+
current_ids = groups.map(&:id)
66+
create_member(ids, current_ids, 'Group') do |group|
67+
ids = group.users.map(&:id)
68+
current_ids = users_by_group_id(group.id).map(&:id)
69+
create_member(ids, current_ids, 'User', inherited_by: group.id, destroy: false)
70+
end
71+
end
72+
73+
74+
# Triggered by Group callbacks
75+
#
76+
def add_user_member(user, group)
77+
ids = users_by_group_id(group.id).push(user).map(&:id)
78+
current_ids = users_by_group_id(group.id).map(&:id)
79+
create_member(ids, current_ids, 'User', inherited_by: group.id, destroy: false)
80+
end
81+
82+
83+
def remove_user_member(user, group)
84+
return unless users_by_group_id(group.id).include?(user)
85+
member = protected_branches_members.find_by_protected_branch_id_and_principal_id_and_inherited_by(id, user.id, group.id)
86+
member.destroy! unless member.nil?
87+
end
88+
89+
90+
private
91+
92+
93+
def users_by_group_id(id)
94+
protected_branches_members.select { |pbm| pbm.principal.class.name == 'User' && pbm.inherited_by == id }.map(&:principal)
95+
end
96+
97+
98+
def create_member(ids, current_ids, klass, destroy: true, inherited_by: nil, &block)
99+
ids = (ids || []).collect(&:to_i) - [0]
100+
new_ids = ids - current_ids
101+
102+
new_ids.each do |id|
103+
object = klass.constantize.find_by_id(id)
104+
next if object.nil?
105+
protected_branches_members.create(principal_id: object.id, inherited_by: inherited_by)
106+
yield object if block_given?
107+
end
108+
109+
if destroy
110+
member_to_destroy = protected_branches_members.select { |m| m.principal.class.name == klass && !ids.include?(m.principal.id) }
111+
member_to_destroy.each(&:destroy) if member_to_destroy.any?
112+
end
113+
end
114+
43115
end

Diff for: app/views/repository_protected_branches/_form.html.haml

+19-8
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,24 @@
55
%p= f.select :permissions, options_for_select(RepositoryProtectedBranche::VALID_PERMS, @protected_branch.permissions), required: true, label: :label_permissions
66

77
= hidden_field_tag 'repository_protected_branche[user_ids][]', ''
8+
= hidden_field_tag 'repository_protected_branche[group_ids][]', ''
89

9-
%p
10-
%label{ for: 'repository_protected_branche[user_ids]' }= l(:label_user_list) + ' :'
10+
.container
11+
.row
12+
.col-md-6
13+
%h4= label_with_icon(l('label_user_plural'), 'fa-user')
14+
- protected_branch_available_users.each do |user|
15+
%p{ style: 'padding: 0px;' }
16+
%label{ style: 'margin-left: 0; width: auto; font-weight: lighter;' }
17+
= check_box_tag 'repository_protected_branche[user_ids][]', user.id, @protected_branch.users.include?(user)
18+
= user
19+
%br
1120

12-
- protected_branch_available_users.each do |user|
13-
%p
14-
%label{ style: 'margin-left: 0; width: auto; font-weight: lighter;' }
15-
= check_box_tag 'repository_protected_branche[user_ids][]', user.id, @protected_branch.users.include?(user)
16-
= user
17-
%br
21+
.col-md-6
22+
%h4= label_with_icon(l('label_group_plural'), 'fa-users')
23+
- protected_branch_available_groups.each do |group|
24+
%p{ style: 'padding: 0px;' }
25+
%label{ style: 'margin-left: 0; width: auto; font-weight: lighter;' }
26+
= check_box_tag 'repository_protected_branche[group_ids][]', group.id, @protected_branch.groups.include?(group)
27+
= group
28+
%br

Diff for: app/views/repository_protected_branches/index.html.haml

+1-3
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,7 @@
3434

3535
%td{ style: 'font-family: Consolas;' }= protected_branch.path
3636

37-
%td
38-
- protected_branch.users.each do |user|
39-
%span{ class: 'label label-info' }= user
37+
%td= protected_branch.users.map { |u| link_to(u) }.join(', ').html_safe
4038

4139
%td{ class: 'buttons' }
4240
- if User.current.git_allowed_to?(:edit_repository_protected_branches, @repository)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
class CreateProtectedBranchesMembers < ActiveRecord::Migration
2+
3+
def self.up
4+
create_table :protected_branches_members do |t|
5+
t.column :protected_branch_id, :integer
6+
t.column :principal_id, :integer
7+
t.column :inherited_by, :integer
8+
end
9+
10+
add_index :protected_branches_members, [:protected_branch_id, :principal_id, :inherited_by], unique: true, name: 'unique_protected_branch_member'
11+
end
12+
13+
def self.down
14+
drop_table :protected_branches_members
15+
end
16+
17+
end

Diff for: db/migrate/20150823030000_create_protected_branches_users.rb

-16
This file was deleted.

Diff for: db/migrate/20150823030100_migrate_protected_branches_users.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class MigrateProtectedBranchesUsers < ActiveRecord::Migration
77
def self.up
88
RepositoryProtectedBrancheWrapped.all.each do |protected_branch|
99
users = protected_branch.user_list.map { |u| User.find_by_login(u) }.compact.uniq
10-
protected_branch.users << users
10+
protected_branch.user_ids = users.map(&:id)
1111
end
1212
remove_column :repository_protected_branches, :user_list
1313
end

Diff for: lib/redmine_git_hosting/patches/group_patch.rb

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
require_dependency 'group'
2+
3+
module RedmineGitHosting
4+
module Patches
5+
module GroupPatch
6+
7+
def self.included(base)
8+
base.send(:include, InstanceMethods)
9+
base.class_eval do
10+
unloadable
11+
12+
# Relations
13+
has_many :protected_branches_members, dependent: :destroy, foreign_key: :principal_id
14+
has_many :protected_branches, through: :protected_branches_members
15+
16+
alias_method_chain :user_added, :git_hosting
17+
alias_method_chain :user_removed, :git_hosting
18+
end
19+
end
20+
21+
22+
module InstanceMethods
23+
24+
def user_added_with_git_hosting(user, &block)
25+
user_added_without_git_hosting(user, &block)
26+
protected_branches.each do |pb|
27+
pb.add_user_member(user, self)
28+
end
29+
end
30+
31+
32+
def user_removed_with_git_hosting(user, &block)
33+
user_removed_without_git_hosting(user, &block)
34+
protected_branches.each do |pb|
35+
pb.remove_user_member(user, self)
36+
end
37+
end
38+
39+
end
40+
41+
end
42+
end
43+
end
44+
45+
unless Group.included_modules.include?(RedmineGitHosting::Patches::GroupPatch)
46+
Group.send(:include, RedmineGitHosting::Patches::GroupPatch)
47+
end

Diff for: lib/redmine_git_hosting/patches/user_patch.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ def self.included(base)
1414

1515
# Relations
1616
has_many :gitolite_public_keys, dependent: :destroy
17-
has_many :protected_branches_users, dependent: :destroy
18-
has_many :protected_branches, through: :protected_branches_users
17+
18+
has_many :protected_branches_members, dependent: :destroy, foreign_key: :principal_id
19+
has_many :protected_branches, through: :protected_branches_members
1920

2021
# Callbacks
2122
after_save :check_if_status_changed

Diff for: spec/factories/group.rb

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FactoryGirl.define do
2+
3+
factory :group do |f|
4+
f.sequence(:lastname) { |n| "GroupTest#{n}" }
5+
end
6+
7+
end

Diff for: spec/models/group_spec.rb

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2+
3+
describe Group do
4+
5+
before(:each) do
6+
@group = build(:group)
7+
end
8+
9+
subject { @group }
10+
11+
it { should have_many(:protected_branches_members).dependent(:destroy) }
12+
it { should have_many(:protected_branches).through(:protected_branches_members) }
13+
end

Diff for: spec/models/repository_protected_branche_spec.rb

+3-3
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ def build_protected_branch(opts = {})
2222

2323
## Relations
2424
it { should belong_to(:repository) }
25-
it { should have_many(:protected_branches_users).with_foreign_key(:protected_branch_id).dependent(:destroy) }
26-
it { should have_many(:users).through(:protected_branches_users) }
25+
it { should have_many(:protected_branches_members).with_foreign_key(:protected_branch_id).dependent(:destroy) }
26+
it { should have_many(:members).through(:protected_branches_members) }
2727

2828
## Validations
2929
it { should be_valid }
@@ -34,6 +34,6 @@ def build_protected_branch(opts = {})
3434

3535
it { should validate_uniqueness_of(:path).scoped_to([:permissions, :repository_id]) }
3636

37-
it { should validate_inclusion_of(:permissions).in_array(%w(RW RW+)) }
37+
it { should validate_inclusion_of(:permissions).in_array RepositoryProtectedBranche::VALID_PERMS }
3838
end
3939
end

Diff for: spec/models/user_spec.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
subject { @user }
1010

11-
it { should have_many(:protected_branches_users).dependent(:destroy) }
12-
it { should have_many(:protected_branches).through(:protected_branches_users) }
11+
it { should have_many(:protected_branches_members).dependent(:destroy) }
12+
it { should have_many(:protected_branches).through(:protected_branches_members) }
1313

1414
it "has a gitolite_identifier" do
1515
user = create(:user)

0 commit comments

Comments
 (0)