ability.rb 8.0 KB
Newer Older
G
gitlabhq 已提交
1
class Ability
A
Andrey Kumanyaev 已提交
2
  class << self
3
    def allowed(user, subject)
4
      return not_auth_abilities(user, subject) if user.nil?
5
      return [] unless user.kind_of?(User)
6
      return [] if user.blocked?
7

A
Andrey Kumanyaev 已提交
8
      case subject.class.name
9 10 11
      when "Project" then project_abilities(user, subject)
      when "Issue" then issue_abilities(user, subject)
      when "Note" then note_abilities(user, subject)
12
      when "ProjectSnippet" then project_snippet_abilities(user, subject)
13
      when "PersonalSnippet" then personal_snippet_abilities(user, subject)
14
      when "MergeRequest" then merge_request_abilities(user, subject)
15 16
      when "Group" then group_abilities(user, subject)
      when "Namespace" then namespace_abilities(user, subject)
17
      when "GroupMember" then group_member_abilities(user, subject)
A
Andrey Kumanyaev 已提交
18
      else []
19 20 21
      end.concat(global_abilities(user))
    end

22 23 24 25 26 27 28 29 30 31 32
    # 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

33
      if project && project.public?
34
        rules = [
35 36 37
          :read_project,
          :read_wiki,
          :read_issue,
38
          :read_label,
39 40
          :read_milestone,
          :read_project_snippet,
41
          :read_project_member,
42 43 44 45
          :read_merge_request,
          :read_note,
          :download_code
        ]
46 47

        rules - project_disabled_features_rules(project)
48
      else
49 50 51 52 53 54 55
        group = if subject.kind_of?(Group)
                  subject
                elsif subject.respond_to?(:group)
                  subject.group
                else
                  nil
                end
56

57
        if group && group.public_profile?
58 59 60 61
          [:read_group]
        else
          []
        end
62 63 64
      end
    end

65 66 67 68
    def global_abilities(user)
      rules = []
      rules << :create_group if user.can_create_group
      rules
G
gitlabhq 已提交
69 70
    end

A
Andrey Kumanyaev 已提交
71 72
    def project_abilities(user, project)
      rules = []
S
skv-headless 已提交
73
      key = "/user/#{user.id}/project/#{project.id}"
74

S
skv-headless 已提交
75 76
      RequestStore.store[key] ||= begin
        team = project.team
G
gitlabhq 已提交
77

S
skv-headless 已提交
78 79
        # Rules based on role in project
        if team.master?(user)
80
          rules.push(*project_master_rules)
D
Dmitriy Zaporozhets 已提交
81

S
skv-headless 已提交
82
        elsif team.developer?(user)
83
          rules.push(*project_dev_rules)
84

S
skv-headless 已提交
85
        elsif team.reporter?(user)
86
          rules.push(*project_report_rules)
87

S
skv-headless 已提交
88
        elsif team.guest?(user)
89
          rules.push(*project_guest_rules)
S
skv-headless 已提交
90
        end
91

S
skv-headless 已提交
92
        if project.public? || project.internal?
93
          rules.push(*public_project_rules)
S
skv-headless 已提交
94
        end
95

S
skv-headless 已提交
96
        if project.owner == user || user.admin?
97
          rules.push(*project_admin_rules)
S
skv-headless 已提交
98
        end
99

S
skv-headless 已提交
100
        if project.group && project.group.has_owner?(user)
101
          rules.push(*project_admin_rules)
S
skv-headless 已提交
102
        end
103

S
skv-headless 已提交
104 105 106
        if project.archived?
          rules -= project_archived_rules
        end
107

108
        rules - project_disabled_features_rules(project)
109
      end
110 111
    end

112
    def public_project_rules
113
      project_guest_rules + [
114
        :download_code,
115
        :fork_project
116 117 118
      ]
    end

119 120
    def project_guest_rules
      [
A
Andrey Kumanyaev 已提交
121 122 123
        :read_project,
        :read_wiki,
        :read_issue,
124
        :read_label,
A
Andrey Kumanyaev 已提交
125
        :read_milestone,
A
Andrew8xx8 已提交
126
        :read_project_snippet,
127
        :read_project_member,
A
Andrey Kumanyaev 已提交
128 129
        :read_merge_request,
        :read_note,
130 131 132
        :create_project,
        :create_issue,
        :create_note
133 134
      ]
    end
D
Dmitriy Zaporozhets 已提交
135

136 137
    def project_report_rules
      project_guest_rules + [
K
Kamil Trzcinski 已提交
138 139
        :create_commit_status,
        :read_commit_statuses,
A
Andrey Kumanyaev 已提交
140
        :download_code,
141
        :fork_project,
142 143 144
        :create_project_snippet,
        :update_issue,
        :admin_issue,
145
        :admin_label
146 147
      ]
    end
