Commit cb021e58314791c1c9eb8035ed01349876d246a1

Authored by Dmitriy Zaporozhets
1 parent 2ca00bdb

repo & project access separated. critical gitolite bugfix

app/controllers/team_members_controller.rb
@@ -25,15 +25,10 @@ class TeamMembersController < ApplicationController @@ -25,15 +25,10 @@ class TeamMembersController < ApplicationController
25 @team_member = project.users_projects.find(params[:id]) 25 @team_member = project.users_projects.find(params[:id])
26 @team_member.update_attributes(params[:team_member]) 26 @team_member.update_attributes(params[:team_member])
27 27
28 - respond_to do |format|  
29 - format.js  
30 - format.html do  
31 - unless @team_member.valid?  
32 - flash[:alert] = "User should have at least one role"  
33 - end  
34 - redirect_to team_project_path(@project)  
35 - end 28 + unless @team_member.valid?
  29 + flash[:alert] = "User should have at least one role"
36 end 30 end
  31 + redirect_to team_project_path(@project)
37 end 32 end
38 33
39 def destroy 34 def destroy
app/models/key.rb
@@ -23,7 +23,7 @@ class Key < ActiveRecord::Base @@ -23,7 +23,7 @@ class Key < ActiveRecord::Base
23 c.update_keys(identifier, key) 23 c.update_keys(identifier, key)
24 24
25 projects.each do |project| 25 projects.each do |project|
26 - c.update_project(project.path, project.repository_writers) 26 + c.update_project(project.path, project)
27 end 27 end
28 end 28 end
29 end 29 end
@@ -33,7 +33,7 @@ class Key < ActiveRecord::Base @@ -33,7 +33,7 @@ class Key < ActiveRecord::Base
33 c.delete_key(identifier) 33 c.delete_key(identifier)
34 34
35 projects.each do |project| 35 projects.each do |project|
36 - c.update_project(project.path, project.repository_writers) 36 + c.update_project(project.path, project)
37 end 37 end
38 end 38 end
39 end 39 end
app/models/project.rb
1 require "grit" 1 require "grit"
2 2
3 class Project < ActiveRecord::Base 3 class Project < ActiveRecord::Base
  4 + PROJECT_N = 0
  5 + PROJECT_R = 1
  6 + PROJECT_RW = 2
  7 + PROJECT_RWA = 3
  8 +
4 belongs_to :owner, :class_name => "User" 9 belongs_to :owner, :class_name => "User"
5 10
6 has_many :merge_requests, :dependent => :destroy 11 has_many :merge_requests, :dependent => :destroy
@@ -47,6 +52,16 @@ class Project &lt; ActiveRecord::Base @@ -47,6 +52,16 @@ class Project &lt; ActiveRecord::Base
47 52
48 scope :public_only, where(:private_flag => false) 53 scope :public_only, where(:private_flag => false)
49 54
  55 +
  56 + def self.access_options
  57 + {
  58 + "Denied" => PROJECT_N,
  59 + "Read" => PROJECT_R,
  60 + "Report" => PROJECT_RW,
  61 + "Admin" => PROJECT_RWA
  62 + }
  63 + end
  64 +
50 def repository 65 def repository
51 @repository ||= Repository.new(self) 66 @repository ||= Repository.new(self)
52 end 67 end
@@ -109,21 +124,28 @@ class Project &lt; ActiveRecord::Base @@ -109,21 +124,28 @@ class Project &lt; ActiveRecord::Base
109 users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id 124 users_projects.where(:project_id => self.id, :user_id => user.id).destroy if self.id
110 end 125 end
111 126
112 - def writers  
113 - @writers ||= users_projects.includes(:user).where(:write => true).map(&:user) 127 + def repository_readers
  128 + keys = Key.joins({:user => :users_projects}).
  129 + where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_R)
  130 + keys.map(&:identifier)
114 end 131 end
115 132
116 def repository_writers 133 def repository_writers
117 - keys = Key.joins({:user => :users_projects}).where("users_projects.project_id = ? AND users_projects.write = ?", id, true) 134 + keys = Key.joins({:user => :users_projects}).
  135 + where("users_projects.project_id = ? AND users_projects.repo_access = ?", id, Repository::REPO_RW)
