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

A
Andrey Kumanyaev 已提交
8
      case subject.class.name
J
James Lopez 已提交
9 10 11 12 13 14 15 16 17 18 19
      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)
      when "ProjectMember" then project_member_abilities(user, subject)
      else []
20 21 22
      end.concat(global_abilities(user))
    end

23 24
    # List of possible abilities for anonymous user
    def anonymous_abilities(user, subject)
D
Douwe Maan 已提交
25 26
      case true
      when subject.is_a?(PersonalSnippet)
27
        anonymous_personal_snippet_abilities(subject)
D
Douwe Maan 已提交
28
      when subject.is_a?(Project) || subject.respond_to?(:project)
29
        anonymous_project_abilities(subject)
D
Douwe Maan 已提交
30
      when subject.is_a?(Group) || subject.respond_to?(:group)
31
        anonymous_group_abilities(subject)
D
Douwe Maan 已提交
32 33 34
      else
        []
      end
35 36
    end

37
    def anonymous_project_abilities(subject)
D
Douwe Maan 已提交
38
      project = if subject.is_a?(Project)
39 40
                  subject
                else
41
                  subject.project
42 43
                end

44
      if project && project.public?
45
        rules = [
46 47 48
          :read_project,
          :read_wiki,
          :read_issue,
49
          :read_label,
50 51
          :read_milestone,
          :read_project_snippet,
52
          :read_project_member,
53 54
          :read_merge_request,
          :read_note,
K
Kamil Trzcinski 已提交
55
          :read_build,
56 57
          :download_code
        ]
58 59

        rules - project_disabled_features_rules(project)
60
      else
61 62 63
        []
      end
    end
64

65
    def anonymous_group_abilities(subject)
D
Douwe Maan 已提交
66
      group = if subject.is_a?(Group)
67 68 69 70 71
                subject
              else
                subject.group
              end

72
      if group && group.projects.public_only.any?
73 74 75 76 77 78
        [:read_group]
      else
        []
      end
    end

79
    def anonymous_personal_snippet_abilities(snippet)
80 81 82 83
      if snippet.public?
        [:read_personal_snippet]
      else
        []
84 85 86
      end
    end

87 88 89 90
    def global_abilities(user)
      rules = []
      rules << :create_group if user.can_create_group
      rules
G
gitlabhq 已提交
91 92
    end

A
Andrey Kumanyaev 已提交
93 94
    def project_abilities(user, project)
      rules = []
S
skv-headless 已提交
95
      key = "/user/#{user.id}/project/#{project.id}"
96

S
skv-headless 已提交
97 98
      RequestStore.store[key] ||= begin
        team = project.team
G
gitlabhq 已提交
99

S
skv-headless 已提交
100 101
        # Rules based on role in project
        if team.master?(user)
102
          rules.push(*project_master_rules)
D
Dmitriy Zaporozhets 已提交
103

S
skv-headless 已提交
104
        elsif team.developer?(user)
105
          rules.push(*project_dev_rules)
106

S
skv-headless 已提交
107
        elsif team.reporter?(user)
108
          rules.push(*project_report_rules)
109

S
skv-headless 已提交
110
        elsif team.guest?(user)
111
          rules.push(*project_guest_rules)
S
skv-headless 已提交
112
        end
113

S
skv-headless 已提交
114
        if project.public? || project.internal?
115
          rules.push(*public_project_rules)
S
skv-headless 已提交
116
        end
117

S
skv-headless 已提交
118
        if project.owner == user || user.admin?
119
          rules.push(*project_admin_rules)
S
skv-headless 已提交
120
        end
121

S
skv-headless 已提交
122
        if project.group && project.group.has_owner?(user)
123
          rules.push(*project_admin_rules)
S
skv-headless 已提交
124
        end
125

S
skv-headless 已提交
126 127 128
        if project.archived?
          rules -= project_archived_rules
        end
129

130
        rules - project_disabled_features_rules(project)
131
      end
132 133
    end

134
    def public_project_rules
J
Jason Lee 已提交
135
      @public_project_rules ||= project_guest_rules + [
136
        :download_code,
137
        :fork_project
138 139 140
      ]
    end

141
    def project_guest_rules
J
Jason Lee 已提交
142
      @project_guest_rules ||= [
A
Andrey Kumanyaev 已提交
143 144 145
        :read_project,
        :read_wiki,
        :read_issue,
146
        :read_label,
A
Andrey Kumanyaev 已提交
147
        :read_milestone,
A
Andrew8xx8 已提交
148
        :read_project_snippet,
149
        :read_project_member,
A
Andrey Kumanyaev 已提交
150 151
        :read_merge_request,
        :read_note,
K
Kamil Trzcinski 已提交
152
        :read_build,
153 154 155
        :create_project,
        :create_issue,
        :create_note
156 157
      ]
    end
D
Dmitriy Zaporozhets 已提交
158

159
    def project_report_rules
J
Jason Lee 已提交
160
      @project_report_rules ||= project_guest_rules + [
K
Kamil Trzcinski 已提交
161 162
        :create_commit_status,
        :read_commit_statuses,
163
        :read_build_artifacts,
A
Andrey Kumanyaev 已提交
164
        :download_code,
165
        :fork_project,
166 167 168
        :create_project_snippet,
        :update_issue,
        :admin_issue,
169
        :admin_label
170 171
      ]
    end
D
Dmitriy Zaporozhets 已提交
172

173
    def project_dev_rules
J
Jason Lee 已提交
174
      @project_dev_rules ||= project_report_rules + [
175
        :admin_merge_request,
176 177
        :create_merge_request,
        :create_wiki,
V
Valery Sizov 已提交
178
        :manage_builds,
179
        :push_code
180 181
      ]
    end