D
Dmitriy Zaporozhets 已提交
148

149 150
    def project_dev_rules
      project_report_rules + [
151
        :admin_merge_request,
152 153
        :create_merge_request,
        :create_wiki,
V
Valery Sizov 已提交
154
        :manage_builds,
155
        :push_code
156 157
      ]
    end
158

159 160
    def project_archived_rules
      [
161
        :create_merge_request,
162 163
        :push_code,
        :push_code_to_protected_branches,
164
        :update_merge_request,
165 166 167 168
        :admin_merge_request
      ]
    end

169 170 171
    def project_master_rules
      project_dev_rules + [
        :push_code_to_protected_branches,
172 173
        :update_project_snippet,
        :update_merge_request,
A
Andrey Kumanyaev 已提交
174
        :admin_milestone,
A
Andrew8xx8 已提交
175
        :admin_project_snippet,
176
        :admin_project_member,
A
Andrey Kumanyaev 已提交
177 178
        :admin_merge_request,
        :admin_note,
179 180
        :admin_wiki,
        :admin_project
181 182
      ]
    end
G
gitlabhq 已提交
183

184 185
    def project_admin_rules
      project_master_rules + [
186
        :change_namespace,
187
        :change_visibility_level,
188
        :rename_project,
189 190
        :remove_project,
        :archive_project
191
      ]
A
Andrey Kumanyaev 已提交
192
    end
G
gitlabhq 已提交
193

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
    def project_disabled_features_rules(project)
      rules = []

      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

      unless project.snippets_enabled
        rules += named_abilities('project_snippet')
      end

      unless project.wiki_enabled
        rules += named_abilities('wiki')
      end

      rules
    end

221
    def group_abilities(user, group)
222 223
      rules = []

224
      if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
225 226 227
        rules << :read_group
      end

228 229
      # Only group masters and group owners can create new projects in group
      if group.has_master?(user) || group.has_owner?(user) || user.admin?
230
        rules.push(*[
231
          :create_projects,
232
        ])
233 234
      end

235
      # Only group owner and administrators can admin group
236
      if group.has_owner?(user) || user.admin?
237
        rules.push(*[
238
          :admin_group,
239 240
          :admin_namespace,
          :admin_group_member
241
        ])
242
      end
243 244 245 246

      rules.flatten
    end

247
    def namespace_abilities(user, namespace)
248 249
      rules = []

250
      # Only namespace owner and administrators can admin it
251
      if namespace.owner == user || user.admin?
252
        rules.push(*[
253
          :create_projects,
254
          :admin_namespace
255
        ])
256 257 258 259 260
      end

      rules.flatten
    end

261 262

    [:issue, :merge_request].each do |name|
G
gitlabhq 已提交
263
      define_method "#{name}_abilities" do |user, subject|
264 265 266 267
        rules = []

        if subject.author == user || (subject.respond_to?(:assignee) && subject.assignee == user)
          rules += [
G
gitlabhq 已提交
268
            :"read_#{name}",
269
            :"update_#{name}",
G
gitlabhq 已提交
270
          ]
271 272 273 274 275 276 277 278 279 280 281 282 283
        end

        rules += project_abilities(user, subject.project)
        rules
      end
    end

    [:note, :project_snippet, :personal_snippet].each do |name|
      define_method "#{name}_abilities" do |user, subject|
        rules = []

        if subject.author == user
          rules += [
284
            :"read_#{name}",
285
            :"update_#{name}",
286
            :"admin_#{name}"
287
          ]
G
gitlabhq 已提交
288
        end
289 290 291 292 293 294

        if subject.respond_to?(:project) && subject.project
          rules += project_abilities(user, subject.project)
        end

        rules
G
gitlabhq 已提交
295 296
      end
    end
297

298
    def group_member_abilities(user, subject)
299 300 301
      rules = []
      target_user = subject.user
      group = subject.group
302
      can_manage = group_abilities(user, group).include?(:admin_group_member)
303

304
      if can_manage && (user != target_user)
305
        rules << :update_group_member
306
        rules << :destroy_group_member
307
      end
308

309
      if !group.last_owner?(user) && (can_manage || (user == target_user))
310
        rules << :destroy_group_member
311
      end
312

313 314
      rules
    end
C
Ciro Santilli 已提交
315 316 317 318 319 320 321 322

    def abilities
      @abilities ||= begin
                       abilities = Six.new
                       abilities << self
                       abilities
                     end
    end
323 324 325 326 327 328

    private

    def named_abilities(name)
      [
        :"read_#{name}",
329 330
        :"create_#{name}",
        :"update_#{name}",
331 332 333
        :"admin_#{name}"
      ]
    end
G
gitlabhq 已提交
334
  end
G
gitlabhq 已提交
335
end