1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
|
# frozen_string_literal: true
class Import::BitbucketServerController < Import::BaseController
extend ::Gitlab::Utils::Override
include ActionView::Helpers::SanitizeHelper
before_action :verify_bitbucket_server_import_enabled
before_action :bitbucket_auth, except: [:new, :configure]
before_action :normalize_import_params, only: [:create]
before_action :validate_import_params, only: [:create]
rescue_from BitbucketServer::Connection::ConnectionError, with: :bitbucket_connection_error
# As a basic sanity check to prevent URL injection, restrict project
# repository input and repository slugs to allowed characters. For Bitbucket:
#
# Project keys must start with a letter and may only consist of ASCII letters, numbers and underscores (A-Z, a-z, 0-9, _).
#
# Repository names are limited to 128 characters. They must start with a
# letter or number and may contain spaces, hyphens, underscores, and periods.
# (https://community.atlassian.com/t5/Answers-Developer-Questions/stash-repository-names/qaq-p/499054)
#
# Bitbucket Server starts personal project names with a tilde.
VALID_BITBUCKET_PROJECT_CHARS = /\A~?[\w\-\.\s]+\z/
VALID_BITBUCKET_CHARS = /\A[\w\-\.\s]+\z/
def new; end
def create
repo = client.repo(@project_key, @repo_slug)
unless repo
return render json: { errors: _("Project %{project_repo} could not be found") % { project_repo: "#{@project_key}/#{@repo_slug}" } }, status: :unprocessable_entity
end
result = Import::BitbucketServerService.new(client, current_user, params.merge({ organization_id: Current.organization_id })).execute(credentials)
if result[:status] == :success
render json: ProjectSerializer.new.represent(result[:project], serializer: :import)
else
render json: { errors: result[:message] }, status: result[:http_status]
end
end
def configure
session[personal_access_token_key] = params[:personal_access_token]
session[bitbucket_server_username_key] = params[:bitbucket_server_username]
session[bitbucket_server_url_key] = params[:bitbucket_server_url]
redirect_to status_import_bitbucket_server_path(namespace_id: params[:namespace_id])
end
# We need to re-expose controller's internal method 'status' as action.
# rubocop:disable Lint/UselessMethodDefinition
def status
super
end
# rubocop:enable Lint/UselessMethodDefinition
protected
override :importable_repos
def importable_repos
bitbucket_repos.filter(&:valid?)
end
override :incompatible_repos
def incompatible_repos
bitbucket_repos.reject(&:valid?)
end
override :provider_name
def provider_name
:bitbucket_server
end
override :provider_url
def provider_url
session[bitbucket_server_url_key]
end
private
def client
@client ||= BitbucketServer::Client.new(credentials)
end
def bitbucket_repos
@bitbucket_repos ||= client.repos(page_offset: page_offset, limit: limit_per_page, filter: sanitized_filter_param).to_a
end
def normalize_import_params
project_key, repo_slug = params[:repo_id].split('/')
params[:bitbucket_server_project] = project_key
params[:bitbucket_server_repo] = repo_slug
end
def validate_import_params
@project_key = params[:bitbucket_server_project]
@repo_slug = params[:bitbucket_server_repo]
return render_validation_error('Missing project key') unless @project_key.present? && @repo_slug.present?
return render_validation_error('Missing repository slug') unless @repo_slug.present?
return render_validation_error('Invalid project key') unless VALID_BITBUCKET_PROJECT_CHARS.match?(@project_key)
render_validation_error('Invalid repository slug') unless VALID_BITBUCKET_CHARS.match?(@repo_slug)
end
def render_validation_error(message)
render json: { errors: message }, status: :unprocessable_entity
end
def bitbucket_auth
unless session[bitbucket_server_url_key].present? &&
session[bitbucket_server_username_key].present? &&
session[personal_access_token_key].present?
redirect_to new_import_bitbucket_server_path(namespace_id: params[:namespace_id])
end
end
def verify_bitbucket_server_import_enabled
render_404 unless bitbucket_server_import_enabled?
end
def bitbucket_server_url_key
:bitbucket_server_url
end
def bitbucket_server_username_key
:bitbucket_server_username
end
def personal_access_token_key
:bitbucket_server_personal_access_token
end
def clear_session_data
session[bitbucket_server_url_key] = nil
session[bitbucket_server_username_key] = nil
session[personal_access_token_key] = nil
end
def credentials
{
base_uri: session[bitbucket_server_url_key],
user: session[bitbucket_server_username_key],
password: session[personal_access_token_key]
}
end
def page_offset
[0, params[:page].to_i].max
end
def limit_per_page
BitbucketServer::Paginator::PAGE_LENGTH
end
def bitbucket_connection_error(error)
flash[:alert] = _("Unable to connect to server: %{error}") % { error: error }
clear_session_data
respond_to do |format|
format.json do
render json: {
error: {
message: _("Unable to connect to server: %{error}") % { error: error },
redirect: new_import_bitbucket_server_path
}
}, status: :unprocessable_entity
end
end
end
end
|