182

183
    def project_archived_rules
J
Jason Lee 已提交
184
      @project_archived_rules ||= [
185
        :create_merge_request,
186 187
        :push_code,
        :push_code_to_protected_branches,
188
        :update_merge_request,
189 190 191 192
        :admin_merge_request
      ]
    end

193
    def project_master_rules
J
Jason Lee 已提交
194
      @project_master_rules ||= project_dev_rules + [
195
        :push_code_to_protected_branches,
196 197
        :update_project_snippet,
        :update_merge_request,
A
Andrey Kumanyaev 已提交
198
        :admin_milestone,
A
Andrew8xx8 已提交
199
        :admin_project_snippet,
200
        :admin_project_member,
A
Andrey Kumanyaev 已提交
201 202
        :admin_merge_request,
        :admin_note,
203 204
        :admin_wiki,
        :admin_project
205 206
      ]
    end
G
gitlabhq 已提交
207

208
    def project_admin_rules
J
Jason Lee 已提交
209
      @project_admin_rules ||= project_master_rules + [
210
        :change_namespace,
211
        :change_visibility_level,
212
        :rename_project,
213
        :remove_project,
214 215
        :archive_project,
        :remove_fork_project
216
      ]
A
Andrey Kumanyaev 已提交
217
    end
G
gitlabhq 已提交
218

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
    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

246
    def group_abilities(user, group)
247 248
      rules = []

249
      if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
250 251 252
        rules << :read_group
      end

253 254
      # Only group masters and group owners can create new projects in group
      if group.has_master?(user) || group.has_owner?(user) || user.admin?
255
        rules += [
256
          :create_projects,
257
          :admin_milestones
258
        ]
259 260
      end

261
      # Only group owner and administrators can admin group
262
      if group.has_owner?(user) || user.admin?
D
Douwe Maan 已提交
263 264 265 266 267
        rules += [
          :admin_group,
          :admin_namespace,
          :admin_group_member
        ]
268
      end
269 270 271 272

      rules.flatten
    end

273
    def namespace_abilities(user, namespace)
274 275
      rules = []

276
      # Only namespace owner and administrators can admin it
277
      if namespace.owner == user || user.admin?
D
Douwe Maan 已提交
278 279 280 281
        rules += [
          :create_projects,
          :admin_namespace
        ]
282 283 284 285 286
      end

      rules.flatten
    end

287
    [:issue, :merge_request].each do |name|
G
gitlabhq 已提交
288
      define_method "#{name}_abilities" do |user, subject|
289 290 291 292
        rules = []

        if subject.author == user || (subject.respond_to?(:assignee) && subject.assignee == user)
          rules += [
G
gitlabhq 已提交
293
            :"read_#{name}",
294
            :"update_#{name}",
G
gitlabhq 已提交
295
          ]
296 297 298 299 300 301 302
        end

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

303
    [:note, :project_snippet].each do |name|
304 305 306 307 308
      define_method "#{name}_abilities" do |user, subject|
        rules = []

        if subject.author == user
          rules += [
309
            :"read_#{name}",
310
            :"update_#{name}",
311
            :"admin_#{name}"
312
          ]
G
gitlabhq 已提交
313
        end
314 315 316 317 318 319

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

        rules
G
gitlabhq 已提交
320 321
      end
    end
322

323 324 325 326 327 328 329 330 331 332 333 334
    def personal_snippet_abilities(user, snippet)
      rules = []

      if snippet.author == user
        rules += [
          :read_personal_snippet,
          :update_personal_snippet,
          :admin_personal_snippet
        ]
      end

      if snippet.public? || snippet.internal?
J
Jason Lee 已提交
335
        rules << :read_personal_snippet
336 337 338 339 340
      end

      rules
    end

341
    def group_member_abilities(user, subject)
342 343 344
      rules = []
      target_user = subject.user
      group = subject.group
345

D
Douwe Maan 已提交
346 347
      unless group.last_owner?(target_user)
        can_manage = group_abilities(user, group).include?(:admin_group_member)
348

349
        if can_manage
D
Douwe Maan 已提交
350 351
          rules << :update_group_member
          rules << :destroy_group_member
352
        elsif user == target_user
D
Douwe Maan 已提交
353 354
          rules << :destroy_group_member
        end
355
      end
356

357 358
      rules
    end
C
Ciro Santilli 已提交
359

360 361 362 363 364
    def project_member_abilities(user, subject)
      rules = []
      target_user = subject.user
      project = subject.project

D
Douwe Maan 已提交
365 366
      unless target_user == project.owner
        can_manage = project_abilities(user, project).include?(:admin_project_member)
367

368
        if can_manage
D
Douwe Maan 已提交
369 370
          rules << :update_project_member
          rules << :destroy_project_member
371
        elsif user == target_user
D
Douwe Maan 已提交
372 373
          rules << :destroy_project_member
        end
374
      end
D
Douwe Maan 已提交
375

376 377 378
      rules
    end

C
Ciro Santilli 已提交
379 380
    def abilities
      @abilities ||= begin
381 382 383 384
        abilities = Six.new
        abilities << self
        abilities
      end
C
Ciro Santilli 已提交
385
    end
386 387 388 389 390 391

    private

    def named_abilities(name)
      [
        :"read_#{name}",
392 393
        :"create_#{name}",
        :"update_#{name}",
394 395 396
        :"admin_#{name}"
      ]
    end
G
gitlabhq 已提交
397
  end
G
gitlabhq 已提交
398
end