diff options
Diffstat (limited to 'lib/api/helpers')
-rw-r--r-- | lib/api/helpers/common_helpers.rb | 20 | ||||
-rw-r--r-- | lib/api/helpers/internal_helpers.rb | 4 | ||||
-rw-r--r-- | lib/api/helpers/merge_requests_helpers.rb | 40 | ||||
-rw-r--r-- | lib/api/helpers/packages/basic_auth_helpers.rb | 57 | ||||
-rw-r--r-- | lib/api/helpers/packages/conan/api_helpers.rb | 225 | ||||
-rw-r--r-- | lib/api/helpers/packages/dependency_proxy_helpers.rb | 36 | ||||
-rw-r--r-- | lib/api/helpers/packages_helpers.rb | 52 | ||||
-rw-r--r-- | lib/api/helpers/packages_manager_clients_helpers.rb | 63 | ||||
-rw-r--r-- | lib/api/helpers/projects_helpers.rb | 6 | ||||
-rw-r--r-- | lib/api/helpers/runner.rb | 7 | ||||
-rw-r--r-- | lib/api/helpers/services_helpers.rb | 33 | ||||
-rw-r--r-- | lib/api/helpers/snippets_helpers.rb | 26 | ||||
-rw-r--r-- | lib/api/helpers/users_helpers.rb | 7 | ||||
-rw-r--r-- | lib/api/helpers/wikis_helpers.rb | 35 |
14 files changed, 562 insertions, 49 deletions
diff --git a/lib/api/helpers/common_helpers.rb b/lib/api/helpers/common_helpers.rb index 32a15381f27..a44fd4b0a5b 100644 --- a/lib/api/helpers/common_helpers.rb +++ b/lib/api/helpers/common_helpers.rb @@ -12,6 +12,26 @@ module API end end end + + # Grape v1.3.3 no longer automatically coerces an Array + # type to an empty array if the value is nil. + def coerce_nil_params_to_array! + keys_to_coerce = params_with_array_types + + params.each do |key, val| + params[key] = Array(val) if val.nil? && keys_to_coerce.include?(key) + end + end + + def params_with_array_types + options[:route_options][:params].map do |key, val| + param_type = val[:type] + # Search for parameters with Array types (e.g. "[String]", "[Integer]", etc.) + if param_type =~ %r(\[\w*\]) + key + end + end.compact.to_set + end end end end diff --git a/lib/api/helpers/internal_helpers.rb b/lib/api/helpers/internal_helpers.rb index b05e82a541d..b69930b447c 100644 --- a/lib/api/helpers/internal_helpers.rb +++ b/lib/api/helpers/internal_helpers.rb @@ -118,8 +118,8 @@ module API { repository: repository.gitaly_repository, - address: Gitlab::GitalyClient.address(container.repository_storage), - token: Gitlab::GitalyClient.token(container.repository_storage), + address: Gitlab::GitalyClient.address(repository.shard), + token: Gitlab::GitalyClient.token(repository.shard), features: Feature::Gitaly.server_feature_flags } end diff --git a/lib/api/helpers/merge_requests_helpers.rb b/lib/api/helpers/merge_requests_helpers.rb index 9dab2a88f0b..4d5350498a7 100644 --- a/lib/api/helpers/merge_requests_helpers.rb +++ b/lib/api/helpers/merge_requests_helpers.rb @@ -5,7 +5,30 @@ module API module MergeRequestsHelpers extend Grape::API::Helpers + params :merge_requests_negatable_params do + optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID' + optional :author_username, type: String, desc: 'Return merge requests which are authored by the user with the given username' + mutually_exclusive :author_id, :author_username + + optional :assignee_id, + types: [Integer, String], + integer_none_any: true, + desc: 'Return merge requests which are assigned to the user with the given ID' + optional :assignee_username, type: Array[String], check_assignees_count: true, + coerce_with: Validations::Validators::CheckAssigneesCount.coerce, + desc: 'Return merge requests which are assigned to the user with the given username' + mutually_exclusive :assignee_id, :assignee_username + + optional :labels, + type: Array[String], + coerce_with: Validations::Types::CommaSeparatedToArray.coerce, + desc: 'Comma-separated list of label names' + optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' + optional :my_reaction_emoji, type: String, desc: 'Return issues reacted by the authenticated user by the given emoji' + end + params :merge_requests_base_params do + use :merge_requests_negatable_params optional :state, type: String, values: %w[opened closed locked merged all], @@ -21,11 +44,6 @@ module API values: %w[asc desc], default: 'desc', desc: 'Return merge requests sorted in `asc` or `desc` order.' - optional :milestone, type: String, desc: 'Return merge requests for a specific milestone' - optional :labels, - type: Array[String], - coerce_with: Validations::Types::LabelsList.coerce, - desc: 'Comma-separated list of label names' optional :with_labels_details, type: Boolean, desc: 'Return titles of labels and other details', default: false optional :with_merge_status_recheck, type: Boolean, desc: 'Request that stale merge statuses be rechecked asynchronously', default: false optional :created_after, type: DateTime, desc: 'Return merge requests created after the specified time' @@ -37,19 +55,10 @@ module API values: %w[simple], desc: 'If simple, returns the `iid`, URL, title, description, and basic state of merge request' - optional :author_id, type: Integer, desc: 'Return merge requests which are authored by the user with the given ID' - optional :author_username, type: String, desc: 'Return merge requests which are authored by the user with the given username' - mutually_exclusive :author_id, :author_username - - optional :assignee_id, - types: [Integer, String], - integer_none_any: true, - desc: 'Return merge requests which are assigned to the user with the given ID' optional :scope, type: String, values: %w[created-by-me assigned-to-me created_by_me assigned_to_me all], desc: 'Return merge requests for the given scope: `created_by_me`, `assigned_to_me` or `all`' - optional :my_reaction_emoji, type: String, desc: 'Return issues reacted by the authenticated user by the given emoji' optional :source_branch, type: String, desc: 'Return merge requests with the given source branch' optional :source_project_id, type: Integer, desc: 'Return merge requests with the given source project id' optional :target_branch, type: String, desc: 'Return merge requests with the given target branch' @@ -58,6 +67,9 @@ module API desc: 'Search merge requests for text present in the title, description, or any combination of these' optional :in, type: String, desc: '`title`, `description`, or a string joining them with comma' optional :wip, type: String, values: %w[yes no], desc: 'Search merge requests for WIP in the title' + optional :not, type: Hash, desc: 'Parameters to negate' do + use :merge_requests_negatable_params + end end params :optional_scope_param do diff --git a/lib/api/helpers/packages/basic_auth_helpers.rb b/lib/api/helpers/packages/basic_auth_helpers.rb new file mode 100644 index 00000000000..835b5f4614c --- /dev/null +++ b/lib/api/helpers/packages/basic_auth_helpers.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +module API + module Helpers + module Packages + module BasicAuthHelpers + module Constants + AUTHENTICATE_REALM_HEADER = 'Www-Authenticate: Basic realm' + AUTHENTICATE_REALM_NAME = 'GitLab Packages Registry' + end + + include Constants + + def find_personal_access_token + find_personal_access_token_from_http_basic_auth + end + + def unauthorized_user_project + @unauthorized_user_project ||= find_project(params[:id]) + end + + def unauthorized_user_project! + unauthorized_user_project || not_found! + end + + def authorized_user_project + @authorized_user_project ||= authorized_project_find! + end + + def authorized_project_find! + project = unauthorized_user_project + + unless project && can?(current_user, :read_project, project) + return unauthorized_or! { not_found! } + end + + project + end + + def authorize!(action, subject = :global, reason = nil) + return if can?(current_user, action, subject) + + unauthorized_or! { forbidden!(reason) } + end + + def unauthorized_or! + current_user ? yield : unauthorized_with_header! + end + + def unauthorized_with_header! + header(AUTHENTICATE_REALM_HEADER, AUTHENTICATE_REALM_NAME) + unauthorized! + end + end + end + end +end diff --git a/lib/api/helpers/packages/conan/api_helpers.rb b/lib/api/helpers/packages/conan/api_helpers.rb new file mode 100644 index 00000000000..30e690a5a1d --- /dev/null +++ b/lib/api/helpers/packages/conan/api_helpers.rb @@ -0,0 +1,225 @@ +# frozen_string_literal: true + +module API + module Helpers + module Packages + module Conan + module ApiHelpers + def present_download_urls(entity) + authorize!(:read_package, project) + + presenter = ::Packages::Conan::PackagePresenter.new( + recipe, + current_user, + project, + conan_package_reference: params[:conan_package_reference] + ) + + render_api_error!("No recipe manifest found", 404) if yield(presenter).empty? + + present presenter, with: entity + end + + def present_package_download_urls + present_download_urls(::API::Entities::ConanPackage::ConanPackageManifest, &:package_urls) + end + + def present_recipe_download_urls + present_download_urls(::API::Entities::ConanPackage::ConanRecipeManifest, &:recipe_urls) + end + + def recipe_upload_urls(file_names) + { upload_urls: Hash[ + file_names.collect do |file_name| + [file_name, recipe_file_upload_url(file_name)] + end + ] } + end + + def package_upload_urls(file_names) + { upload_urls: Hash[ + file_names.collect do |file_name| + [file_name, package_file_upload_url(file_name)] + end + ] } + end + + def package_file_upload_url(file_name) + expose_url( + api_v4_packages_conan_v1_files_package_path( + package_name: params[:package_name], + package_version: params[:package_version], + package_username: params[:package_username], + package_channel: params[:package_channel], + recipe_revision: '0', + conan_package_reference: params[:conan_package_reference], + package_revision: '0', + file_name: file_name + ) + ) + end + + def recipe_file_upload_url(file_name) + expose_url( + api_v4_packages_conan_v1_files_export_path( + package_name: params[:package_name], + package_version: params[:package_version], + package_username: params[:package_username], + package_channel: params[:package_channel], + recipe_revision: '0', + file_name: file_name + ) + ) + end + + def recipe + "%{package_name}/%{package_version}@%{package_username}/%{package_channel}" % params.symbolize_keys + end + + def project + strong_memoize(:project) do + full_path = ::Packages::Conan::Metadatum.full_path_from(package_username: params[:package_username]) + Project.find_by_full_path(full_path) + end + end + + def package + strong_memoize(:package) do + project.packages + .with_name(params[:package_name]) + .with_version(params[:package_version]) + .with_conan_channel(params[:package_channel]) + .order_created + .last + end + end + + def token + strong_memoize(:token) do + token = nil + token = ::Gitlab::ConanToken.from_personal_access_token(access_token) if access_token + token = ::Gitlab::ConanToken.from_deploy_token(deploy_token_from_request) if deploy_token_from_request + token = ::Gitlab::ConanToken.from_job(find_job_from_token) if find_job_from_token + token + end + end + + def download_package_file(file_type) + authorize!(:read_package, project) + + package_file = ::Packages::Conan::PackageFileFinder + .new( + package, + params[:file_name].to_s, + conan_file_type: file_type, + conan_package_reference: params[:conan_package_reference] + ).execute! + + track_event('pull_package') if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY + + present_carrierwave_file!(package_file.file) + end + + def find_or_create_package + package || ::Packages::Conan::CreatePackageService.new(project, current_user, params).execute + end + + def track_push_package_event + if params[:file_name] == ::Packages::Conan::FileMetadatum::PACKAGE_BINARY && params['file.size'] > 0 + track_event('push_package') + end + end + + def create_package_file_with_type(file_type, current_package) + unless params['file.size'] == 0 + # conan sends two upload requests, the first has no file, so we skip record creation if file.size == 0 + ::Packages::Conan::CreatePackageFileService.new(current_package, uploaded_package_file, params.merge(conan_file_type: file_type)).execute + end + end + + def upload_package_file(file_type) + authorize_upload!(project) + + current_package = find_or_create_package + + track_push_package_event + + create_package_file_with_type(file_type, current_package) + rescue ObjectStorage::RemoteStoreError => e + Gitlab::ErrorTracking.track_exception(e, file_name: params[:file_name], project_id: project.id) + + forbidden! + end + + def find_personal_access_token + personal_access_token = find_personal_access_token_from_conan_jwt || + find_personal_access_token_from_http_basic_auth + + personal_access_token + end + + def find_user_from_job_token + return unless route_authentication_setting[:job_token_allowed] + + job = find_job_from_token || raise(::Gitlab::Auth::UnauthorizedError) + + job.user + end + + def deploy_token_from_request + find_deploy_token_from_conan_jwt || find_deploy_token_from_http_basic_auth + end + + def find_job_from_token + find_job_from_conan_jwt || find_job_from_http_basic_auth + end + + # We need to override this one because it + # looks into Bearer authorization header + def find_oauth_access_token + end + + def find_personal_access_token_from_conan_jwt + token = decode_oauth_token_from_jwt + + return unless token + + PersonalAccessToken.find_by_id_and_user_id(token.access_token_id, token.user_id) + end + + def find_deploy_token_from_conan_jwt + token = decode_oauth_token_from_jwt + + return unless token + + deploy_token = DeployToken.active.find_by_token(token.access_token_id.to_s) + # note: uesr_id is not a user record id, but is the attribute set on ConanToken + return if token.user_id != deploy_token&.username + + deploy_token + end + + def find_job_from_conan_jwt + token = decode_oauth_token_from_jwt + + return unless token + + ::Ci::Build.find_by_token(token.access_token_id.to_s) + end + + def decode_oauth_token_from_jwt + jwt = Doorkeeper::OAuth::Token.from_bearer_authorization(current_request) + + return unless jwt + + token = ::Gitlab::ConanToken.decode(jwt) + + return unless token && token.access_token_id && token.user_id + + token + end + end + end + end + end +end diff --git a/lib/api/helpers/packages/dependency_proxy_helpers.rb b/lib/api/helpers/packages/dependency_proxy_helpers.rb new file mode 100644 index 00000000000..254af7690a2 --- /dev/null +++ b/lib/api/helpers/packages/dependency_proxy_helpers.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +module API + module Helpers + module Packages + module DependencyProxyHelpers + REGISTRY_BASE_URLS = { + npm: 'https://registry.npmjs.org/' + }.freeze + + def redirect_registry_request(forward_to_registry, package_type, options) + if forward_to_registry && redirect_registry_request_available? + redirect(registry_url(package_type, options)) + else + yield + end + end + + def registry_url(package_type, options) + base_url = REGISTRY_BASE_URLS[package_type] + + raise ArgumentError, "Can't build registry_url for package_type #{package_type}" unless base_url + + case package_type + when :npm + "#{base_url}#{options[:package_name]}" + end + end + + def redirect_registry_request_available? + ::Gitlab::CurrentSettings.current_application_settings.npm_package_requests_forwarding + end + end + end + end +end diff --git a/lib/api/helpers/packages_helpers.rb b/lib/api/helpers/packages_helpers.rb new file mode 100644 index 00000000000..c6037d52de9 --- /dev/null +++ b/lib/api/helpers/packages_helpers.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module API + module Helpers + module PackagesHelpers + MAX_PACKAGE_FILE_SIZE = 50.megabytes.freeze + + def require_packages_enabled! + not_found! unless ::Gitlab.config.packages.enabled + end + + def require_dependency_proxy_enabled! + not_found! unless ::Gitlab.config.dependency_proxy.enabled + end + + def authorize_read_package!(subject = user_project) + authorize!(:read_package, subject) + end + + def authorize_create_package!(subject = user_project) + authorize!(:create_package, subject) + end + + def authorize_destroy_package!(subject = user_project) + authorize!(:destroy_package, subject) + end + + def authorize_packages_access!(subject = user_project) + require_packages_enabled! + authorize_read_package!(subject) + end + + def authorize_workhorse!(subject: user_project, has_length: true, maximum_size: MAX_PACKAGE_FILE_SIZE) + authorize_upload!(subject) + + Gitlab::Workhorse.verify_api_request!(headers) + + status 200 + content_type Gitlab::Workhorse::INTERNAL_API_CONTENT_TYPE + + params = { has_length: has_length } + params[:maximum_size] = maximum_size unless has_length + ::Packages::PackageFileUploader.workhorse_authorize(params) + end + + def authorize_upload!(subject = user_project) + authorize_create_package!(subject) + require_gitlab_workhorse! + end + end + end +end diff --git a/lib/api/helpers/packages_manager_clients_helpers.rb b/lib/api/helpers/packages_manager_clients_helpers.rb new file mode 100644 index 00000000000..7b5d0dd708d --- /dev/null +++ b/lib/api/helpers/packages_manager_clients_helpers.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +module API + module Helpers + module PackagesManagerClientsHelpers + extend Grape::API::Helpers + include ::API::Helpers::PackagesHelpers + + params :workhorse_upload_params do + optional 'file.path', type: String, desc: 'Path to locally stored body (generated by Workhorse)' + optional 'file.name', type: String, desc: 'Real filename as send in Content-Disposition (generated by Workhorse)' + optional 'file.type', type: String, desc: 'Real content type as send in Content-Type (generated by Workhorse)' + optional 'file.size', type: Integer, desc: 'Real size of file (generated by Workhorse)' + optional 'file.md5', type: String, desc: 'MD5 checksum of the file (generated by Workhorse)' + optional 'file.sha1', type: String, desc: 'SHA1 checksum of the file (generated by Workhorse)' + optional 'file.sha256', type: String, desc: 'SHA256 checksum of the file (generated by Workhorse)' + end + + def find_personal_access_token_from_http_basic_auth + return unless headers + + token = decode_token + + return unless token + + PersonalAccessToken.find_by_token(token) + end + + def find_job_from_http_basic_auth + return unless headers + + token = decode_token + + return unless token + + ::Ci::Build.find_by_token(token) + end + + def find_deploy_token_from_http_basic_auth + return unless headers + + token = decode_token + + return unless token + + DeployToken.active.find_by_token(token) + end + + def uploaded_package_file(param_name = :file) + uploaded_file = UploadedFile.from_params(params, param_name, ::Packages::PackageFileUploader.workhorse_local_upload_path) + bad_request!('Missing package file!') unless uploaded_file + uploaded_file + end + + private + + def decode_token + encoded_credentials = headers['Authorization'].to_s.split('Basic ', 2).second + Base64.decode64(encoded_credentials || '').split(':', 2).second + end + end + end +end diff --git a/lib/api/helpers/projects_helpers.rb b/lib/api/helpers/projects_helpers.rb index 8a115d42929..76e5bb95c4d 100644 --- a/lib/api/helpers/projects_helpers.rb +++ b/lib/api/helpers/projects_helpers.rb @@ -6,6 +6,8 @@ module API extend ActiveSupport::Concern extend Grape::API::Helpers + STATISTICS_SORT_PARAMS = %w[storage_size repository_size wiki_size].freeze + params :optional_project_params_ce do optional :description, type: String, desc: 'The description of the project' optional :build_git_strategy, type: String, values: %w(fetch clone), desc: 'The Git strategy. Defaults to `fetch`' @@ -13,6 +15,7 @@ module API optional :auto_cancel_pending_pipelines, type: String, values: %w(disabled enabled), desc: 'Auto-cancel pending pipelines' optional :build_coverage_regex, type: String, desc: 'Test coverage parsing' optional :ci_config_path, type: String, desc: 'The path to CI config file. Defaults to `.gitlab-ci.yml`' + optional :service_desk_enabled, type: Boolean, desc: 'Disable or enable the service desk' # TODO: remove in API v5, replaced by *_access_level optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled' @@ -46,7 +49,7 @@ module API optional :only_allow_merge_if_pipeline_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed' optional :allow_merge_on_skipped_pipeline, type: Boolean, desc: 'Allow to merge if pipeline is skipped' optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved' - optional :tag_list, type: Array[String], desc: 'The list of tags for a project' + optional :tag_list, type: Array[String], coerce_with: ::API::Validations::Types::CommaSeparatedToArray.coerce, desc: 'The list of tags for a project' # TODO: remove rubocop disable - https://gitlab.com/gitlab-org/gitlab/issues/14960 optional :avatar, type: File, desc: 'Avatar image for project' # rubocop:disable Scalability/FileUploads optional :printing_merge_request_link_enabled, type: Boolean, desc: 'Show link to create/view merge request when pushing from the command line' @@ -134,6 +137,7 @@ module API :suggestion_commit_message, :repository_storage, :compliance_framework_setting, + :service_desk_enabled, # TODO: remove in API v5, replaced by *_access_level :issues_enabled, diff --git a/lib/api/helpers/runner.rb b/lib/api/helpers/runner.rb index 293d7ed9a6a..34a2fb09875 100644 --- a/lib/api/helpers/runner.rb +++ b/lib/api/helpers/runner.rb @@ -60,7 +60,7 @@ module API def current_job strong_memoize(:current_job) do - Ci::Build.find_by_id(params[:id]) + ::Ci::Build.find_by_id(params[:id]) end end @@ -69,11 +69,6 @@ module API token && job.valid_token?(token) end - def max_artifacts_size(job) - max_size = job.project.closest_setting(:max_artifacts_size) - max_size.megabytes.to_i - end - def job_forbidden!(job, reason) header 'Job-Status', job.status forbidden!(reason) diff --git a/lib/api/helpers/services_helpers.rb b/lib/api/helpers/services_helpers.rb index 3d6039cacaa..d4870b96575 100644 --- a/lib/api/helpers/services_helpers.rb +++ b/lib/api/helpers/services_helpers.rb @@ -234,18 +234,6 @@ module API name: :project_url, type: String, desc: 'Project URL' - }, - { - required: false, - name: :description, - type: String, - desc: 'Description' - }, - { - required: false, - name: :title, - type: String, - desc: 'Title' } ], 'buildkite' => [ @@ -288,6 +276,14 @@ module API desc: 'Campfire room' } ], + 'confluence' => [ + { + required: true, + name: :confluence_url, + type: String, + desc: 'The URL of the Confluence Cloud Workspace hosted on atlassian.net' + } + ], 'custom-issue-tracker' => [ { required: true, @@ -306,18 +302,6 @@ module API name: :project_url, type: String, desc: 'Project URL' - }, - { - required: false, - name: :description, - type: String, - desc: 'Description' - }, - { - required: false, - name: :title, - type: String, - desc: 'Title' } ], 'discord' => [ @@ -757,6 +741,7 @@ module API ::BambooService, ::BugzillaService, ::BuildkiteService, + ::ConfluenceService, ::CampfireService, ::CustomIssueTrackerService, ::DiscordService, diff --git a/lib/api/helpers/snippets_helpers.rb b/lib/api/helpers/snippets_helpers.rb index 20aeca6a9d3..f95d066bd7c 100644 --- a/lib/api/helpers/snippets_helpers.rb +++ b/lib/api/helpers/snippets_helpers.rb @@ -3,15 +3,37 @@ module API module Helpers module SnippetsHelpers + extend Grape::API::Helpers + + params :raw_file_params do + requires :file_path, type: String, file_path: true, desc: 'The url encoded path to the file, e.g. lib%2Fclass%2Erb' + requires :ref, type: String, desc: 'The name of branch, tag or commit' + end + def content_for(snippet) if snippet.empty_repo? + env['api.format'] = :txt + content_type 'text/plain' + header['Content-Disposition'] = 'attachment' + snippet.content else blob = snippet.blobs.first - blob.load_all_data! - blob.data + + send_git_blob(blob.repository, blob) end end + + def file_content_for(snippet) + repo = snippet.repository + commit = repo.commit(params[:ref]) + not_found!('Reference') unless commit + + blob = repo.blob_at(commit.sha, params[:file_path]) + not_found!('File') unless blob + + send_git_blob(repo, blob) + end end end end diff --git a/lib/api/helpers/users_helpers.rb b/lib/api/helpers/users_helpers.rb index 99eefc1cbb9..2d7b22e66b3 100644 --- a/lib/api/helpers/users_helpers.rb +++ b/lib/api/helpers/users_helpers.rb @@ -11,6 +11,13 @@ module API params :optional_index_params_ee do end + + def model_error_messages(model) + super.tap do |error_messages| + # Remapping errors from nested associations. + error_messages[:bio] = error_messages.delete(:"user_detail.bio") if error_messages.has_key?(:"user_detail.bio") + end + end end end end diff --git a/lib/api/helpers/wikis_helpers.rb b/lib/api/helpers/wikis_helpers.rb new file mode 100644 index 00000000000..49da1e317ab --- /dev/null +++ b/lib/api/helpers/wikis_helpers.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module API + module Helpers + module WikisHelpers + def self.wiki_resource_kinds + [:projects] + end + + def find_container(kind) + return user_project if kind == :projects + + raise "Unknown wiki container #{kind}" + end + + def wiki_page + Wiki.for_container(container, current_user).find_page(params[:slug]) || not_found!('Wiki Page') + end + + def commit_params(attrs) + base_params = { branch_name: attrs[:branch] } + file_details = case attrs[:file] + when Hash # legacy format: TODO remove when we drop support for non accelerated uploads + { file_name: attrs[:file][:filename], file_content: attrs[:file][:tempfile].read } + else + { file_name: attrs[:file].original_filename, file_content: attrs[:file].read } + end + + base_params.merge(file_details) + end + end + end +end + +API::Helpers::WikisHelpers.prepend_if_ee('EE::API::Helpers::WikisHelpers') |