OSDN Git Service

Refactor abilities. Added ProjectUpdate context. Fixed few bugs with namespaces
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Thu, 29 Nov 2012 04:29:11 +0000 (07:29 +0300)
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>
Thu, 29 Nov 2012 10:39:03 +0000 (12:39 +0200)
18 files changed:
app/contexts/project_update_context.rb [new file with mode: 0644]
app/controllers/admin/projects_controller.rb
app/controllers/application_controller.rb
app/controllers/dashboard_controller.rb
app/controllers/groups_controller.rb
app/controllers/project_resource_controller.rb
app/controllers/projects_controller.rb
app/models/ability.rb
app/models/group.rb
app/models/namespace.rb
app/models/project.rb
app/models/user.rb
app/views/admin/projects/_form.html.haml
app/views/errors/access_denied.html.haml
app/views/groups/show.html.haml
db/fixtures/development/010_groups.rb [new file with mode: 0644]
spec/models/group_spec.rb
spec/models/namespace_spec.rb

diff --git a/app/contexts/project_update_context.rb b/app/contexts/project_update_context.rb
new file mode 100644 (file)
index 0000000..e28d43d
--- /dev/null
@@ -0,0 +1,21 @@
+class ProjectUpdateContext < BaseContext
+  def execute(role = :default)
+    namespace_id = params[:project].delete(:namespace_id)
+
+    if namespace_id.present?
+      if namespace_id == Namespace.global_id
+        if project.namespace.present?
+          # Transfer to global namespace from anyone
+          project.transfer(nil)
+        end
+      elsif namespace_id.to_i != project.namespace_id
+        # Transfer to someone namespace
+        namespace = Namespace.find(namespace_id)
+        project.transfer(namespace)
+      end
+    end
+
+    project.update_attributes(params[:project], as: role)
+  end
+end
+
index c3a419a..e61f94f 100644 (file)
@@ -24,13 +24,9 @@ class Admin::ProjectsController < AdminController
   end
 
   def update
-    owner_id = params[:project].delete(:owner_id)
+    status = ProjectUpdateContext.new(project, current_user, params).execute(:admin)
 
-    if owner_id
-      @project.owner = User.find(owner_id)
-    end
-
-    if @project.update_attributes(params[:project], as: :admin)
+    if status
       redirect_to [:admin, @project], notice: 'Project was successfully updated.'
     else
       render action: "edit"
index 2be9a54..66f2e87 100644 (file)
@@ -2,6 +2,7 @@ class ApplicationController < ActionController::Base
   before_filter :authenticate_user!
   before_filter :reject_blocked!
   before_filter :set_current_user_for_observers
+  before_filter :add_abilities
   before_filter :dev_tools if Rails.env == 'development'
 
   protect_from_forgery
@@ -65,11 +66,17 @@ class ApplicationController < ActionController::Base
   def project
     id = params[:project_id] || params[:id]
 
-    @project ||= current_user.projects.find_with_namespace(id)
-    @project || render_404
+    @project = Project.find_with_namespace(id)
+
+    if @project and can?(current_user, :read_project, @project)
+      @project
+    else
+      @project = nil
+      render_404
+    end
   end
 
-  def add_project_abilities
+  def add_abilities
     abilities << Ability
   end
 
index 4f874a9..e01b586 100644 (file)
@@ -5,7 +5,7 @@ class DashboardController < ApplicationController
   before_filter :event_filter, only: :index
 
   def index
-    @groups = Group.where(id: current_user.projects.pluck(:namespace_id))
+    @groups = current_user.accessed_groups
     @projects = @projects.page(params[:page]).per(30)
     @events = Event.in_projects(current_user.project_ids)
     @events = @event_filter.apply_filter(@events)
index c969f41..6fd5de8 100644 (file)
@@ -4,7 +4,6 @@ class GroupsController < ApplicationController
 
   before_filter :group
   before_filter :projects
-  before_filter :add_project_abilities
 
   def show
     @events = Event.in_projects(project_ids).limit(20).offset(params[:offset] || 0)
@@ -45,7 +44,7 @@ class GroupsController < ApplicationController
   end
 
   def people
-    @users = group.users.all
+    @users = group.users
   end
 
   protected