118 keys.map(&:identifier) 136 keys.map(&:identifier)
119 end 137 end
120 138
121 def readers 139 def readers
122 - @readers ||= users_projects.includes(:user).where(:read => true).map(&:user) 140 + @readers ||= users_projects.includes(:user).where(:project_access => [PROJECT_R, PROJECT_RW, PROJECT_RWA]).map(&:user)
  141 + end
  142 +
  143 + def writers
  144 + @writers ||= users_projects.includes(:user).where(:project_access => [PROJECT_RW, PROJECT_RWA]).map(&:user)
123 end 145 end
124 146
125 def admins 147 def admins
126 - @admins ||=users_projects.includes(:user).where(:admin => true).map(&:user) 148 + @admins ||= users_projects.includes(:user).where(:project_access => PROJECT_RWA).map(&:user)
127 end 149 end
128 150
129 def root_ref 151 def root_ref
app/models/repository.rb
1 require File.join(Rails.root, "lib", "gitlabhq", "git_host") 1 require File.join(Rails.root, "lib", "gitlabhq", "git_host")
2 2
3 class Repository 3 class Repository
  4 + REPO_N = 0
  5 + REPO_R = 1
  6 + REPO_RW = 2
  7 +
4 attr_accessor :project 8 attr_accessor :project
5 9
6 def self.default_ref 10 def self.default_ref
7 "master" 11 "master"
8 end 12 end
9 13
  14 + def self.access_options
  15 + {
  16 + "Denied" => REPO_N,
  17 + "Pull" => REPO_R,
  18 + "Pull & Push" => REPO_RW
  19 + }
  20 + end
  21 +
10 def initialize(project) 22 def initialize(project)
11 @project = project 23 @project = project
12 end 24 end
@@ -33,7 +45,7 @@ class Repository @@ -33,7 +45,7 @@ class Repository
33 45
34 def update_repository 46 def update_repository
35 Gitlabhq::GitHost.system.new.configure do |c| 47 Gitlabhq::GitHost.system.new.configure do |c|
36 - c.update_project(path, project.repository_writers) 48 + c.update_project(path, project)
37 end 49 end
38 end 50 end
39 51
app/models/users_project.rb
@@ -4,25 +4,20 @@ class UsersProject &lt; ActiveRecord::Base @@ -4,25 +4,20 @@ class UsersProject &lt; ActiveRecord::Base
4 4
5 attr_protected :project_id, :project 5 attr_protected :project_id, :project
6 6
7 - after_commit :update_repository 7 + after_save :update_repository
  8 + after_destroy :update_repository
8 9
9 validates_uniqueness_of :user_id, :scope => [:project_id] 10 validates_uniqueness_of :user_id, :scope => [:project_id]
10 validates_presence_of :user_id 11 validates_presence_of :user_id
11 validates_presence_of :project_id 12 validates_presence_of :project_id
12 - validate :user_has_a_role_selected  
13 13
14 delegate :name, :email, :to => :user, :prefix => true 14 delegate :name, :email, :to => :user, :prefix => true
15 15
16 def update_repository 16 def update_repository
17 - Gitosis.new.configure do |c|  
18 - c.update_project(project.path, project.repository) 17 + Gitlabhq::GitHost.system.new.configure do |c|
  18 + c.update_project(project.path, project)
19 end 19 end
20 end 20 end
21 -  
22 - def user_has_a_role_selected  
23 - errors.add(:base, "Please choose at least one Role in the Access list") unless read || write || admin  
24 - end  
25 -  
26 end 21 end
27 # == Schema Information 22 # == Schema Information
28 # 23 #
app/views/projects/_team.html.haml
@@ -5,14 +5,19 @@ @@ -5,14 +5,19 @@
5 %table.round-borders#team-table 5 %table.round-borders#team-table
6 %thead 6 %thead
7 %th Name 7 %th Name
8 - %th Web  
9 - %th Git  
10 - %th Admin 8 + %th Project
  9 + %th Repository
11 - if can? current_user, :admin_team_member, @project 10 - if can? current_user, :admin_team_member, @project
12 %th Actions 11 %th Actions
13 - @project.users_projects.each do |up| 12 - @project.users_projects.each do |up|
14 = render(:partial => 'team_members/show', :locals => {:member => up}) 13 = render(:partial => 'team_members/show', :locals => {:member => up})
15 14
16 :javascript 15 :javascript
  16 + $(function(){
  17 + $('.repo-access-select, .project-access-select').live("change", function() {
  18 + $(this.form).submit();
  19 + });
  20 + })
  21 +
17 $('.delete-team-member').live('ajax:success', function() { 22 $('.delete-team-member').live('ajax:success', function() {
18 $(this).closest('tr').fadeOut(); }); 23 $(this).closest('tr').fadeOut(); });
app/views/team_members/_show.html.haml
1 - user = member.user 1 - user = member.user
  2 +- allow_admin = can? current_user, :admin_project, @project
