groups_controller.rb 5.89 KB
Newer Older
1 2
# frozen_string_literal: true

3
class GroupsController < Groups::ApplicationController
4
  include API::Helpers::RelatedResourcesHelpers
5
  include IssuableCollectionsAction
6
  include ParamsBackwardCompatibility
7
  include PreviewMarkdown
8
  include RecordUserLastActivity
9

10
  before_action do
11
    push_frontend_feature_flag(:manual_sorting, default_enabled: true)
12 13
  end

randx's avatar
randx committed
14
  respond_to :html
15

16 17 18
  prepend_before_action(only: [:show, :issues]) { authenticate_sessionless_user!(:rss) }
  prepend_before_action(only: [:issues_calendar]) { authenticate_sessionless_user!(:ics) }

19
  before_action :authenticate_user!, only: [:new, :create]
20
  before_action :group, except: [:index, :new, :create]
randx's avatar
randx committed
21

22
  # Authorize
23
  before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects, :transfer]
24
  before_action :authorize_create_group!, only: [:new]
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
25

26
  before_action :group_projects, only: [:projects, :activity, :issues, :merge_requests]
27
  before_action :event_filter, only: [:activity]
28

29
  before_action :user_actions, only: [:show]
30

31 32 33 34 35 36
  skip_cross_project_access_check :index, :new, :create, :edit, :update,
                                  :destroy, :projects
  # When loading show as an atom feed, we render events that could leak cross
  # project information
  skip_cross_project_access_check :show, if: -> { request.format.html? }

37 38
  layout :determine_layout

39
  def index
40
    redirect_to(current_user ? dashboard_groups_path : explore_groups_path)
41 42
  end

Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
43
  def new
44
    @group = Group.new(params.permit(:parent_id))
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
45 46 47
  end

  def create
Felipe Artur's avatar
Felipe Artur committed
48
    @group = Groups::CreateService.new(current_user, group_params).execute
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
49

Felipe Artur's avatar
Felipe Artur committed
50
    if @group.persisted?
Z.J. van de Weg's avatar
Z.J. van de Weg committed
51 52 53
      notice = if @group.chat_team.present?
                 "Group '#{@group.name}' and its Mattermost team were successfully created."
               else
Z.J. van de Weg's avatar
Z.J. van de Weg committed
54
                 "Group '#{@group.name}' was successfully created."
Z.J. van de Weg's avatar
Z.J. van de Weg committed
55 56 57
               end

      redirect_to @group, notice: notice
Dmitriy Zaporozhets's avatar
Dmitriy Zaporozhets committed
58 59 60 61
    else
      render action: "new"
    end
  end
62

randx's avatar
randx committed
63 64
  def show
    respond_to do |format|
65 66 67
      format.html do
        render_show_html
      end
68

69
      format.atom do
70 71 72 73 74 75 76 77 78 79 80 81 82
        render_details_view_atom
      end
    end
  end

  def details
    respond_to do |format|
      format.html do
        render_details_html
      end

      format.atom do
        render_details_view_atom
83
      end
randx's avatar
randx committed
84 85 86
    end
  end

87
  def activity
88
    respond_to do |format|
89 90
      format.html

91 92 93 94 95 96 97
      format.json do
        load_events
        pager_json("events/_events", @events.count)
      end
    end
  end

98
  def edit
99
    @badge_api_endpoint = expose_url(api_v4_groups_badges_path(id: @group.id))
100 101
  end

102
  def projects
103
    @projects = @group.projects.with_statistics.page(params[:page])
104 105
  end

106
  def update
107
    if Groups::UpdateService.new(@group, current_user, group_params).execute
108
      redirect_to edit_group_path(@group, anchor: params[:update_section]), notice: "Group '#{@group.name}' was successfully updated."
109
    else
Heinrich Lee Yu's avatar
Heinrich Lee Yu committed
110
      @group.path = @group.path_before_last_save || @group.path_was
James Lopez's avatar
James Lopez committed
111

112
      render action: "edit"
113 114 115 116
    end
  end

  def destroy
117
    Groups::DestroyService.new(@group, current_user).async_execute
118

119
    redirect_to root_path, status: 302, alert: "Group '#{@group.name}' was scheduled for deletion."
120 121
  end

122
  # rubocop: disable CodeReuse/ActiveRecord
123 124 125 126 127 128 129 130
  def transfer
    parent_group = Group.find_by(id: params[:new_parent_group_id])
    service = ::Groups::TransferService.new(@group, current_user)

    if service.execute(parent_group)
      flash[:notice] = "Group '#{@group.name}' was successfully transferred."
      redirect_to group_path(@group)
    else
131 132
      flash[:alert] = service.error
      redirect_to edit_group_path(@group)
133 134
    end
  end
135
  # rubocop: enable CodeReuse/ActiveRecord
136

randx's avatar
randx committed
137 138
  protected

139 140 141 142 143 144 145 146 147 148 149 150 151
  def render_show_html
    render 'groups/show'
  end

  def render_details_html
    render 'groups/show'
  end

  def render_details_view_atom
    load_events
    render layout: 'xml.atom', template: 'groups/show'
  end

152
  # rubocop: disable CodeReuse/ActiveRecord
153
  def authorize_create_group!
154 155 156 157 158 159 160 161
    allowed = if params[:parent_id].present?
                parent = Group.find_by(id: params[:parent_id])
                can?(current_user, :create_subgroup, parent)
              else
                can?(current_user, :create_group)
              end

    render_404 unless allowed
162
  end
163
  # rubocop: enable CodeReuse/ActiveRecord
164

165
  def determine_layout
166
    if [:new, :create].include?(action_name.to_sym)
167
      'application'
168 169
    elsif [:edit, :update, :projects].include?(action_name.to_sym)
      'group_settings'
170
    else
171
      'group'
172 173
    end
  end
174

175
  def group_params
176
    params.require(:group).permit(group_params_attributes)
177 178
  end

179
  def group_params_attributes
180
    [
181
      :avatar,
182
      :description,
183 184
      :lfs_enabled,
      :name,
185 186 187
      :path,
      :public,
      :request_access_enabled,
188
      :share_with_group_lock,
189
      :visibility_level,
190
      :parent_id,
Z.J. van de Weg's avatar
Z.J. van de Weg committed
191
      :create_chat_team,
192 193
      :chat_team_name,
      :require_two_factor_authentication,
Gosia Ksionek's avatar
Gosia Ksionek committed
194 195
      :two_factor_grace_period,
      :project_creation_level
196
    ]
197
  end
198

199
  # rubocop: disable CodeReuse/ActiveRecord
200
  def load_events
201 202 203
    params[:sort] ||= 'latest_activity_desc'

    options = {}
204
    options[:include_subgroups] = true
205 206 207 208 209

    @projects = GroupProjectsFinder.new(params: params, group: group, options: options, current_user: current_user)
                  .execute
                  .includes(:namespace)

210
    @events = EventCollection
211 212
                .new(@projects, offset: params[:offset].to_i, filter: event_filter)
                .to_a
213

214 215 216
    Events::RenderService
      .new(current_user)
      .execute(@events, atom_request: request.format.atom?)
217
  end
218
  # rubocop: enable CodeReuse/ActiveRecord
219 220 221 222 223 224

  def user_actions
    if current_user
      @notification_setting = current_user.notification_settings_for(group)
    end
  end
225 226 227

  def build_canonical_path(group)
    return group_path(group) if action_name == 'show' # root group path
228

229 230
    params[:id] = group.to_param

231
    url_for(safe_params)
232
  end
randx's avatar
randx committed
233
end