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
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,
158
        :push_code
159 160
      ]
    end
161

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

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

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

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
    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

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

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

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

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

      rules.flatten
    end

251
    def namespace_abilities(user, namespace)
252 253
      rules = []

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

      rules.flatten
    end

265 266

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

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

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

        rules
G
gitlabhq 已提交
299 300
      end
    end
301

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

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

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

317 318
      rules
    end
C
Ciro Santilli 已提交
319

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

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

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

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

    private

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