ability.rb 9.4 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 72 73 74 75 76 77 78
                subject
              else
                subject.group
              end

      if group && group.public_profile?
        [: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
135
      project_guest_rules + [
136
        :download_code,
137
        :fork_project
138 139 140
      ]
    end

141 142
    def 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 160
    def project_report_rules
      project_guest_rules + [
K
Kamil Trzcinski 已提交
161 162
        :create_commit_status,
        :read_commit_statuses,
A
Andrey Kumanyaev 已提交
163
        :download_code,
164
        :fork_project,
165 166 167
        :create_project_snippet,
        :update_issue,
        :admin_issue,
168
        :admin_label
169 170
      ]
    end
D
Dmitriy Zaporozhets 已提交
171

172 173
    def project_dev_rules
      project_report_rules + [
174
        :admin_merge_request,
175 176
        :create_merge_request,
        :create_wiki,
V
Valery Sizov 已提交
177
        :manage_builds,
K
Kamil Trzcinski 已提交
178
        :download_build_artifacts,
179
        :push_code
180 181
      ]
    end
182

183 184
    def 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 194 195
    def project_master_rules
      project_dev_rules + [
        :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 209
    def 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?
D
Douwe Maan 已提交
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

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

        if user == target_user
          rules << :destroy_project_member
        end
376
      end
D
Douwe Maan 已提交
377

378 379 380
      rules
    end

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

    private

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