Skip to content
Snippets Groups Projects
ability.rb 7.61 KiB
Newer Older
  • Learn to ignore specific revisions
  • gitlabhq's avatar
    gitlabhq committed
    class Ability
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
      class << self
    
        def allowed(user, subject)
    
          return not_auth_abilities(user, subject) if user.nil?
    
          return [] unless user.kind_of?(User)
    
          return [] if user.blocked?
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
          case subject.class.name
    
          when "Project" then project_abilities(user, subject)
          when "Issue" then issue_abilities(user, subject)
          when "Note" then note_abilities(user, subject)
    
          when "ProjectSnippet" then project_snippet_abilities(user, subject)
    
          when "PersonalSnippet" then personal_snippet_abilities(user, subject)
    
          when "MergeRequest" then merge_request_abilities(user, subject)
    
          when "Group" then group_abilities(user, subject)
          when "Namespace" then namespace_abilities(user, subject)
    
          when "GroupMember" then group_member_abilities(user, subject)
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
          else []
    
          end.concat(global_abilities(user))
        end
    
    
        # List of possible abilities
        # for non-authenticated user
        def not_auth_abilities(user, subject)
          project = if subject.kind_of?(Project)
                      subject
                    elsif subject.respond_to?(:project)
                      subject.project
                    else
                      nil
                    end
    
    
          if project && project.public?
    
            [
              :read_project,
              :read_wiki,
              :read_issue,
              :read_milestone,
              :read_project_snippet,
    
              :read_project_member,
    
              :read_merge_request,
              :read_note,
              :download_code
            ]
    
            group = if subject.kind_of?(Group)
                      subject
                    elsif subject.respond_to?(:group)
                      subject.group
                    else
                      nil
                    end
    
        def global_abilities(user)
          rules = []
          rules << :create_group if user.can_create_group
          rules
    
    gitlabhq's avatar
    gitlabhq committed
        end
    
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
        def project_abilities(user, project)
          rules = []
    
          key = "/user/#{user.id}/project/#{project.id}"
          RequestStore.store[key] ||= begin
            team = project.team
    
    gitlabhq's avatar
    gitlabhq committed
    
    
            # Rules based on role in project
            if team.master?(user)
    
              rules.push(*project_master_rules)
    
            elsif team.developer?(user)
    
              rules.push(*project_dev_rules)
    
            elsif team.reporter?(user)
    
              rules.push(*project_report_rules)
    
            elsif team.guest?(user)
    
              rules.push(*project_guest_rules)
    
            if project.public? || project.internal?
    
              rules.push(*public_project_rules)
    
            if project.owner == user || user.admin?
    
              rules.push(*project_admin_rules)
    
            if project.group && project.group.has_owner?(user)
    
              rules.push(*project_admin_rules)
    
            if project.archived?
              rules -= project_archived_rules
            end
    
            unless project.issues_enabled
              rules -= named_abilities('issue')
            end
    
            unless project.merge_requests_enabled
              rules -= named_abilities('merge_request')
            end
    
    
            unless project.issues_enabled or project.merge_requests_enabled
              rules -= named_abilities('label')
              rules -= named_abilities('milestone')
            end
    
    
              rules -= named_abilities('project_snippet')
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :read_project,
            :read_wiki,
            :read_issue,
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :read_milestone,
    
    Andrew8xx8's avatar
    Andrew8xx8 committed
            :read_project_snippet,
    
            :read_project_member,
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :read_merge_request,
            :read_note,
            :write_project,
            :write_issue,
    
        def project_report_rules
          project_guest_rules + [
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :download_code,
    
            :fork_project,
    
    Andrew8xx8's avatar
    Andrew8xx8 committed
            :write_project_snippet
    
            :admin_issue,
    
    Dmitriy Zaporozhets's avatar
    Dmitriy Zaporozhets committed
            :admin_label,
    
        def project_archived_rules
          [
            :write_merge_request,
            :push_code,
            :push_code_to_protected_branches,
            :modify_merge_request,
            :admin_merge_request
          ]
        end
    
    
        def project_master_rules
          project_dev_rules + [
            :push_code_to_protected_branches,
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :modify_issue,
    
    Andrew8xx8's avatar
    Andrew8xx8 committed
            :modify_project_snippet,
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :modify_merge_request,
            :admin_milestone,
    
    Andrew8xx8's avatar
    Andrew8xx8 committed
            :admin_project_snippet,
    
            :admin_project_member,
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
            :admin_merge_request,
            :admin_note,
    
    gitlabhq's avatar
    gitlabhq committed
    
    
        def project_admin_rules
          project_master_rules + [
    
            :change_visibility_level,
    
    Andrey Kumanyaev's avatar
    Andrey Kumanyaev committed
        end
    
    gitlabhq's avatar
    gitlabhq committed
    
    
        def group_abilities(user, group)
    
          if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
    
          # Only group masters and group owners can create new projects in group
          if group.has_master?(user) || group.has_owner?(user) || user.admin?
    
            rules.push(*[
    
          # Only group owner and administrators can admin group
    
          if group.has_owner?(user) || user.admin?
    
            rules.push(*[
    
        def namespace_abilities(user, namespace)
    
          # Only namespace owner and administrators can admin it
    
          if namespace.owner == user || user.admin?
    
            rules.push(*[
    
        [:issue, :note, :project_snippet, :personal_snippet, :merge_request].each do |name|
    
    gitlabhq's avatar
    gitlabhq committed
          define_method "#{name}_abilities" do |user, subject|
    
            if subject.author == user || user.is_admin?
              rules = [
    
    gitlabhq's avatar
    gitlabhq committed
                :"read_#{name}",
                :"write_#{name}",
    
                :"modify_#{name}",
    
    gitlabhq's avatar
    gitlabhq committed
                :"admin_#{name}"
              ]
    
              rules.push(:change_visibility_level) if subject.is_a?(Snippet)
              rules
    
            elsif subject.respond_to?(:assignee) && subject.assignee == user
              [
                :"read_#{name}",
                :"write_#{name}",
                :"modify_#{name}",
              ]
    
    gitlabhq's avatar
    gitlabhq committed
            else
    
              if subject.respond_to?(:project) && subject.project
    
                project_abilities(user, subject.project)
              else
                []
              end
    
    gitlabhq's avatar
    gitlabhq committed
            end
          end
        end
    
        def group_member_abilities(user, subject)
    
          rules = []
          target_user = subject.user
          group = subject.group
    
          can_manage = group_abilities(user, group).include?(:admin_group)
    
          if can_manage && (user != target_user)
    
            rules << :modify_group_member
            rules << :destroy_group_member
    
          end
          if !group.last_owner?(user) && (can_manage || (user == target_user))
    
            rules << :destroy_group_member
    
    Ciro Santilli's avatar
    Ciro Santilli committed
    
        def abilities
          @abilities ||= begin
                           abilities = Six.new
                           abilities << self
                           abilities
                         end
        end
    
    
        private
    
        def named_abilities(name)
          [
            :"read_#{name}",
            :"write_#{name}",
            :"modify_#{name}",
            :"admin_#{name}"
          ]
        end
    
    gitlabhq's avatar
    gitlabhq committed
      end
    
    gitlabhq's avatar
    gitlabhq committed
    end