BigW Consortium Gitlab

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

Andrey Kumanyaev committed
8
      case subject.class.name
James Lopez committed
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)
Douwe Maan committed
25 26
      case true
      when subject.is_a?(PersonalSnippet)
27
        anonymous_personal_snippet_abilities(subject)
Douwe Maan committed
28
      when subject.is_a?(Project) || subject.respond_to?(:project)
29
        anonymous_project_abilities(subject)
Douwe Maan committed
30
      when subject.is_a?(Group) || subject.respond_to?(:group)
31
        anonymous_group_abilities(subject)
Douwe Maan committed
32 33 34
      else
        []
      end
35 36
    end

37
    def anonymous_project_abilities(subject)
Douwe Maan committed
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,
Kamil Trzcinski committed
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)
Douwe Maan committed
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
gitlabhq committed
91 92
    end

Andrey Kumanyaev committed
93 94
    def project_abilities(user, project)
      rules = []
95
      key = "/user/#{user.id}/project/#{project.id}"
96

97 98
      RequestStore.store[key] ||= begin
        team = project.team
gitlabhq committed
99

100 101
        # Rules based on role in project
        if team.master?(user)
102
          rules.push(*project_master_rules)
103

104
        elsif team.developer?(user)
105
          rules.push(*project_dev_rules)
106

107
        elsif team.reporter?(user)
108
          rules.push(*project_report_rules)
109

110
        elsif team.guest?(user)
111
          rules.push(*project_guest_rules)
112
        end
113

114
        if project.public? || project.internal?
115
          rules.push(*public_project_rules)
116
        end
117

118
        if project.owner == user || user.admin?
119
          rules.push(*project_admin_rules)
120
        end
121

122
        if project.group && project.group.has_owner?(user)
123
          rules.push(*project_admin_rules)
124
        end
125

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
      [
Andrey Kumanyaev committed
143 144 145
        :read_project,
        :read_wiki,
        :read_issue,
146
        :read_label,
Andrey Kumanyaev committed
147
        :read_milestone,
Andrew8xx8 committed
148
        :read_project_snippet,
149
        :read_project_member,
Andrey Kumanyaev committed
150 151
        :read_merge_request,
        :read_note,
Kamil Trzcinski committed
152
        :read_build,
153 154 155
        :create_project,
        :create_issue,
        :create_note
156 157
      ]
    end
Dmitriy Zaporozhets committed
158

159 160
    def project_report_rules
      project_guest_rules + [
161 162
        :create_commit_status,
        :read_commit_statuses,
Andrey Kumanyaev committed
163
        :download_code,
164
        :fork_project,
165 166 167
        :create_project_snippet,
        :update_issue,
        :admin_issue,
168
        :admin_label
169 170
      ]
    end
Dmitriy Zaporozhets committed
171

172 173
    def project_dev_rules
      project_report_rules + [
174
        :admin_merge_request,
175 176
        :create_merge_request,
        :create_wiki,
177
        :manage_builds,
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,
Andrey Kumanyaev committed
198
        :admin_milestone,
Andrew8xx8 committed
199
        :admin_project_snippet,
200
        :admin_project_member,
Andrey Kumanyaev committed
201 202
        :admin_merge_request,
        :admin_note,
203 204
        :admin_wiki,
        :admin_project
205 206
      ]
    end
gitlabhq committed
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
      ]
Andrey Kumanyaev committed
217
    end
gitlabhq committed
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?
Douwe Maan committed
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?
Douwe Maan committed
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|
gitlabhq committed
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 += [
gitlabhq committed
293
            :"read_#{name}",
294
            :"update_#{name}",
gitlabhq committed
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
          ]
gitlabhq committed
313
        end
314 315 316 317 318 319

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

        rules
gitlabhq committed
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?
Douwe Maan committed
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

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

Douwe Maan committed
349 350 351 352 353 354 355 356
        if can_manage && user != target_user
          rules << :update_group_member
          rules << :destroy_group_member
        end

        if user == target_user
          rules << :destroy_group_member
        end
357
      end
358

359 360
      rules
    end
Ciro Santilli committed
361

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

Douwe Maan committed
367 368
      unless target_user == project.owner
        can_manage = project_abilities(user, project).include?(:admin_project_member)
369

Douwe Maan committed
370 371 372 373 374 375 376 377
        if can_manage && user != target_user
          rules << :update_project_member
          rules << :destroy_project_member
        end

        if user == target_user
          rules << :destroy_project_member
        end
378
      end
Douwe Maan committed
379

380 381 382
      rules
    end

Ciro Santilli committed
383 384
    def abilities
      @abilities ||= begin
385 386 387 388
        abilities = Six.new
        abilities << self
        abilities
      end
Ciro Santilli committed
389
    end
390 391 392 393 394 395

    private

    def named_abilities(name)
      [
        :"read_#{name}",
396 397
        :"create_#{name}",
        :"update_#{name}",
398 399 400
        :"admin_#{name}"
      ]
    end
gitlabhq committed
401
  end
gitlabhq committed
402
end