Commit eb1004f7890d25a86beb0ca0a7eca802d9fce665
1 parent
a1ffc673
Exists in
master
and in
4 other branches
Refactor abilities. Added ProjectUpdate context. Fixed few bugs with namespaces
Showing
18 changed files
with
127 additions
and
53 deletions
Show diff stats
| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | +class ProjectUpdateContext < BaseContext | |
| 2 | + def execute(role = :default) | |
| 3 | + namespace_id = params[:project].delete(:namespace_id) | |
| 4 | + | |
| 5 | + if namespace_id.present? | |
| 6 | + if namespace_id == Namespace.global_id | |
| 7 | + if project.namespace.present? | |
| 8 | + # Transfer to global namespace from anyone | |
| 9 | + project.transfer(nil) | |
| 10 | + end | |
| 11 | + elsif namespace_id.to_i != project.namespace_id | |
| 12 | + # Transfer to someone namespace | |
| 13 | + namespace = Namespace.find(namespace_id) | |
| 14 | + project.transfer(namespace) | |
| 15 | + end | |
| 16 | + end | |
| 17 | + | |
| 18 | + project.update_attributes(params[:project], as: role) | |
| 19 | + end | |
| 20 | +end | |
| 21 | + | ... | ... |
app/controllers/admin/projects_controller.rb
| ... | ... | @@ -24,13 +24,9 @@ class Admin::ProjectsController < AdminController |
| 24 | 24 | end |
| 25 | 25 | |
| 26 | 26 | def update |
| 27 | - owner_id = params[:project].delete(:owner_id) | |
| 27 | + status = ProjectUpdateContext.new(project, current_user, params).execute(:admin) | |
| 28 | 28 | |
| 29 | - if owner_id | |
| 30 | - @project.owner = User.find(owner_id) | |
| 31 | - end | |
| 32 | - | |
| 33 | - if @project.update_attributes(params[:project], as: :admin) | |
| 29 | + if status | |
| 34 | 30 | redirect_to [:admin, @project], notice: 'Project was successfully updated.' |
| 35 | 31 | else |
| 36 | 32 | render action: "edit" | ... | ... |
app/controllers/application_controller.rb
| ... | ... | @@ -2,6 +2,7 @@ class ApplicationController < ActionController::Base |
| 2 | 2 | before_filter :authenticate_user! |
| 3 | 3 | before_filter :reject_blocked! |
| 4 | 4 | before_filter :set_current_user_for_observers |
| 5 | + before_filter :add_abilities | |
| 5 | 6 | before_filter :dev_tools if Rails.env == 'development' |
| 6 | 7 | |
| 7 | 8 | protect_from_forgery |
| ... | ... | @@ -65,11 +66,17 @@ class ApplicationController < ActionController::Base |
| 65 | 66 | def project |
| 66 | 67 | id = params[:project_id] || params[:id] |
| 67 | 68 | |
| 68 | - @project ||= current_user.projects.find_with_namespace(id) | |
| 69 | - @project || render_404 | |
| 69 | + @project = Project.find_with_namespace(id) | |
| 70 | + | |
| 71 | + if @project and can?(current_user, :read_project, @project) | |
| 72 | + @project | |
| 73 | + else | |
| 74 | + @project = nil | |
| 75 | + render_404 | |
| 76 | + end | |
| 70 | 77 | end |
| 71 | 78 | |
| 72 | - def add_project_abilities | |
| 79 | + def add_abilities | |
| 73 | 80 | abilities << Ability |
| 74 | 81 | end |
| 75 | 82 | ... | ... |
app/controllers/dashboard_controller.rb
| ... | ... | @@ -5,7 +5,7 @@ class DashboardController < ApplicationController |
| 5 | 5 | before_filter :event_filter, only: :index |
| 6 | 6 | |
| 7 | 7 | def index |
| 8 | - @groups = Group.where(id: current_user.projects.pluck(:namespace_id)) | |
| 8 | + @groups = current_user.accessed_groups | |
| 9 | 9 | @projects = @projects.page(params[:page]).per(30) |
| 10 | 10 | @events = Event.in_projects(current_user.project_ids) |
| 11 | 11 | @events = @event_filter.apply_filter(@events) | ... | ... |
app/controllers/groups_controller.rb
| ... | ... | @@ -4,7 +4,6 @@ class GroupsController < ApplicationController |
| 4 | 4 | |
| 5 | 5 | before_filter :group |
| 6 | 6 | before_filter :projects |
| 7 | - before_filter :add_project_abilities | |
| 8 | 7 | |
| 9 | 8 | def show |
| 10 | 9 | @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0) |
| ... | ... | @@ -45,7 +44,7 @@ class GroupsController < ApplicationController |
| 45 | 44 | end |
| 46 | 45 | |
| 47 | 46 | def people |
| 48 | - @users = group.users.all | |
| 47 | + @users = group.users | |
| 49 | 48 | end |
| 50 | 49 | |
| 51 | 50 | protected |
| ... | ... | @@ -55,7 +54,11 @@ class GroupsController < ApplicationController |
| 55 | 54 | end |
| 56 | 55 | |
| 57 | 56 | def projects |
| 58 | - @projects ||= current_user.projects_sorted_by_activity.where(namespace_id: @group.id) | |
| 57 | + @projects ||= if can?(current_user, :manage_group, @group) | |
| 58 | + @group.projects.all | |
| 59 | + else | |
| 60 | + current_user.projects_sorted_by_activity.where(namespace_id: @group.id) | |
| 61 | + end | |
| 59 | 62 | end |
| 60 | 63 | |
| 61 | 64 | def project_ids | ... | ... |
app/controllers/project_resource_controller.rb
app/controllers/projects_controller.rb
| ... | ... | @@ -34,20 +34,10 @@ class ProjectsController < ProjectResourceController |
| 34 | 34 | end |
| 35 | 35 | |
| 36 | 36 | def update |
| 37 | - if params[:project].has_key?(:namespace_id) | |
| 38 | - namespace_id = params[:project].delete(:namespace_id) | |
| 39 | - if namespace_id == Namespace.global_id and project.namespace.present? | |
| 40 | - # Transfer to global namespace from anyone | |
| 41 | - project.transfer(nil) | |
| 42 | - elsif namespace_id.present? and namespace_id.to_i != project.namespace_id | |
| 43 | - # Transfer to someone namespace | |
| 44 | - namespace = Namespace.find(namespace_id) | |
| 45 | - project.transfer(namespace) | |
| 46 | - end | |
| 47 | - end | |
| 37 | + status = ProjectUpdateContext.new(project, current_user, params).execute | |
| 48 | 38 | |
| 49 | 39 | respond_to do |format| |
| 50 | - if project.update_attributes(params[:project]) | |
| 40 | + if status | |
| 51 | 41 | flash[:notice] = 'Project was successfully updated.' |
| 52 | 42 | format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' } |
| 53 | 43 | format.js | ... | ... |
app/models/ability.rb
| ... | ... | @@ -15,7 +15,37 @@ class Ability |
| 15 | 15 | def project_abilities(user, project) |
| 16 | 16 | rules = [] |
| 17 | 17 | |
| 18 | - rules << [ | |
| 18 | + # Rules based on role in project | |
| 19 | + if project.master_access_for?(user) | |
| 20 | + # TODO: replace with master rules. | |
| 21 | + # Only allow project administration for owners | |
| 22 | + rules << project_admin_rules | |
| 23 | + | |
| 24 | + elsif project.dev_access_for?(user) | |
| 25 | + rules << project_dev_rules | |
| 26 | + | |
| 27 | + elsif project.report_access_for?(user) | |
| 28 | + rules << project_report_rules | |
| 29 | + | |
| 30 | + elsif project.guest_access_for?(user) | |
| 31 | + rules << project_guest_rules | |
| 32 | + end | |
| 33 | + | |
| 34 | + # If user own project namespace (Ex. group owner or account owner) | |
| 35 | + if project.namespace && project.namespace.owner == user | |
| 36 | + rules << project_admin_rules | |
| 37 | + end | |
| 38 | + | |
| 39 | + # If user was set as direct project owner | |
| 40 | + if project.owner == user | |
| 41 | + rules << project_admin_rules | |
| 42 | + end | |
| 43 | + | |
| 44 | + rules.flatten | |
| 45 | + end | |
| 46 | + | |
| 47 | + def project_guest_rules | |
| 48 | + [ | |
| 19 | 49 | :read_project, |
| 20 | 50 | :read_wiki, |
| 21 | 51 | :read_issue, |
| ... | ... | @@ -27,28 +57,30 @@ class Ability |
| 27 | 57 | :write_project, |
| 28 | 58 | :write_issue, |
| 29 | 59 | :write_note |
| 30 | - ] if project.guest_access_for?(user) | |
| 60 | + ] | |
| 61 | + end | |
| 31 | 62 | |
| 32 | - rules << [ | |
| 63 | + def project_report_rules | |
| 64 | + project_guest_rules + [ | |
| 33 | 65 | :download_code, |
| 34 | 66 | :write_merge_request, |
| 35 | 67 | :write_snippet |
| 36 | - ] if project.report_access_for?(user) | |
| 68 | + ] | |
| 69 | + end | |
| 37 | 70 | |
| 38 | - rules << [ | |
| 71 | + def project_dev_rules | |
| 72 | + project_report_rules + [ | |
| 39 | 73 | :write_wiki, |
| 40 | 74 | :push_code |
| 41 | - ] if project.dev_access_for?(user) | |
| 42 | - | |
| 43 | - rules << [ | |
| 44 | - :push_code_to_protected_branches | |
| 45 | - ] if project.master_access_for?(user) | |
| 75 | + ] | |
| 76 | + end | |
| 46 | 77 | |
| 47 | - rules << [ | |
| 78 | + def project_master_rules | |
| 79 | + project_dev_rules + [ | |
| 80 | + :push_code_to_protected_branches, | |
| 48 | 81 | :modify_issue, |
| 49 | 82 | :modify_snippet, |
| 50 | 83 | :modify_merge_request, |
| 51 | - :admin_project, | |
| 52 | 84 | :admin_issue, |
| 53 | 85 | :admin_milestone, |
| 54 | 86 | :admin_snippet, |
| ... | ... | @@ -57,9 +89,13 @@ class Ability |
| 57 | 89 | :admin_note, |
| 58 | 90 | :accept_mr, |
| 59 | 91 | :admin_wiki |
| 60 | - ] if project.master_access_for?(user) || project.owner == user | |
| 92 | + ] | |
| 93 | + end | |
| 61 | 94 | |
| 62 | - rules.flatten | |
| 95 | + def project_admin_rules | |
| 96 | + project_master_rules + [ | |
| 97 | + :admin_project | |
| 98 | + ] | |
| 63 | 99 | end |
| 64 | 100 | |
| 65 | 101 | def group_abilities user, group | ... | ... |
app/models/group.rb
| ... | ... | @@ -13,7 +13,9 @@ |
| 13 | 13 | |
| 14 | 14 | class Group < Namespace |
| 15 | 15 | def users |
| 16 | - User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq | |
| 16 | + users = User.joins(:users_projects).where(users_projects: {project_id: project_ids}) | |
| 17 | + users = users << owner | |
| 18 | + users.uniq | |
| 17 | 19 | end |
| 18 | 20 | |
| 19 | 21 | def human_name | ... | ... |
app/models/namespace.rb
| ... | ... | @@ -53,12 +53,14 @@ class Namespace < ActiveRecord::Base |
| 53 | 53 | end |
| 54 | 54 | |
| 55 | 55 | def move_dir |
| 56 | - old_path = File.join(Gitlab.config.git_base_path, path_was) | |
| 57 | - new_path = File.join(Gitlab.config.git_base_path, path) | |
| 58 | - if File.exists?(new_path) | |
| 59 | - raise "Already exists" | |
| 56 | + if path_changed? | |
| 57 | + old_path = File.join(Gitlab.config.git_base_path, path_was) | |
| 58 | + new_path = File.join(Gitlab.config.git_base_path, path) | |
| 59 | + if File.exists?(new_path) | |
| 60 | + raise "Already exists" | |
| 61 | + end | |
| 62 | + system("mv #{old_path} #{new_path}") | |
| 60 | 63 | end |
| 61 | - system("mv #{old_path} #{new_path}") | |
| 62 | 64 | end |
| 63 | 65 | |
| 64 | 66 | def rm_dir | ... | ... |
app/models/project.rb
| ... | ... | @@ -29,7 +29,7 @@ class Project < ActiveRecord::Base |
| 29 | 29 | attr_accessible :name, :path, :description, :default_branch, :issues_enabled, |
| 30 | 30 | :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin] |
| 31 | 31 | |
| 32 | - attr_accessible :namespace_id, as: :admin | |
| 32 | + attr_accessible :namespace_id, :owner_id, as: :admin | |
| 33 | 33 | |
| 34 | 34 | attr_accessor :error_code |
| 35 | 35 | ... | ... |
app/models/user.rb
| ... | ... | @@ -123,4 +123,11 @@ class User < ActiveRecord::Base |
| 123 | 123 | self.password = self.password_confirmation = Devise.friendly_token.first(8) |
| 124 | 124 | end |
| 125 | 125 | end |
| 126 | + | |
| 127 | + def accessed_groups | |
| 128 | + @accessed_groups ||= begin | |
| 129 | + groups = Group.where(id: self.projects.pluck(:namespace_id)).all | |
| 130 | + groups + self.groups | |
| 131 | + end | |
| 132 | + end | |
| 126 | 133 | end | ... | ... |
app/views/admin/projects/_form.html.haml
| ... | ... | @@ -22,7 +22,7 @@ |
| 22 | 22 | - unless project.new_record? |
| 23 | 23 | .clearfix |
| 24 | 24 | = f.label :namespace_id |
| 25 | - .input= f.select :namespace_id, namespaces_options, {}, {class: 'chosen'} | |
| 25 | + .input= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'} | |
| 26 | 26 | |
| 27 | 27 | .clearfix |
| 28 | 28 | = f.label :owner_id | ... | ... |
app/views/errors/access_denied.html.haml
app/views/groups/show.html.haml
| ... | ... | @@ -10,7 +10,7 @@ |
| 10 | 10 | - if @events.any? |
| 11 | 11 | .content_list= render @events |
| 12 | 12 | - else |
| 13 | - %h4.nothing_here_message Projects activity will be displayed here | |
| 13 | + %p.nothing_here_message Projects activity will be displayed here | |
| 14 | 14 | .loading.hide |
| 15 | 15 | .side |
| 16 | 16 | = render "projects", projects: @projects | ... | ... |
| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | +Group.seed(:id, [ | |
| 2 | + { id: 100, name: "Gitlab", path: 'gitlab', owner_id: 1}, | |
| 3 | + { id: 101, name: "Rails", path: 'rails', owner_id: 1 }, | |
| 4 | + { id: 102, name: "KDE", path: 'kde', owner_id: 1 } | |
| 5 | +]) | |
| 6 | + | |
| 7 | +Project.seed(:id, [ | |
| 8 | + { id: 10, name: "kdebase", path: "kdebase", owner_id: 1, namespace_id: 102 }, | |
| 9 | + { id: 11, name: "kdelibs", path: "kdelibs", owner_id: 1, namespace_id: 102 }, | |
| 10 | + { id: 12, name: "amarok", path: "amarok", owner_id: 1, namespace_id: 102 } | |
| 11 | +]) | ... | ... |
spec/models/group_spec.rb
spec/models/namespace_spec.rb
| ... | ... | @@ -55,9 +55,10 @@ describe Namespace do |
| 55 | 55 | describe :move_dir do |
| 56 | 56 | before do |
| 57 | 57 | @namespace = create :namespace |
| 58 | + @namespace.stub(path_changed?: true) | |
| 58 | 59 | end |
| 59 | 60 | |
| 60 | - it "should raise error when called directly" do | |
| 61 | + it "should raise error when dirtory exists" do | |
| 61 | 62 | expect { @namespace.move_dir }.to raise_error("Already exists") |
| 62 | 63 | end |
| 63 | 64 | ... | ... |