@@ -55,7 +54,11 @@ class GroupsController < ApplicationController
   end
 
   def projects
-    @projects ||= current_user.projects_sorted_by_activity.where(namespace_id: @group.id)
+    @projects ||= if can?(current_user, :manage_group, @group)
+                    @group.projects.all
+                  else
+                    current_user.projects_sorted_by_activity.where(namespace_id: @group.id)
+                  end
   end
 
   def project_ids
index d297bba..81bc3a9 100644 (file)
@@ -1,5 +1,3 @@
 class ProjectResourceController < ApplicationController
   before_filter :project
-  # Authorize
-  before_filter :add_project_abilities
 end
index ed34069..a6e7f1f 100644 (file)
@@ -34,20 +34,10 @@ class ProjectsController < ProjectResourceController
   end
 
   def update
-    if params[:project].has_key?(:namespace_id)
-      namespace_id = params[:project].delete(:namespace_id)
-      if namespace_id == Namespace.global_id and project.namespace.present?
-        # Transfer to global namespace from anyone
-        project.transfer(nil)
-      elsif namespace_id.present? and namespace_id.to_i != project.namespace_id
-        # Transfer to someone namespace
-        namespace = Namespace.find(namespace_id)
-        project.transfer(namespace)
-      end
-    end
+    status = ProjectUpdateContext.new(project, current_user, params).execute
 
     respond_to do |format|
-      if project.update_attributes(params[:project])
+      if status
         flash[:notice] = 'Project was successfully updated.'
         format.html { redirect_to edit_project_path(project), notice: 'Project was successfully updated.' }
         format.js
index e55e770..96d3ac6 100644 (file)
@@ -15,7 +15,37 @@ class Ability
     def project_abilities(user, project)
       rules = []
 
-      rules << [
+      # Rules based on role in project
+      if project.master_access_for?(user)
+        # TODO: replace with master rules.
+        # Only allow project administration for owners
+        rules << project_admin_rules
+
+      elsif project.dev_access_for?(user)
+        rules << project_dev_rules
+
+      elsif project.report_access_for?(user)
+        rules << project_report_rules
+
+      elsif project.guest_access_for?(user)
+        rules << project_guest_rules
+      end
+
+      # If user own project namespace (Ex. group owner or account owner)
+      if project.namespace && project.namespace.owner == user
+        rules << project_admin_rules
+      end
+
+      # If user was set as direct project owner
+      if project.owner == user
+        rules << project_admin_rules
+      end
+
+      rules.flatten
+    end
+
+    def project_guest_rules
+      [
         :read_project,
         :read_wiki,
         :read_issue,
@@ -27,28 +57,30 @@ class Ability
         :write_project,
         :write_issue,
         :write_note
-      ] if project.guest_access_for?(user)
+      ]
+    end
 
-      rules << [
+    def project_report_rules
+      project_guest_rules + [
         :download_code,
         :write_merge_request,
         :write_snippet
-      ] if project.report_access_for?(user)
+      ]
+    end
 
-      rules << [
+    def project_dev_rules
+      project_report_rules + [
         :write_wiki,
         :push_code
-      ] if project.dev_access_for?(user)
-
-      rules << [
-        :push_code_to_protected_branches
-      ] if project.master_access_for?(user)
+      ]
+    end
 
-      rules << [
+    def project_master_rules
+      project_dev_rules + [
+        :push_code_to_protected_branches,
         :modify_issue,
         :modify_snippet,
         :modify_merge_request,
-        :admin_project,
         :admin_issue,
         :admin_milestone,
         :admin_snippet,
@@ -57,9 +89,13 @@ class Ability
         :admin_note,
         :accept_mr,
         :admin_wiki
-      ] if project.master_access_for?(user) || project.owner == user
+      ]
+    end
 
-      rules.flatten
+    def project_admin_rules
+      project_master_rules + [
+        :admin_project
+      ]
     end
 
     def group_abilities user, group
index 66267c5..b668f55 100644 (file)
@@ -13,7 +13,9 @@
 
 class Group < Namespace
   def users
-    User.joins(:users_projects).where(users_projects: {project_id: project_ids}).uniq
+    users = User.joins(:users_projects).where(users_projects: {project_id: project_ids})
+    users = users << owner
+    users.uniq
   end
 
   def human_name
