github_controller.rb 4.83 KB
Newer Older
1 2
# frozen_string_literal: true

3
class Import::GithubController < Import::BaseController
4 5
  include ImportHelper

6
  before_action :verify_import_enabled
7 8
  before_action :provider_auth, only: [:status, :realtime_changes, :create]
  before_action :expire_etag_cache, only: [:status, :create]
Valery Sizov's avatar
Valery Sizov committed
9

10
  rescue_from Octokit::Unauthorized, with: :provider_unauthorized
11 12

  def new
13
    if github_import_configured? && logged_in_with_provider?
14
      go_to_provider_for_permissions
15
    elsif session[access_token_key]
16
      redirect_to status_import_url
17 18 19
    end
  end

Valery Sizov's avatar
Valery Sizov committed
20
  def callback
21
    session[access_token_key] = client.get_token(params[:code])
22
    redirect_to status_import_url
Valery Sizov's avatar
Valery Sizov committed
23 24
  end

25
  def personal_access_token
26
    session[access_token_key] = params[:personal_access_token]&.strip
27
    redirect_to status_import_url
28 29
  end

Valery Sizov's avatar
Valery Sizov committed
30
  def status
31 32 33 34 35 36 37 38 39 40 41 42
    # Request repos to display error page if provider token is invalid
    # Improving in https://gitlab.com/gitlab-org/gitlab-ce/issues/55585
    client_repos

    respond_to do |format|
      format.json do
        render json: { imported_projects: serialized_imported_projects,
                       provider_repos: serialized_provider_repos,
                       namespaces: serialized_namespaces }
      end
      format.html
    end
43 44
  end

Valery Sizov's avatar
Valery Sizov committed
45
  def create
Ben's avatar
Ben committed
46 47 48
    result = Import::GithubService.new(client, current_user, import_params).execute(access_params, provider)

    if result[:status] == :success
49
      render json: serialized_imported_projects(result[:project])
50
    else
Ben's avatar
Ben committed
51
      render json: { errors: result[:message] }, status: result[:http_status]
52
    end
Valery Sizov's avatar
Valery Sizov committed
53 54
  end

55 56 57 58 59 60
  def realtime_changes
    Gitlab::PollingInterval.set_header(response, interval: 3_000)

    render json: find_jobs(provider)
  end

Valery Sizov's avatar
Valery Sizov committed
61 62
  private

Ben's avatar
Ben committed
63
  def import_params
64 65 66 67 68
    params.permit(permitted_import_params)
  end

  def permitted_import_params
    [:repo_id, :new_name, :target_namespace]
Ben's avatar
Ben committed
69 70
  end

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
  def serialized_imported_projects(projects = already_added_projects)
    ProjectSerializer.new.represent(projects, serializer: :import, provider_url: provider_url)
  end

  def serialized_provider_repos
    repos = client_repos.reject { |repo| already_added_project_names.include? repo.full_name }
    ProviderRepoSerializer.new(current_user: current_user).represent(repos, provider: provider, provider_url: provider_url)
  end

  def serialized_namespaces
    NamespaceSerializer.new.represent(namespaces)
  end

  def already_added_projects
    @already_added_projects ||= find_already_added_projects(provider)
  end

  def already_added_project_names
    @already_added_projects_names ||= already_added_projects.pluck(:import_source) # rubocop:disable CodeReuse/ActiveRecord
  end

  def namespaces
    current_user.manageable_groups_with_routes
  end

  def expire_etag_cache
    Gitlab::EtagCaching::Store.new.tap do |store|
      store.touch(realtime_changes_path)
    end
  end

Valery Sizov's avatar
Valery Sizov committed
102
  def client
103
    @client ||= Gitlab::LegacyGithubImport::Client.new(session[access_token_key], client_options)
Valery Sizov's avatar
Valery Sizov committed
104 105
  end

106 107 108 109
  def client_repos
    @client_repos ||= client.repos
  end

110 111
  def verify_import_enabled
    render_404 unless import_enabled?
112 113
  end

114 115 116 117 118
  def go_to_provider_for_permissions
    redirect_to client.authorize_url(callback_import_url)
  end

  def import_enabled?
119
    __send__("#{provider}_import_enabled?") # rubocop:disable GitlabSecurity/PublicSend
Valery Sizov's avatar
Valery Sizov committed
120 121
  end

122 123 124 125
  def realtime_changes_path
    public_send("realtime_changes_import_#{provider}_path", format: :json) # rubocop:disable GitlabSecurity/PublicSend
  end

126
  def new_import_url
127
    public_send("new_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
Valery Sizov's avatar
Valery Sizov committed
128 129
  end

130
  def status_import_url
131
    public_send("status_import_#{provider}_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
Valery Sizov's avatar
Valery Sizov committed
132
  end
133

134
  def callback_import_url
135
    public_send("users_import_#{provider}_callback_url", extra_import_params) # rubocop:disable GitlabSecurity/PublicSend
136 137 138
  end

  def provider_unauthorized
139
    session[access_token_key] = nil
140
    redirect_to new_import_url,
141
      alert: "Access denied to your #{Gitlab::ImportSources.title(provider.to_s)} account."
142
  end
143

144 145 146 147
  def access_token_key
    :"#{provider}_access_token"
  end

148
  def access_params
149
    { github_access_token: session[access_token_key] }
150 151
  end

152
  # The following methods are overridden in subclasses
153 154 155 156
  def provider
    :github
  end

157 158 159 160 161 162 163 164
  def provider_url
    strong_memoize(:provider_url) do
      provider = Gitlab::Auth::OAuth::Provider.config_for('github')

      provider&.dig('url').presence || 'https://github.com'
    end
  end

165
  # rubocop: disable CodeReuse/ActiveRecord
166 167 168
  def logged_in_with_provider?
    current_user.identities.exists?(provider: provider)
  end
169
  # rubocop: enable CodeReuse/ActiveRecord
170 171

  def provider_auth
172
    if session[access_token_key].blank?
173 174 175 176 177 178
      go_to_provider_for_permissions
    end
  end

  def client_options
    {}
179
  end
180 181 182 183

  def extra_import_params
    {}
  end
Valery Sizov's avatar
Valery Sizov committed
184
end