2 %tr{:id => dom_id(member)} 3 %tr{:id => dom_id(member)}
3 %td 4 %td
4 = link_to image_tag(gravatar_icon(user.email), :class => "left", :width => 40, :style => "padding:0 5px;"), project_team_member_path(@project, member) 5 = link_to image_tag(gravatar_icon(user.email), :class => "left", :width => 40, :style => "padding:0 5px;"), project_team_member_path(@project, member)
@@ -6,15 +7,13 @@ @@ -6,15 +7,13 @@
6 = link_to truncate(user.name, :lenght => 24), project_team_member_path(@project, member) 7 = link_to truncate(user.name, :lenght => 24), project_team_member_path(@project, member)
7 %br 8 %br
8 .cgray{:style => "padding-top:10px;"}= truncate user.email, :lenght => 24 9 .cgray{:style => "padding-top:10px;"}= truncate user.email, :lenght => 24
9 - - if can? current_user, :admin_project, @project  
10 - = form_for(member, :as => :team_member, :url => project_team_member_path(@project, member)) do |f|  
11 - %td= f.check_box :read, :onclick => "$(this.form).submit();"  
12 - %td= f.check_box :write, :onclick => "$(this.form).submit();"  
13 - %td= f.check_box :admin, :onclick => "$(this.form).submit();"  
14 - - else  
15 - %td= check_box_tag "read", 1, member.read, :disabled => :disabled  
16 - %td= check_box_tag "commit", 1, member.write, :disabled => :disabled  
17 - %td= check_box_tag "admin", 1, member.admin, :disabled => :disabled  
18 - - if can? current_user, :admin_team_member, @project 10 + %td
  11 + = form_for(member, :as => :team_member, :url => project_team_member_path(@project, member)) do |f|
  12 + = f.select :project_access, options_for_select(Project.access_options, member.project_access), {}, :class => "project-access-select", :disabled => !allow_admin
  13 + %td
  14 + = form_for(member, :as => :team_member, :url => project_team_member_path(@project, member)) do |f|
  15 + = f.select :repo_access, options_for_select(Repository.access_options, member.repo_access), {}, :class => "repo-access-select", :disabled => !allow_admin
  16 + - if allow_admin
19 %td 17 %td
20 = link_to 'Cancel', project_team_member_path(:project_id => @project, :id => member.id), :confirm => 'Are you sure?', :method => :delete, :class => "grey-button negative delete-team-member", :remote => true 18 = link_to 'Cancel', project_team_member_path(:project_id => @project, :id => member.id), :confirm => 'Are you sure?', :method => :delete, :class => "grey-button negative delete-team-member", :remote => true
  19 +
db/migrate/20111206213842_add_advanced_rights_to_team_member.rb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +class AddAdvancedRightsToTeamMember < ActiveRecord::Migration
  2 + def change
  3 + add_column :users_projects, :repo_access, :integer, :default => 0, :null => false
  4 + add_column :users_projects, :project_access, :integer, :default => 0, :null => false
  5 + end
  6 +end
db/migrate/20111206222316_migrate_to_new_rights.rb 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +class MigrateToNewRights < ActiveRecord::Migration
  2 + def up
  3 + # Repository access
  4 + UsersProject.update_all("repo_access = 2", :write => true)
  5 + UsersProject.update_all("repo_access = 1", :read => true, :write => false)
  6 +
  7 + # Project access
  8 + UsersProject.update_all("project_access = 1", :read => true, :write => false, :admin => false)
  9 + UsersProject.update_all("project_access = 2", :read => true, :write => true, :admin => false)
  10 + UsersProject.update_all("project_access = 3", :read => true, :write => true, :admin => true)
  11 +
  12 + # Remove old fields
  13 + remove_column :users_projects, :read
  14 + remove_column :users_projects, :write
  15 + remove_column :users_projects, :admin
  16 + end
  17 +
  18 + def down
  19 + end
  20 +end
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 # 11 #
12 # It's strongly recommended to check this file into your version control system. 12 # It's strongly recommended to check this file into your version control system.
13 13
14 -ActiveRecord::Schema.define(:version => 20111127155345) do 14 +ActiveRecord::Schema.define(:version => 20111206222316) do
15 15
16 create_table "features", :force => true do |t| 16 create_table "features", :force => true do |t|
17 t.string "name" 17 t.string "name"
@@ -137,11 +137,10 @@ ActiveRecord::Schema.define(:version =&gt; 20111127155345) do @@ -137,11 +137,10 @@ ActiveRecord::Schema.define(:version =&gt; 20111127155345) do
137 create_table "users_projects", :force => true do |t| 137 create_table "users_projects", :force => true do |t|
138 t.integer "user_id", :null => false 138 t.integer "user_id", :null => false
139 t.integer "project_id", :null => false 139 t.integer "project_id", :null => false
140 - t.boolean "read", :default => false  
141 - t.boolean "write", :default => false  
142 - t.boolean "admin", :default => false  
143 t.datetime "created_at" 140 t.datetime "created_at"
144 t.datetime "updated_at" 141 t.datetime "updated_at"
  142 + t.integer "repo_access", :default => 0, :null => false
  143 + t.integer "project_access", :default => 0, :null => false
