ability.rb 8.9 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
    # List of possible abilities
    # for non-authenticated user
    def not_auth_abilities(user, subject)
25 26 27 28 29 30 31
      return not_auth_personal_snippet_abilities(subject) if subject.kind_of?(PersonalSnippet)
      return not_auth_project_abilities(subject) if subject.kind_of?(Project) || subject.respond_to?(:project)
      return not_auth_group_abilities(subject) if subject.kind_of?(Group) || subject.respond_to?(:group)
      []
    end

    def not_auth_project_abilities(subject)
32 33 34
      project = if subject.kind_of?(Project)
                  subject
                else
35
                  subject.project
36 37
                end

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

        rules - project_disabled_features_rules(project)
54
      else
55 56 57
        []
      end
    end
58

59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
    def not_auth_group_abilities(subject)
      group = if subject.kind_of?(Group)
                subject
              else
                subject.group
              end

      if group && group.public_profile?
        [:read_group]
      else
        []
      end
    end

    def not_auth_personal_snippet_abilities(snippet)
      if snippet.public?
        [:read_personal_snippet]
      else
        []
78 79 80
      end
    end

81 82 83 84
    def global_abilities(user)
      rules = []
      rules << :create_group if user.can_create_group
      rules
G
gitlabhq 已提交
85 86
    end

A
Andrey Kumanyaev 已提交
87 88
    def project_abilities(user, project)
      rules = []
S
skv-headless 已提交
89
      key = "/user/#{user.id}/project/#{project.id}"
90

S
skv-headless 已提交
91 92
      RequestStore.store[key] ||= begin
        team = project.team
G
gitlabhq 已提交
93

S
skv-headless 已提交
94 95
        # Rules based on role in project
        if team.master?(user)
96
          rules.push(*project_master_rules)
D
Dmitriy Zaporozhets 已提交
97

S
skv-headless 已提交
98
        elsif team.developer?(user)
99
          rules.push(*project_dev_rules)
100

S
skv-headless 已提交
101
        elsif team.reporter?(user)
102
          rules.push(*project_report_rules)
103

S
skv-headless 已提交
104
        elsif team.guest?(user)
105
          rules.push(*project_guest_rules)
S
skv-headless 已提交
106
        end
107

S
skv-headless 已提交
108
        if project.public? || project.internal?
109
          rules.push(*public_project_rules)
S
skv-headless 已提交
110
        end
111

S
skv-headless 已提交
112
        if project.owner == user || user.admin?
113
          rules.push(*project_admin_rules)
S
skv-headless 已提交
114
        end
115

S
skv-headless 已提交
116
        if project.group && project.group.has_owner?(user)
117
          rules.push(*project_admin_rules)
S
skv-headless 已提交
118
        end
119

S
skv-headless 已提交
120 121 122
        if project.archived?
          rules -= project_archived_rules
        end
123

124
        rules - project_disabled_features_rules(project)
125
      end
126 127
    end

128
    def public_project_rules
129
      project_guest_rules + [
130
        :download_code,
131
        :fork_project
132 133 134
      ]
    end

135 136
    def project_guest_rules
      [
A
Andrey Kumanyaev 已提交
137 138 139
        :read_project,
        :read_wiki,
        :read_issue,
140
        :read_label,
A
Andrey Kumanyaev 已提交
141
        :read_milestone,
A
Andrew8xx8 已提交
142
        :read_project_snippet,
143
        :read_project_member,
A
Andrey Kumanyaev 已提交
144 145
        :read_merge_request,
        :read_note,
K
Kamil Trzcinski 已提交
146
        :read_build,
147 148 149
        :create_project,
        :create_issue,
        :create_note
150 151
      ]
    end
D
Dmitriy Zaporozhets 已提交
152

153 154
    def project_report_rules
      project_guest_rules + [
K
Kamil Trzcinski 已提交
155 156
        :create_commit_status,
        :read_commit_statuses,
A
Andrey Kumanyaev 已提交
157
        :download_code,
158
        :fork_project,
159 160 161
        :create_project_snippet,
        :update_issue,
        :admin_issue,
162
        :admin_label
163 164
      ]
    end
D
Dmitriy Zaporozhets 已提交
165

166 167
    def project_dev_rules
      project_report_rules + [
168
        :admin_merge_request,
169 170
        :create_merge_request,
        :create_wiki,
V
Valery Sizov 已提交
171
        :manage_builds,
K
Kamil Trzcinski 已提交
172
        :download_build_artifacts,
173
        :push_code
174 175
      ]
    end
