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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

223
    def group_abilities(user, group)
224 225
      rules = []

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

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

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

      rules.flatten
    end

249
    def namespace_abilities(user, namespace)
250 251
      rules = []

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

      rules.flatten
    end

263 264

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

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

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

        rules
G
gitlabhq 已提交
297 298
      end
    end
299

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

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

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

315 316
      rules
    end
C
Ciro Santilli 已提交
317 318 319 320 321 322 323 324

    def abilities
      @abilities ||= begin
                       abilities = Six.new
                       abilities << self
                       abilities
                     end
    end
325 326 327 328 329 330

    private

    def named_abilities(name)
      [
        :"read_#{name}",
331 332
        :"create_#{name}",
        :"update_#{name}",
333 334 335
        :"admin_#{name}"
      ]
    end
G
gitlabhq 已提交
336
  end
G
gitlabhq 已提交
337
end