diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-06 21:08:22 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-12-06 21:08:22 +0300 |
commit | 5a73318262aab6ab952f2b7205b3674ea1f20053 (patch) | |
tree | e53191adbc529ce23ca08a73e1235c7b6fb6ced5 /lib/gitlab/github_gists_import | |
parent | 552877c4d1c535f529be13862692a8fe826a72a2 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'lib/gitlab/github_gists_import')
-rw-r--r-- | lib/gitlab/github_gists_import/importer/gist_importer.rb | 84 | ||||
-rw-r--r-- | lib/gitlab/github_gists_import/representation/gist.rb | 71 |
2 files changed, 155 insertions, 0 deletions
diff --git a/lib/gitlab/github_gists_import/importer/gist_importer.rb b/lib/gitlab/github_gists_import/importer/gist_importer.rb new file mode 100644 index 00000000000..a5e87d3cf7d --- /dev/null +++ b/lib/gitlab/github_gists_import/importer/gist_importer.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +module Gitlab + module GithubGistsImport + module Importer + class GistImporter + attr_reader :gist, :user + + FileCountLimitError = Class.new(StandardError) + + # gist - An instance of `Gitlab::GithubGistsImport::Representation::Gist`. + def initialize(gist, user_id) + @gist = gist + @user = User.find(user_id) + end + + def execute + snippet = build_snippet + import_repository(snippet) if snippet.save! + + return ServiceResponse.success unless max_snippet_files_count_exceeded?(snippet) + + fail_and_track(snippet) + end + + private + + def build_snippet + attrs = { + title: gist.truncated_title, + visibility_level: gist.visibility_level, + content: gist.first_file[:file_content], + file_name: gist.first_file[:file_name], + author: user, + created_at: gist.created_at, + updated_at: gist.updated_at + } + + PersonalSnippet.new(attrs) + end + + def import_repository(snippet) + resolved_address = get_resolved_address + + snippet.create_repository + snippet.repository.fetch_as_mirror(gist.git_pull_url, forced: true, resolved_address: resolved_address) + rescue StandardError + remove_snippet_and_repository(snippet) + + raise + end + + def get_resolved_address + validated_pull_url, host = Gitlab::UrlBlocker.validate!(gist.git_pull_url, + schemes: Project::VALID_IMPORT_PROTOCOLS, + ports: Project::VALID_IMPORT_PORTS, + allow_localhost: allow_local_requests?, + allow_local_network: allow_local_requests?) + + host.present? ? validated_pull_url.host.to_s : '' + end + + def max_snippet_files_count_exceeded?(snippet) + snippet.all_files.size > Snippet.max_file_limit + end + + def remove_snippet_and_repository(snippet) + snippet.repository.remove if snippet.repository_exists? + snippet.destroy + end + + def allow_local_requests? + Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services? + end + + def fail_and_track(snippet) + remove_snippet_and_repository(snippet) + + ServiceResponse.error(message: 'Snippet max file count exceeded').track_exception(as: FileCountLimitError) + end + end + end + end +end diff --git a/lib/gitlab/github_gists_import/representation/gist.rb b/lib/gitlab/github_gists_import/representation/gist.rb new file mode 100644 index 00000000000..0d309a98f38 --- /dev/null +++ b/lib/gitlab/github_gists_import/representation/gist.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +module Gitlab + module GithubGistsImport + module Representation + class Gist + include Gitlab::GithubImport::Representation::ToHash + include Gitlab::GithubImport::Representation::ExposeAttribute + + attr_reader :attributes + + expose_attribute :id, :description, :is_public, :created_at, :updated_at, :files, :git_pull_url + + # Builds a gist from a GitHub API response. + # + # gist - An instance of `Hash` containing the gist + # details. + def self.from_api_response(gist, additional_data = {}) + hash = { + id: gist[:id], + description: gist[:description], + is_public: gist[:public], + files: gist[:files], + git_pull_url: gist[:git_pull_url], + created_at: gist[:created_at], + updated_at: gist[:updated_at] + } + + new(hash) + end + + # Builds a new gist using a Hash that was built from a JSON payload. + def self.from_json_hash(raw_hash) + new(Gitlab::GithubImport::Representation.symbolize_hash(raw_hash)) + end + + # attributes - A hash containing the raw gist details. The keys of this + # Hash (and any nested hashes) must be symbols. + def initialize(attributes) + @attributes = attributes + end + + # Gist description can be an empty string, so we returning nil to use first file + # name as a title in such case on snippet creation + # Gist description has a limit of 256, while the snippet's title can be up to 255 + def truncated_title + title = description.presence || first_file[:file_name] + + title.truncate(255) + end + + def visibility_level + is_public ? Gitlab::VisibilityLevel::PUBLIC : Gitlab::VisibilityLevel::PRIVATE + end + + def first_file + _key, value = files.first + + { + file_name: value[:filename], + file_content: Gitlab::HTTP.try_get(value[:raw_url])&.body + } + end + + def github_identifiers + { id: id } + end + end + end + end +end |