1# frozen_string_literal: true
2
3class GroupChildEntity < Grape::Entity
4  include ActionView::Helpers::NumberHelper
5  include RequestAwareEntity
6  include MarkupHelper
7
8  expose :id, :name, :description, :visibility, :full_name,
9         :created_at, :updated_at, :avatar_url
10
11  expose :type do |instance|
12    type
13  end
14
15  expose :can_edit do |instance|
16    can_edit?
17  end
18
19  expose :edit_path do |instance|
20    # We know `type` will be one either `project` or `group`.
21    # The `edit_polymorphic_path` helper would try to call the path helper
22    # with a plural: `edit_groups_path(instance)` or `edit_projects_path(instance)`
23    # while our methods are `edit_group_path` or `edit_project_path`
24    public_send("edit_#{type}_path", instance) # rubocop:disable GitlabSecurity/PublicSend
25  end
26
27  expose :relative_path do |instance|
28    polymorphic_path(instance)
29  end
30
31  expose :permission do |instance|
32    membership&.human_access
33  end
34
35  # Project only attributes
36  expose :star_count, :archived,
37         if: lambda { |_instance, _options| project? }
38
39  # Group only attributes
40  expose :children_count, :parent_id,
41         unless: lambda { |_instance, _options| project? }
42
43  expose :subgroup_count, if: lambda { |group| access_group_counts?(group) }
44
45  expose :project_count, if: lambda { |group| access_group_counts?(group) }
46
47  expose :leave_path, unless: lambda { |_instance, _options| project? } do |instance|
48    leave_group_members_path(instance)
49  end
50
51  expose :can_leave, unless: lambda { |_instance, _options| project? } do |instance|
52    if membership
53      can?(request.current_user, :destroy_group_member, membership)
54    else
55      false
56    end
57  end
58
59  expose :number_users_with_delimiter, unless: lambda { |_instance, _options| project? } do |instance|
60    number_with_delimiter(instance.member_count)
61  end
62
63  expose :markdown_description do |instance|
64    markdown_description
65  end
66
67  private
68
69  def access_group_counts?(group)
70    !project? && can?(request.current_user, :read_counts, group)
71  end
72
73  # rubocop: disable CodeReuse/ActiveRecord
74  def membership
75    return unless request.current_user
76
77    @membership ||= request.current_user.members.find_by(source: object)
78  end
79  # rubocop: enable CodeReuse/ActiveRecord
80
81  def project?
82    object.is_a?(Project)
83  end
84
85  def type
86    object.class.name.downcase
87  end
88
89  def markdown_description
90    markdown_field(object, :description)
91  end
92
93  def can_edit?
94    return false unless request.respond_to?(:current_user)
95
96    if project?
97      # Avoid checking rights for each project, as it might be expensive if the
98      # user cannot read cross project.
99      can?(request.current_user, :read_cross_project) &&
100        can?(request.current_user, :admin_project, object)
101    else
102      can?(request.current_user, :admin_group, object)
103    end
104  end
105end
106
107GroupChildEntity.prepend_mod_with('GroupChildEntity')
108