145 end 144 end
146 145
147 end 146 end
lib/gitlabhq/gitolite.rb
@@ -61,7 +61,7 @@ module Gitlabhq @@ -61,7 +61,7 @@ module Gitlabhq
61 end 61 end
62 62
63 # update or create 63 # update or create
64 - def update_project(repo_name, name_writers) 64 + def update_project(repo_name, project)
65 ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite')) 65 ga_repo = ::Gitolite::GitoliteAdmin.new(File.join(@local_dir,'gitolite'))
66 conf = ga_repo.config 66 conf = ga_repo.config
67 67
@@ -71,8 +71,13 @@ module Gitlabhq @@ -71,8 +71,13 @@ module Gitlabhq
71 ::Gitolite::Config::Repo.new(repo_name) 71 ::Gitolite::Config::Repo.new(repo_name)
72 end 72 end
73 73
  74 + name_readers = project.repository_readers
  75 + name_writers = project.repository_writers
  76 +
  77 + repo.clean_permissions
  78 + repo.add_permission("R", "", name_readers) unless name_readers.blank?
74 repo.add_permission("RW+", "", name_writers) unless name_writers.blank? 79 repo.add_permission("RW+", "", name_writers) unless name_writers.blank?
75 - conf.add_repo(repo) 80 + conf.add_repo(repo, true)
76 81
77 ga_repo.save 82 ga_repo.save
78 end 83 end
public/githost_error.html 0 → 100644
@@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <title>We're sorry, but we cant get access to your gitosis</title>
  5 + <style type="text/css">
  6 + body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; }
  7 + div.dialog {
  8 + width: 600px;
  9 + padding: 0 4em;
  10 + margin: 4em auto 0 auto;
  11 + }
  12 + h1 { font-size: 48px; color: #444; line-height: 1.5em; }
  13 + h2 { font-size: 24px; color: #666; line-height: 1.5em; }
  14 + </style>
  15 +</head>
  16 +
  17 +<body>
  18 + <!-- This file lives in public/500.html -->
  19 + <div class="dialog">
  20 + <h1>Gitolite Error</h1>
  21 + <h2>We're sorry, but we cant get access to your gitolite system.</h2>
  22 + <h3> 1. Check 'config/gitlab.yml' for correct settings.</h3>
  23 + <h3> 2. Be sure web server user has access to gitolite.</h3>
  24 + </div>
  25 +</body>
  26 +</html>
public/gitosis_error.html
@@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
1 -<!DOCTYPE html>  
2 -<html>  
3 -<head>  
4 - <title>We're sorry, but we cant get access to your gitosis</title>  
5 - <style type="text/css">  
6 - body { background-color: #EAEAEA; color: #666; text-align: center; font-family: arial, sans-serif; }  
7 - div.dialog {  
8 - width: 600px;  
9 - padding: 0 4em;  
10 - margin: 4em auto 0 auto;  
11 - }  
12 - h1 { font-size: 48px; color: #444; line-height: 1.5em; }  
13 - h2 { font-size: 24px; color: #666; line-height: 1.5em; }  
14 - </style>  
15 -</head>  
16 -  
17 -<body>  
18 - <!-- This file lives in public/500.html -->  
19 - <div class="dialog">  
20 - <h1>Gitosis Error</h1>  
21 - <h2>We're sorry, but we cant get access to your gitosis.</h2>  
22 - <h3> 1. Check 'config/gitosis.yml' for correct settings.</h3>  
23 - <h3> 2. Be sure web server user has access to gitosis.</h3>  
24 - </div>  
25 -</body>  
26 -</html>