index 5762bfc..e1c24de 100644 (file)
@@ -53,12 +53,14 @@ class Namespace < ActiveRecord::Base
   end
 
   def move_dir
-    old_path = File.join(Gitlab.config.git_base_path, path_was)
-    new_path = File.join(Gitlab.config.git_base_path, path)
-    if File.exists?(new_path)
-      raise "Already exists"
+    if path_changed?
+      old_path = File.join(Gitlab.config.git_base_path, path_was)
+      new_path = File.join(Gitlab.config.git_base_path, path)
+      if File.exists?(new_path)
+        raise "Already exists"
+      end
+      system("mv #{old_path} #{new_path}")
     end
-    system("mv #{old_path} #{new_path}")
   end
 
   def rm_dir
index 0c74c0b..8df662d 100644 (file)
@@ -29,7 +29,7 @@ class Project < ActiveRecord::Base
   attr_accessible :name, :path, :description, :default_branch, :issues_enabled,
                   :wall_enabled, :merge_requests_enabled, :wiki_enabled, as: [:default, :admin]
 
-  attr_accessible :namespace_id, as: :admin
+  attr_accessible :namespace_id, :owner_id, as: :admin
 
   attr_accessor :error_code
 
index 4316340..d43e3cb 100644 (file)
@@ -123,4 +123,11 @@ class User < ActiveRecord::Base
       self.password = self.password_confirmation = Devise.friendly_token.first(8)
     end
   end
+
+  def accessed_groups
+    @accessed_groups ||= begin
+                           groups = Group.where(id: self.projects.pluck(:namespace_id)).all
+                           groups + self.groups
+                         end
+  end
 end
index eb12c61..110ff04 100644 (file)
@@ -22,7 +22,7 @@
     - unless project.new_record?
       .clearfix
         = f.label :namespace_id
-        .input= f.select :namespace_id, namespaces_options, {}, {class: 'chosen'}
+        .input= f.select :namespace_id, namespaces_options(@project.namespace_id), {}, {class: 'chosen'}
 
       .clearfix
         = f.label :owner_id
index a6e4f0b..f2d082c 100644 (file)
@@ -1,4 +1,4 @@
-%h1 403
+%h1.http_status_code 403
 %h3.page_title Access Denied
 %hr
 %p You are not allowed to access this page.
index 72d7ad9..0c2eb15 100644 (file)
@@ -10,7 +10,7 @@
     - if @events.any?
       .content_list= render @events
     - else
-      %h4.nothing_here_message Projects activity will be displayed here
+      %p.nothing_here_message Projects activity will be displayed here
     .loading.hide
   .side
     = render "projects", projects: @projects
diff --git a/db/fixtures/development/010_groups.rb b/db/fixtures/development/010_groups.rb
new file mode 100644 (file)
index 0000000..09371b0
--- /dev/null
@@ -0,0 +1,11 @@
+Group.seed(:id, [
+  { id: 100, name: "Gitlab", path: 'gitlab', owner_id: 1},
+  { id: 101, name: "Rails", path: 'rails', owner_id: 1 },
+  { id: 102, name: "KDE", path: 'kde', owner_id: 1 }
+])
+
+Project.seed(:id, [
+  { id: 10, name: "kdebase", path: "kdebase", owner_id: 1, namespace_id: 102 },
+  { id: 11, name: "kdelibs", path: "kdelibs", owner_id: 1, namespace_id: 102 },
+  { id: 12, name: "amarok",  path: "amarok",  owner_id: 1, namespace_id: 102 }
+])
index 8847262..108bc30 100644 (file)
@@ -24,7 +24,7 @@ describe Group do
   it { should validate_presence_of :owner }
 
   describe :users do
-    it { group.users.should == [] }
+    it { group.users.should == [group.owner] }
   end
 
   describe :human_name do
index 1f1d661..d0de4a7 100644 (file)
@@ -55,9 +55,10 @@ describe Namespace do
   describe :move_dir do
     before do
       @namespace = create :namespace
+      @namespace.stub(path_changed?: true)
     end
 
-    it "should raise error when called directly" do
+    it "should raise error when dirtory exists" do
       expect { @namespace.move_dir }.to raise_error("Already exists")
     end