176

177 178
    def project_archived_rules
      [
179
        :create_merge_request,
180 181
        :push_code,
        :push_code_to_protected_branches,
182
        :update_merge_request,
183 184 185 186
        :admin_merge_request
      ]
    end

187 188 189
    def project_master_rules
      project_dev_rules + [
        :push_code_to_protected_branches,
190 191
        :update_project_snippet,
        :update_merge_request,
A
Andrey Kumanyaev 已提交
192
        :admin_milestone,
A
Andrew8xx8 已提交
193
        :admin_project_snippet,
194
        :admin_project_member,
A
Andrey Kumanyaev 已提交
195 196
        :admin_merge_request,
        :admin_note,
197 198
        :admin_wiki,
        :admin_project
199 200
      ]
    end
G
gitlabhq 已提交
201

202 203
    def project_admin_rules
      project_master_rules + [
204
        :change_namespace,
205
        :change_visibility_level,
206
        :rename_project,
207
        :remove_project,
208 209
        :archive_project,
        :remove_fork_project
210
      ]
A
Andrey Kumanyaev 已提交
211
    end
G
gitlabhq 已提交
212

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
    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

240
    def group_abilities(user, group)
241 242
      rules = []

243
      if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
244 245 246
        rules << :read_group
      end

247 248
      # Only group masters and group owners can create new projects in group
      if group.has_master?(user) || group.has_owner?(user) || user.admin?
249
        rules.push(*[
250
          :create_projects,
251
          :admin_milestones
252
        ])
253 254
      end

255
      # Only group owner and administrators can admin group
256
      if group.has_owner?(user) || user.admin?
257
        rules.push(*[
258
          :admin_group,
259 260
          :admin_namespace,
          :admin_group_member
261
        ])
262
      end
263 264 265 266

      rules.flatten
    end

267
    def namespace_abilities(user, namespace)
268 269
      rules = []

270
      # Only namespace owner and administrators can admin it
271
      if namespace.owner == user || user.admin?
272
        rules.push(*[
273
          :create_projects,
274
          :admin_namespace
275
        ])
276 277 278 279 280
      end

      rules.flatten
    end

281 282

    [:issue, :merge_request].each do |name|
G
gitlabhq 已提交
283
      define_method "#{name}_abilities" do |user, subject|
284 285 286 287
        rules = []

        if subject.author == user || (subject.respond_to?(:assignee) && subject.assignee == user)
          rules += [
G
gitlabhq 已提交
288
            :"read_#{name}",
289
            :"update_#{name}",
G
gitlabhq 已提交
290
          ]
291 292 293 294 295 296 297
        end

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

298
    [:note, :project_snippet].each do |name|
299 300 301 302 303
      define_method "#{name}_abilities" do |user, subject|
        rules = []

        if subject.author == user
          rules += [
304
            :"read_#{name}",
305
            :"update_#{name}",
306
            :"admin_#{name}"
307
          ]
G
gitlabhq 已提交
308
        end
309 310 311 312 313 314

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

        rules
G
gitlabhq 已提交
315 316
      end
    end
317

318 319 320 321 322 323 324 325 326 327 328 329
    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?
330
        rules.push(:read_personal_snippet)
331 332 333 334 335
      end

      rules
    end

336
    def group_member_abilities(user, subject)
337 338 339
      rules = []
      target_user = subject.user
      group = subject.group
340
      can_manage = group_abilities(user, group).include?(:admin_group_member)
341

342
      if can_manage && (user != target_user)
343
        rules << :update_group_member
344
        rules << :destroy_group_member
345
      end
346

347
      if !group.last_owner?(user) && (can_manage || (user == target_user))
348
        rules << :destroy_group_member
349
      end
350

351 352
      rules
    end
C
Ciro Santilli 已提交
353 354 355 356 357 358 359 360

    def abilities
      @abilities ||= begin
                       abilities = Six.new
                       abilities << self
                       abilities
                     end
    end
361 362 363 364 365 366

    private

    def named_abilities(name)
      [
        :"read_#{name}",
367 368
        :"create_#{name}",
        :"update_#{name}",
369 370 371
        :"admin_#{name}"
      ]
    end
G
gitlabhq 已提交
372
  end
G
gitlabhq 已提交
373
end