Skip to content

Commit 62c0c23

Browse files
author
root
committed
Add support of protected branch (#86)
1 parent ea4bc49 commit 62c0c23

File tree

9 files changed

+153
-26
lines changed

9 files changed

+153
-26
lines changed

Diff for: app/controllers/repository_protected_branches_controller.rb

+11-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class RepositoryProtectedBranchesController < RedmineGitHostingController
66
before_filter :can_create_protected_branches, :only => [:new, :create]
77
before_filter :can_edit_protected_branches, :only => [:edit, :update, :destroy]
88

9-
before_filter :find_repository_protected_branch, :except => [:index, :new, :create]
9+
before_filter :find_repository_protected_branch, :except => [:index, :new, :create, :sort]
1010

1111

1212
def index
@@ -21,6 +21,8 @@ def index
2121

2222
def new
2323
@protected_branch = RepositoryProtectedBranche.new()
24+
@protected_branch.repository = @repository
25+
@protected_branch.user_list = []
2426
end
2527

2628

@@ -81,6 +83,14 @@ def clone
8183
end
8284

8385

86+
def sort
87+
params[:repository_protected_branche].each_with_index do |id, index|
88+
RepositoryProtectedBranche.update_all({position: index + 1}, {id: id})
89+
end
90+
render :nothing => true
91+
end
92+
93+
8494
private
8595

8696

Diff for: app/models/repository_protected_branche.rb

+33-5
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,56 @@
11
class RepositoryProtectedBranche < ActiveRecord::Base
22
unloadable
33

4-
VALID_PERMS = [ "RW+", "RW", "R", '-' ]
4+
VALID_PERMS = [ "RW+", "RW" ]
55
DEFAULT_PERM = "RW+"
66

7-
attr_accessible :role_id, :path, :permissions
7+
attr_accessible :path, :permissions, :position, :user_list
8+
9+
acts_as_list
810

911
## Relations
1012
belongs_to :repository
11-
belongs_to :role
1213

1314
## Validations
1415
validates :repository_id, :presence => true
15-
validates :role_id, :presence => true
16-
validates :path, :presence => true
16+
validates :path, :presence => true, :uniqueness => { :scope => :permissions }
1717
validates :permissions, :presence => true, :inclusion => { :in => VALID_PERMS }
18+
validates :user_list, :presence => true
19+
20+
## Serializations
21+
serialize :user_list, Array
1822

1923
## Callbacks
24+
before_validation :remove_blank_items
25+
2026
after_commit ->(obj) { obj.update_permissions }, :on => :create
2127
after_commit ->(obj) { obj.update_permissions }, :on => :update
2228
after_commit ->(obj) { obj.update_permissions }, :on => :destroy
2329

30+
## Scopes
31+
default_scope order('position ASC')
32+
2433

2534
def self.clone_from(parent)
2635
parent = find_by_id(parent) unless parent.kind_of? RepositoryProtectedBranche
2736
copy = self.new
2837
copy.attributes = parent.attributes
38+
copy.repository = parent.repository
2939

3040
copy
3141
end
3242

3343

44+
def available_users
45+
repository.project.member_principals.map(&:user).compact.uniq.map{ |user| user.login }.sort
46+
end
47+
48+
49+
def allowed_users
50+
self.user_list.map{ |user| User.find_by_login(user).gitolite_identifier }.sort
51+
end
52+
53+
3454
protected
3555

3656

@@ -39,4 +59,12 @@ def update_permissions
3959
RedmineGitolite::GitHosting.resync_gitolite(:update_repository, repository.id)
4060
end
4161

62+
63+
private
64+
65+
66+
def remove_blank_items
67+
self.user_list = user_list.select{ |user| !user.blank? }
68+
end
69+
4270
end
+47-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,55 @@
11
<div id="validation_messages_protected_branch"><%= error_messages_for 'protected_branch' %></div>
22

3-
<% roles = Role.find_all_givable %>
4-
53
<div class="box">
6-
<p><%= f.select :role_id, roles.collect{|role| [role.name, role.id]}, :required => true %></p>
74
<p><%= f.text_field :path, :required => true, :size => 65, :label => l(:label_branch_path) %></p>
8-
<p><%= f.select :permissions, options_for_select(RepositoryProtectedBranche::VALID_PERMS, RepositoryProtectedBranche::DEFAULT_PERM),
5+
<p><%= f.select :permissions, options_for_select(RepositoryProtectedBranche::VALID_PERMS, @protected_branch.permissions),
96
:required => true,
107
:label => :label_permissions %>
118
</p>
9+
10+
<%= hidden_field_tag "repository_protected_branches[user_list][]", "" %>
11+
12+
<p><label for="repository_protected_branches[user_list]"><%= l(:label_user_list) %> :</label></p>
13+
<ul id="user_list">
14+
<% if @protected_branch.user_list.any? %>
15+
<% @protected_branch.user_list.each do |item| %>
16+
<li><%= item %></li>
17+
<% end %>
18+
<% end %>
19+
</ul>
1220
</div>
21+
22+
<%= javascript_tag do %>
23+
var user_list = <%= raw @protected_branch.available_users.to_json %>;
24+
25+
function loadTagIt(target){
26+
27+
$('#' + target).gtagit({
28+
autocomplete: {source: function(request, resolve) {
29+
// fetch new values with request.resolve
30+
resolve(user_list);
31+
}
32+
},
33+
afterTagAdded: function(event, ui) {
34+
var value = ui.tag.children('input:hidden').val();
35+
user_list = user_list.filter(function(v) { return v != value;});
36+
$(".ui-dialog-content").dialog("option", "position", ['center', 'center']).animate('slow');
37+
},
38+
afterTagRemoved: function(event, ui) {
39+
var value = ui.tag.children('input:hidden').val();
40+
user_list.push(value);
41+
$(".ui-dialog-content").dialog("option", "position", ['center', 'center']).animate('slow');
42+
},
43+
showAutocompleteOnFocus: true,
44+
placeholderText: '+ add user',
45+
allowDuplicates: false,
46+
caseSensitive: false,
47+
fieldName: 'repository_protected_branches[' + target + '][]',
48+
});
49+
50+
}
51+
52+
$(document).ready(function() {
53+
loadTagIt('user_list');
54+
});
55+
<% end %>

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

+27-7
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,31 @@
1212

1313
<% if @repository_protected_branches.any? %>
1414

15-
<table class="table table-hover">
15+
<table id="protected_branches" class="table table-hover" data-update-url="<%= sort_repository_protected_branches_url %>">
1616
<thead>
1717
<tr>
18-
<th><%= l(:label_role) %></th>
18+
<th></th>
1919
<th><%= l(:label_branch_path) %></th>
2020
<th><%= l(:label_permissions) %></th>
21+
<th><%= l(:label_user_list) %></th>
2122
<th></th>
2223
</tr>
2324
</thead>
2425

2526
<tbody>
2627
<% @repository_protected_branches.each do |protected_branch| %>
27-
<tr>
28-
<td><span class="label label-info"><%= protected_branch.role %></span></td>
29-
<td><span class="label label-info"><%= protected_branch.path %></span></td>
28+
<%= content_tag_for(:tr, protected_branch) do %>
29+
<td><span class="handle">[drag]</span></td>
30+
<td style="font-family: Consolas;" ><%= protected_branch.path %></td>
3031
<td>
3132
<% color = protected_branch.permissions == '-' ? 'important' : 'success' %>
3233
<span class="label label-<%= color %>"><%= protected_branch.permissions %></span>
3334
</td>
34-
35+
<td>
36+
<% protected_branch.user_list.each do |user| %>
37+
<span class="label label-info"><%= user %></span>
38+
<% end %>
39+
</td>
3540
<td class="buttons">
3641
<% if user_allowed_to(:edit_repository_protected_branches, @project) %>
3742

@@ -48,7 +53,7 @@
4853
:class => 'icon icon-del' %>
4954
<% end %>
5055
</td>
51-
</tr>
56+
<% end %>
5257
<% end %>
5358
</tbody>
5459
</table>
@@ -60,7 +65,22 @@
6065
</div>
6166

6267
<%= javascript_tag do %>
68+
// Return a helper with preserved width of cells
69+
var fixHelper = function(e, ui) {
70+
ui.children().each(function() {
71+
$(this).width($(this).width());
72+
});
73+
return ui;
74+
};
75+
6376
$(document).ready(function() {
6477
initModalBoxes(modals);
78+
$('#protected_branches tbody').sortable({
79+
helper: fixHelper,
80+
axis: 'y',
81+
update: function(event, ui) {
82+
$.post($('#protected_branches').data('update-url'), $(this).sortable('serialize'));
83+
}
84+
});
6585
});
6686
<% end %>

Diff for: config/locales/plugin_interface/en.yml

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ en:
113113
notice_protected_branch_update_failed: Failed to update protected branch
114114

115115
label_branch_path: Branch path
116+
label_user_list: Users allowed
116117

117118

118119
########### GIT NOTIFICATIONS ###########

Diff for: config/locales/plugin_interface/fr.yml

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ fr:
113113
notice_protected_branch_update_failed: Échec de modification de la branche protégée
114114

115115
label_branch_path: Chemin de la branche
116+
label_user_list: Liste des utilisateurs autorisés
116117

117118

118119
########### GIT NOTIFICATIONS ###########

Diff for: config/routes.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
resources :deployment_credentials, controller: 'repository_deployment_credentials'
2020
resources :git_notifications, controller: 'repository_git_notifications'
2121
resources :git_config_keys, controller: 'repository_git_config_keys'
22-
resources :protected_branches, controller: 'repository_protected_branches'
22+
resources :protected_branches, controller: 'repository_protected_branches' do
23+
collection { post :sort }
24+
end
2325
end
2426
end
2527

Diff for: db/migrate/20140621004200_create_repository_protected_branches.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ class CreateRepositoryProtectedBranches < ActiveRecord::Migration
22
def self.up
33
create_table :repository_protected_branches do |t|
44
t.column :repository_id, :integer, :null => false
5-
t.column :role_id, :integer, :null => false
65
t.column :path, :string, :null => false
76
t.column :permissions, :string, :null => false
7+
t.column :user_list, :text, :null => false
8+
t.column :position, :integer
89
end
910
end
1011

Diff for: lib/redmine_gitolite/gitolite_wrapper/repositories_helper.rb

+28-7
Original file line numberDiff line numberDiff line change
@@ -232,12 +232,12 @@ def build_permissions(repository)
232232
rewind_users = users.select{|user| user.allowed_to?(:manage_repository, project)}
233233
write_users = users.select{|user| user.allowed_to?(:commit_access, project)} - rewind_users
234234
read_users = users.select{|user| user.allowed_to?(:view_changesets, project)} - rewind_users - write_users
235-
developer_team = rewind_users + write_users
236235

237236
if project.active?
238-
rewind = rewind_users.map{|user| user.gitolite_identifier}
239-
write = write_users.map{|user| user.gitolite_identifier}
240-
read = read_users.map{|user| user.gitolite_identifier}
237+
rewind = rewind_users.map{|user| user.gitolite_identifier}.sort
238+
write = write_users.map{|user| user.gitolite_identifier}.sort
239+
read = read_users.map{|user| user.gitolite_identifier}.sort
240+
developer_team = rewind + write
241241

242242
## DEPLOY KEY
243243
repository.deployment_credentials.active.each do |cred|
@@ -260,9 +260,30 @@ def build_permissions(repository)
260260
end
261261

262262
permissions = {}
263-
permissions["RW+"] = {"" => rewind.uniq.sort} unless rewind.empty?
264-
permissions["RW"] = {"" => write.uniq.sort} unless write.empty?
265-
permissions["R"] = {"" => read.uniq.sort} unless read.empty?
263+
permissions["RW+"] = {}
264+
permissions["RW"] = {}
265+
permissions["R"] = {}
266+
267+
if repository.extra[:protected_branch]
268+
## http://gitolite.com/gitolite/rules.html
269+
## The refex field is ignored for read check.
270+
## (Git does not support distinguishing one ref from another for access control during read operations).
271+
272+
repository.protected_branches.each do |branch|
273+
case branch.permissions
274+
when 'RW+'
275+
permissions["RW+"][branch.path] = branch.allowed_users unless branch.allowed_users.empty?
276+
when 'RW'
277+
permissions["RW"][branch.path] = branch.allowed_users unless branch.allowed_users.empty?
278+
end
279+
end
280+
281+
permissions["RW+"]['personal/USER/'] = developer_team.sort unless developer_team.empty?
282+
end
283+
284+
permissions["RW+"][""] = rewind unless rewind.empty?
285+
permissions["RW"][""] = write unless write.empty?
286+
permissions["R"][""] = read unless read.empty?
266287

267288
permissions
268289
end

0 commit comments

Comments
 (0)