ability.rb 8.7 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
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 25 26 27 28 29 30 31 32 33
    # 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

34
      if project && project.public?
35
        rules = [
36 37 38
          :read_project,
          :read_wiki,
          :read_issue,
39
          :read_label,
40 41
          :read_milestone,
          :read_project_snippet,
42
          :read_project_member,
43 44
          :read_merge_request,
          :read_note,
K
Kamil Trzcinski 已提交
45
          :read_build,
46 47
          :download_code
        ]
48 49

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

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

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

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

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

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

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

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

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

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

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

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

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

110
        rules - project_disabled_features_rules(project)
111
      end
112 113
    end

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

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

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

152 153
    def project_dev_rules
      project_report_rules + [
154
        :admin_merge_request,
155 156
        :create_merge_request,
        :create_wiki,
V
Valery Sizov 已提交
157
        :manage_builds,
K
Kamil Trzcinski 已提交
158
        :download_build_artifacts,
159
        :push_code
160 161
      ]
    end
162

163 164
    def project_archived_rules
      [
165
        :create_merge_request,
166 167
        :push_code,
        :push_code_to_protected_branches,
168
        :update_merge_request,
169 170 171 172
        :admin_merge_request
      ]
    end

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

188 189
    def project_admin_rules
      project_master_rules + [
190
        :change_namespace,
191
        :change_visibility_level,
192
        :rename_project,
193
        :remove_project,
194 195
        :archive_project,
        :remove_fork_project
196
      ]
A
Andrey Kumanyaev 已提交
197
    end
G
gitlabhq 已提交
198

199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
    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

226
    def group_abilities(user, group)
227 228
      rules = []

229
      if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
230 231 232
        rules << :read_group
      end

233 234
      # Only group masters and group owners can create new projects in group
      if group.has_master?(user) || group.has_owner?(user) || user.admin?
235
        rules += [
236
          :create_projects,
237
          :admin_milestones
238
        ]
239 240
      end

241
      # Only group owner and administrators can admin group
242
      if group.has_owner?(user) || user.admin?
243
        rules.push(*[
244 245 246 247
                     :admin_group,
                     :admin_namespace,
                     :admin_group_member
                   ])
248
      end
249 250 251 252

      rules.flatten
    end

253
    def namespace_abilities(user, namespace)
254 255
      rules = []

256
      # Only namespace owner and administrators can admin it
257
      if namespace.owner == user || user.admin?
258
        rules.push(*[
259 260 261
                     :create_projects,
                     :admin_namespace
                   ])
262 263 264 265 266
      end

      rules.flatten
    end

267 268

    [:issue, :merge_request].each do |name|
G
gitlabhq 已提交
269
      define_method "#{name}_abilities" do |user, subject|
270 271 272 273
        rules = []

        if subject.author == user || (subject.respond_to?(:assignee) && subject.assignee == user)
          rules += [
G
gitlabhq 已提交
274
            :"read_#{name}",
275
            :"update_#{name}",
G
gitlabhq 已提交
276
          ]
277 278 279 280 281 282 283 284 285 286 287 288 289
        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 += [
290
            :"read_#{name}",
291
            :"update_#{name}",
292
            :"admin_#{name}"
293
          ]
G
gitlabhq 已提交
294
        end
295 296 297 298 299 300

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

        rules
G
gitlabhq 已提交
301 302
      end
    end
303

304
    def group_member_abilities(user, subject)
305 306 307
      rules = []
      target_user = subject.user
      group = subject.group
308
      can_manage = group_abilities(user, group).include?(:admin_group_member)
309

310
      if can_manage && (user != target_user)
311
        rules << :update_group_member
312
        rules << :destroy_group_member
313
      end
314

315
      if !group.last_owner?(user) && (can_manage || (user == target_user))
316
        rules << :destroy_group_member
317
      end
318

319 320
      rules
    end
C
Ciro Santilli 已提交
321

322 323 324 325 326 327
    def project_member_abilities(user, subject)
      rules = []
      target_user = subject.user
      project = subject.project
      can_manage = project_abilities(user, project).include?(:admin_project_member)

328
      if can_manage && user != target_user && target_user != project.owner
329 330 331 332
        rules << :update_project_member
        rules << :destroy_project_member
      end

333
      if user == target_user && target_user != project.owner
334 335 336 337 338
        rules << :destroy_project_member
      end
      rules
    end

C
Ciro Santilli 已提交
339 340
    def abilities
      @abilities ||= begin
341 342 343 344
        abilities = Six.new
        abilities << self
        abilities
      end
C
Ciro Santilli 已提交
345
    end
346 347 348 349 350 351

    private

    def named_abilities(name)
      [
        :"read_#{name}",
352 353
        :"create_#{name}",
        :"update_#{name}",
354 355 356
        :"admin_#{name}"
      ]
    end
G
gitlabhq 已提交
357
  end
G
gitlabhq 已提交
358
end