ability.rb 8.1 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
        :remove_project,
192 193
        :archive_project,
        :remove_fork_project
194
      ]
A
Andrey Kumanyaev 已提交
195
    end
G
gitlabhq 已提交
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 223
    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

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

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

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

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

      rules.flatten
    end

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

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

      rules.flatten
    end

264 265

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

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

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

        rules
G
gitlabhq 已提交
298 299
      end
    end
300

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

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

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

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

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

    private

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