gitlab-ce/app/services/groups/create_service.rb

208 lines
7.0 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frozen_string_literal: true
module Groups
class CreateService < Groups::BaseService
def initialize(user, params = {})
@current_user = user
@params = params.dup
@chat_team = @params.delete(:create_chat_team)
end
def execute
build_group
after_build_hook
return error_response unless valid?
@group.name ||= @group.path.dup
create_chat_team
create_group
return error_response unless @group.persisted?
after_successful_creation_hook
ServiceResponse.success(payload: { group: @group })
end
private
def valid?
valid_visibility_level? && valid_user_permissions?
end
def error_response
ServiceResponse.error(message: 'Group has errors', payload: { group: @group })
end
def create_chat_team
return unless valid_to_create_chat_team?
response = ::Mattermost::CreateTeamService.new(@group, current_user).execute
return ServiceResponse.error(message: 'Group has errors', payload: { group: @group }) if @group.errors.any?
@group.build_chat_team(name: response['name'], team_id: response['id'])
end
def build_group
remove_unallowed_params
set_visibility_level
except_keys = ::NamespaceSetting.allowed_namespace_settings_params + [:organization_id]
@group = Group.new(params.except(*except_keys))
set_organization
@group.build_namespace_settings
handle_namespace_settings
end
def create_group
Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.temporary_ignore_tables_in_transaction(
%w[routes redirect_routes], url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/424281'
) do
Group.transaction do
if @group.save
@group.add_owner(current_user)
Integration.create_from_active_default_integrations(@group, :group_id)
add_creator
end
end
end
end
def after_build_hook
inherit_group_shared_runners_settings
end
def add_creator
# The creator needs to be added after the group is saved because a database trigger automatically creates the
# namespace_details after a namespace is created. If we attempt to build the namespace details
# like we do with the namespace settings, the trigger will fire first and rails will subsequently try
# to create the namespace_details which will result in an error due to a primary key conflict.
#
# See https://gitlab.com/gitlab-org/gitlab/-/merge_requests/82958/diffs#diff-content-c02244956d423e6837379548e5f9b1fa093bb289
@group.namespace_details.creator = current_user
@group.namespace_details.save
end
def after_successful_creation_hook
# overridden in EE
end
def remove_unallowed_params
unless can?(current_user, :create_group_with_default_branch_protection)
params.delete(:default_branch_protection)
params.delete(:default_branch_protection_defaults)
end
params.delete(:allow_mfa_for_subgroups)
params.delete(:remove_dormant_members)
params.delete(:remove_dormant_members_period)
params.delete(:math_rendering_limits_enabled)
params.delete(:lock_math_rendering_limits_enabled)
end
def valid_to_create_chat_team?
Gitlab.config.mattermost.enabled && @chat_team && @group.chat_team.nil?
end
def valid_user_permissions?
if @group.subgroup?
unless can?(current_user, :create_subgroup, @group.parent)
@group.parent = nil
@group.errors.add(:parent_id, s_('CreateGroup|You dont have permission to create a subgroup in this group.'))
return false
end
else
unless can?(current_user, :create_group)
@group.errors.add(:base, s_('CreateGroup|You dont have permission to create groups.'))
return false
end
end
return true if organization_setting_valid?
# We are unsetting this here to match behavior of invalid parent_id above and protect against possible
# committing to the database of a value that isn't allowed.
@group.organization = nil
false
end
def can_create_group_in_organization?
return true if can?(current_user, :create_group, @group.organization)
message = s_("CreateGroup|You don't have permission to create a group in the provided organization.")
@group.errors.add(:organization_id, message)
false
end
def matches_parent_organization?
return true if @group.parent_id.blank?
return true if @group.parent.organization_id == @group.organization_id
message = s_("CreateGroup|You can't create a group in a different organization than the parent group.")
@group.errors.add(:organization_id, message)
false
end
def organization_setting_valid?
# we check for the params presence explicitly since:
# 1. We have a default organization_id at db level set and organization exists and may not have the entry
# in organization_users table to allow authorization. This shouldn't be the case longterm as we
# plan on populating organization_users correctly.
# 2. We shouldn't need to check if this is allowed if the user didn't try to set it themselves. i.e.
# provided in the params
return true if params[:organization_id].blank?
# There is a chance the organization is still blank(if not default organization), but that is the only case
# where we should allow this to not actually be a record in the database.
# Otherwise it isn't valid to set this to a non-existent record id and we'll check that in the lines after
# this code.
return true if @group.organization.blank? && Organizations::Organization.default?(params[:organization_id])
can_create_group_in_organization? && matches_parent_organization?
end
def valid_visibility_level?
return true if Gitlab::VisibilityLevel.allowed_for?(current_user, visibility_level)
deny_visibility_level(@group)
false
end
def set_visibility_level
return if visibility_level.present?
params[:visibility_level] = Gitlab::CurrentSettings.current_application_settings.default_group_visibility
end
def inherit_group_shared_runners_settings
return unless @group.parent
@group.shared_runners_enabled = @group.parent.shared_runners_enabled
@group.allow_descendants_override_disabled_shared_runners = @group.parent.allow_descendants_override_disabled_shared_runners
end
def set_organization
if params[:organization_id]
@group.organization_id = params[:organization_id]
elsif @group.parent_id
@group.organization = @group.parent.organization
# Rely on middleware setting of the organization, but sometimes it won't be set, so we need to guard it here.
elsif Current.organization
@group.organization = Current.organization
end
end
end
end
Groups::CreateService.prepend_mod_with('Groups::CreateService')