Module: API::Helpers

Includes:
Caching, Pagination, PaginationStrategies, Gitlab::Utils
Defined in:
lib/api/helpers.rb,
lib/api/helpers/caching.rb,
lib/api/helpers/version.rb,
lib/api/helpers/pagination.rb,
lib/api/helpers/award_emoji.rb,
lib/api/helpers/presentable.rb,
lib/api/helpers/sse_helpers.rb,
lib/api/helpers/packages/npm.rb,
lib/api/helpers/rate_limiter.rb,
lib/api/helpers/label_helpers.rb,
lib/api/helpers/notes_helpers.rb,
lib/api/helpers/users_helpers.rb,
lib/api/helpers/wikis_helpers.rb,
lib/api/helpers/authentication.rb,
lib/api/helpers/badges_helpers.rb,
lib/api/helpers/common_helpers.rb,
lib/api/helpers/events_helpers.rb,
lib/api/helpers/groups_helpers.rb,
lib/api/helpers/issues_helpers.rb,
lib/api/helpers/search_helpers.rb,
lib/api/helpers/graphql_helpers.rb,
lib/api/helpers/headers_helpers.rb,
lib/api/helpers/members_helpers.rb,
lib/api/helpers/internal_helpers.rb,
lib/api/helpers/packages_helpers.rb,
lib/api/helpers/projects_helpers.rb,
lib/api/helpers/settings_helpers.rb,
lib/api/helpers/snippets_helpers.rb,
lib/api/helpers/custom_attributes.rb,
lib/api/helpers/variables_helpers.rb,
lib/api/helpers/discussions_helpers.rb,
lib/api/helpers/file_upload_helpers.rb,
lib/api/helpers/integrations_helpers.rb,
lib/api/helpers/pagination_strategies.rb,
lib/api/helpers/merge_requests_helpers.rb,
lib/api/helpers/performance_bar_helpers.rb,
lib/api/helpers/project_snapshots_helpers.rb,
lib/api/helpers/related_resources_helpers.rb,
lib/api/helpers/container_registry_helpers.rb,
lib/api/helpers/packages/conan/api_helpers.rb,
lib/api/helpers/protected_branches_helpers.rb,
lib/api/helpers/packages/basic_auth_helpers.rb,
lib/api/helpers/resource_label_events_helpers.rb,
lib/api/helpers/packages_manager_clients_helpers.rb,
lib/api/helpers/packages/dependency_proxy_helpers.rb

Defined Under Namespace

Modules: Authentication, AwardEmoji, BadgesHelpers, Caching, CommonHelpers, ContainerRegistryHelpers, CustomAttributes, DiscussionsHelpers, EventsHelpers, FileUploadHelpers, GraphqlHelpers, GroupsHelpers, HeadersHelpers, IntegrationsHelpers, InternalHelpers, IssuesHelpers, LabelHelpers, MembersHelpers, MergeRequestsHelpers, NotesHelpers, Packages, PackagesHelpers, PackagesManagerClientsHelpers, Pagination, PaginationStrategies, PerformanceBarHelpers, Presentable, ProjectSnapshotsHelpers, ProjectsHelpers, ProtectedBranchesHelpers, RateLimiter, RelatedResourcesHelpers, ResourceLabelEventsHelpers, SSEHelpers, SearchHelpers, SettingsHelpers, SnippetsHelpers, UsersHelpers, VariablesHelpers, WikisHelpers Classes: Version

Constant Summary collapse

SUDO_HEADER =
"HTTP_SUDO"
GITLAB_SHARED_SECRET_HEADER =
"Gitlab-Shared-Secret"
SUDO_PARAM =
:sudo
API_USER_ENV =
'gitlab.api.user'
API_EXCEPTION_ENV =
'gitlab.api.exception'
API_RESPONSE_STATUS_CODE =
'gitlab.api.response_status_code'

Constants included from Caching

Caching::DEFAULT_CACHE_OPTIONS, Caching::PAGINATION_HEADERS

Constants included from Gitlab::Cache::Helpers

Gitlab::Cache::Helpers::DEFAULT_EXPIRY

Instance Method Summary collapse

Methods included from PaginationStrategies

#paginate_with_strategies, #paginator

Methods included from Pagination

#paginate

Methods included from Caching

#cache_action, #cache_action_if, #cache_action_unless, #present_cached

Methods included from Gitlab::Cache::Helpers

#cache, #render_cached

Methods included from Gitlab::Utils

#add_url_parameters, #allowlisted?, #append_path, #boolean_to_yes_no, #bytes_to_megabytes, #check_allowed_absolute_path!, #check_allowed_absolute_path_and_path_traversal!, #check_path_traversal!, #decode_path, #deep_indifferent_access, #deep_symbolized_access, #ensure_array_from_string, #ensure_utf8_size, #force_utf8, #ms_to_round_sec, #multiple_key_invert, #nlbr, #parse_url, #remove_line_breaks, #removes_sensitive_data_from_url, #safe_downcase!, #slugify, #stable_sort_by, #string_to_ip_object, #to_boolean, #to_exclusive_sentence, #try_megabytes_to_bytes, #valid_brackets?, #which

Instance Method Details

#accepted!Object


473
474
475
# File 'lib/api/helpers.rb', line 473

def accepted!
  render_api_error!('202 Accepted', 202)
end

#attributes_for_keys(keys, custom_params = nil) ⇒ Object


368
369
370
371
372
373
374
375
376
377
378
# File 'lib/api/helpers.rb', line 368

def attributes_for_keys(keys, custom_params = nil)
  params_hash = custom_params || params
  attrs = {}
  keys.each do |key|
    if params_hash[key].present? || (params_hash.key?(key) && params_hash[key] == false)
      attrs[key] = params_hash[key]
    end
  end
  permitted_attrs = ActionController::Parameters.new(attrs).permit!
  permitted_attrs.to_h
end

#authenticate!Object


258
259
260
# File 'lib/api/helpers.rb', line 258

def authenticate!
  unauthorized! unless current_user
end

#authenticate_by_gitlab_shell_token!Object


266
267
268
269
270
271
272
273
# File 'lib/api/helpers.rb', line 266

def authenticate_by_gitlab_shell_token!
  input = params['secret_token']
  input ||= Base64.decode64(headers[GITLAB_SHARED_SECRET_HEADER]) if headers.key?(GITLAB_SHARED_SECRET_HEADER)

  input&.chomp!

  unauthorized! unless Devise.secure_compare(secret_token, input)
end

#authenticate_non_get!Object


262
263
264
# File 'lib/api/helpers.rb', line 262

def authenticate_non_get!
  authenticate! unless %w[GET HEAD].include?(route.request_method)
end

#authenticated_as_admin!Object


280
281
282
283
# File 'lib/api/helpers.rb', line 280

def authenticated_as_admin!
  authenticate!
  forbidden! unless current_user.admin?
end

#authenticated_with_can_read_all_resources!Object


275
276
277
278
# File 'lib/api/helpers.rb', line 275

def authenticated_with_can_read_all_resources!
  authenticate!
  forbidden! unless current_user.can_read_all_resources?
end

#authorize!(action, subject = :global, reason = nil) ⇒ Object


285
286
287
# File 'lib/api/helpers.rb', line 285

def authorize!(action, subject = :global, reason = nil)
  forbidden!(reason) unless can?(current_user, action, subject)
end

#authorize_admin_groupObject


301
302
303
# File 'lib/api/helpers.rb', line 301

def authorize_admin_group
  authorize! :admin_group, user_group
end

#authorize_admin_projectObject


297
298
299
# File 'lib/api/helpers.rb', line 297

def authorize_admin_project
  authorize! :admin_project, user_project
end

#authorize_admin_tagObject


293
294
295
# File 'lib/api/helpers.rb', line 293

def authorize_admin_tag
  authorize! :admin_tag, user_project
end

#authorize_destroy_artifacts!Object


317
318
319
# File 'lib/api/helpers.rb', line 317

def authorize_destroy_artifacts!
  authorize! :destroy_artifacts, user_project
end

#authorize_push_projectObject


289
290
291
# File 'lib/api/helpers.rb', line 289

def authorize_push_project
  authorize! :push_code, user_project
end

#authorize_read_build_trace!(build) ⇒ Object


309
310
311
# File 'lib/api/helpers.rb', line 309

def authorize_read_build_trace!(build)
  authorize! :read_build_trace, build
end

#authorize_read_builds!Object


305
306
307
# File 'lib/api/helpers.rb', line 305

def authorize_read_builds!
  authorize! :read_build, user_project
end

#authorize_read_job_artifacts!(build) ⇒ Object


313
314
315
# File 'lib/api/helpers.rb', line 313

def authorize_read_job_artifacts!(build)
  authorize! :read_job_artifacts, build
end

#authorize_update_builds!Object


321
322
323
# File 'lib/api/helpers.rb', line 321

def authorize_update_builds!
  authorize! :update_build, user_project
end

#authorized_project_scope?(project) ⇒ Boolean

Returns:

  • (Boolean)

143
144
145
146
147
148
149
# File 'lib/api/helpers.rb', line 143

def authorized_project_scope?(project)
  return true unless job_token_authentication?
  return true unless route_authentication_setting[:job_token_scope] == :project

  ::Feature.enabled?(:ci_job_token_scope, project) &&
    current_authenticated_job.project == project
end

#available_labels_for(label_parent, params = { include_ancestor_groups: true, only_group_labels: true }) ⇒ Object


103
104
105
106
107
108
109
110
111
112
# File 'lib/api/helpers.rb', line 103

def available_labels_for(label_parent, params = { include_ancestor_groups: true, only_group_labels: true })
  if label_parent.is_a?(Project)
    params.delete(:only_group_labels)
    params[:project_id] = label_parent.id
  else
    params[:group_id] = label_parent.id
  end

  LabelsFinder.new(current_user, params).execute
end

#bad_request!(reason = nil) ⇒ Object


410
411
412
413
414
# File 'lib/api/helpers.rb', line 410

def bad_request!(reason = nil)
  message = ['400 Bad request']
  message << "- #{reason}" if reason
  render_api_error!(message.join(' '), 400)
end

#bad_request_missing_attribute!(attribute) ⇒ Object


416
417
418
# File 'lib/api/helpers.rb', line 416

def bad_request_missing_attribute!(attribute)
  bad_request!("\"#{attribute}\" not given")
end

#can?(object, action, subject = :global) ⇒ Boolean

Returns:

  • (Boolean)

353
354
355
# File 'lib/api/helpers.rb', line 353

def can?(object, action, subject = :global)
  Ability.allowed?(object, action, subject)
end

#check_group_access(group) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


173
174
175
176
177
178
# File 'lib/api/helpers.rb', line 173

def check_group_access(group)
  return group if can?(current_user, :read_group, group)
  return unauthorized! if authenticate_non_public?

  not_found!('Group')
end

#check_namespace_access(namespace) ⇒ Object


180
181
182
183
184
# File 'lib/api/helpers.rb', line 180

def check_namespace_access(namespace)
  return namespace if can?(current_user, :read_namespace, namespace)

  not_found!('Namespace')
end

#check_sha_param!(params, merge_request) ⇒ Object


427
428
429
430
431
# File 'lib/api/helpers.rb', line 427

def check_sha_param!(params, merge_request)
  if params[:sha] && merge_request.diff_head_sha != params[:sha]
    render_api_error!("SHA does not match HEAD of source branch: #{merge_request.diff_head_sha}", 409)
  end
end

#check_unmodified_since!(last_modified) ⇒ Object


22
23
24
25
26
27
28
# File 'lib/api/helpers.rb', line 22

def check_unmodified_since!(last_modified)
  if_unmodified_since = Time.parse(headers['If-Unmodified-Since']) rescue nil

  if if_unmodified_since && last_modified && last_modified > if_unmodified_since
    render_api_error!('412 Precondition Failed', 412)
  end
end

#conflict!(message = nil) ⇒ Object


449
450
451
# File 'lib/api/helpers.rb', line 449

def conflict!(message = nil)
  render_api_error!(message || '409 Conflict', 409)
end

#created!Object


469
470
471
# File 'lib/api/helpers.rb', line 469

def created!
  render_api_error!('201 Created', 201)
end

#current_authenticated_jobObject

Returns the job associated with the token provided for authentication, if any


51
52
53
54
55
56
57
# File 'lib/api/helpers.rb', line 51

def current_authenticated_job
  if try(:namespace_inheritable, :authentication)
    ci_build_from_namespace_inheritable
  else
    @current_authenticated_job # rubocop:disable Gitlab/ModuleWithInstanceVariables
  end
end

#current_userObject

rubocop:disable Gitlab/ModuleWithInstanceVariables We can't rewrite this with StrongMemoize because `sudo!` would actually write to `@current_user`, and `sudo?` would immediately call `current_user` again which reads from `@current_user`. We should rewrite this in a way that using StrongMemoize is possible


64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/api/helpers.rb', line 64

def current_user
  return @current_user if defined?(@current_user)

  @current_user = initial_current_user

  Gitlab::I18n.locale = @current_user&.preferred_language

  sudo!

  validate_access_token!(scopes: scopes_registered_for_endpoint) unless sudo?

  save_current_user_in_env(@current_user) if @current_user

  if @current_user
    ::ApplicationRecord
      .sticking
      .stick_or_unstick_request(env, :user, @current_user.id)
  end

  @current_user
end

#declared_params(options = {}) ⇒ Object


17
18
19
20
# File 'lib/api/helpers.rb', line 17

def declared_params(options = {})
  options = { include_parent_namespaces: false }.merge(options)
  declared(params, options).to_h.symbolize_keys
end

#destroy_conditionally!(resource, last_updated: nil) ⇒ Object


30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/api/helpers.rb', line 30

def destroy_conditionally!(resource, last_updated: nil)
  last_updated ||= resource.updated_at

  check_unmodified_since!(last_updated)

  status 204
  body false

  if block_given?
    yield resource
  else
    resource.destroy
  end
end

#file_too_large!Object


457
458
459
# File 'lib/api/helpers.rb', line 457

def file_too_large!
  render_api_error!('413 Request Entity Too Large', 413)
end

#filter_by_iid(items, iid) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


381
382
383
# File 'lib/api/helpers.rb', line 381

def filter_by_iid(items, iid)
  items.where(iid: iid)
end

#filter_by_search(items, text) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


392
393
394
# File 'lib/api/helpers.rb', line 392

def filter_by_search(items, text)
  items.search(text)
end

#filter_by_title(items, title) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


387
388
389
# File 'lib/api/helpers.rb', line 387

def filter_by_title(items, title)
  items.where(title: title)
end

#find_branch!(branch_name) ⇒ Object


208
209
210
211
212
213
214
# File 'lib/api/helpers.rb', line 208

def find_branch!(branch_name)
  if Gitlab::GitRefValidator.validate(branch_name)
    user_project.repository.find_branch(branch_name) || not_found!('Branch')
  else
    render_api_error!('The branch refname is invalid', 400)
  end
end

#find_build!(id) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


250
251
252
# File 'lib/api/helpers.rb', line 250

def find_build!(id)
  user_project.builds.find(id.to_i)
end

#find_group(id) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


152
153
154
155
156
157
158
# File 'lib/api/helpers.rb', line 152

def find_group(id)
  if id.to_s =~ /^\d+$/
    Group.find_by(id: id)
  else
    Group.find_by_full_path(id)
  end
end

#find_group!(id) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


161
162
163
164
# File 'lib/api/helpers.rb', line 161

def find_group!(id)
  group = find_group(id)
  check_group_access(group)
end

#find_group_by_full_path!(full_path) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


167
168
169
170
# File 'lib/api/helpers.rb', line 167

def find_group_by_full_path!(full_path)
  group = Group.find_by_full_path(full_path)
  check_group_access(group)
end

#find_job!(id) ⇒ Object


254
255
256
# File 'lib/api/helpers.rb', line 254

def find_job!(id)
  user_project.processables.find(id.to_i)
end

#find_merge_request_with_access(iid, access_level = :read_merge_request) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


243
244
245
246
247
# File 'lib/api/helpers.rb', line 243

def find_merge_request_with_access(iid, access_level = :read_merge_request)
  merge_request = user_project.merge_requests.find_by!(iid: iid)
  authorize! access_level, merge_request
  merge_request
end

#find_namespace(id) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


187
188
189
190
191
192
193
# File 'lib/api/helpers.rb', line 187

def find_namespace(id)
  if id.to_s =~ /^\d+$/
    Namespace.without_project_namespaces.find_by(id: id)
  else
    find_namespace_by_path(id)
  end
end

#find_namespace!(id) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


196
197
198
# File 'lib/api/helpers.rb', line 196

def find_namespace!(id)
  check_namespace_access(find_namespace(id))
end

#find_namespace_by_path(path) ⇒ Object


200
201
202
# File 'lib/api/helpers.rb', line 200

def find_namespace_by_path(path)
  Namespace.without_project_namespaces.find_by_full_path(path)
end

#find_namespace_by_path!(path) ⇒ Object


204
205
206
# File 'lib/api/helpers.rb', line 204

def find_namespace_by_path!(path)
  check_namespace_access(find_namespace_by_path(path))
end

#find_project(id) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


119
120
121
122
123
124
125
126
127
128
129
# File 'lib/api/helpers.rb', line 119

def find_project(id)
  return unless id

  projects = Project.without_deleted.not_hidden

  if id.is_a?(Integer) || id =~ /^\d+$/
    projects.find_by(id: id)
  elsif id.include?("/")
    projects.find_by_full_path(id)
  end
end

#find_project!(id) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


132
133
134
135
136
137
138
139
140
141
# File 'lib/api/helpers.rb', line 132

def find_project!(id)
  project = find_project(id)

  return forbidden! unless authorized_project_scope?(project)

  return project if can?(current_user, :read_project, project)
  return unauthorized! if authenticate_non_public?

  not_found!('Project')
end

#find_project_commit(id) ⇒ Object

rubocop: enable CodeReuse/ActiveRecord


238
239
240
# File 'lib/api/helpers.rb', line 238

def find_project_commit(id)
  user_project.commit_by(oid: id)
end

#find_project_issue(iid, project_id = nil) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


225
226
227
228
229
# File 'lib/api/helpers.rb', line 225

def find_project_issue(iid, project_id = nil)
  project = project_id ? find_project!(project_id) : user_project

  ::IssuesFinder.new(current_user, project_id: project.id).find_by!(iid: iid)
end

#find_project_merge_request(iid) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


233
234
235
# File 'lib/api/helpers.rb', line 233

def find_project_merge_request(iid)
  MergeRequestsFinder.new(current_user, project_id: user_project.id).find_by!(iid: iid)
end

#find_tag!(tag_name) ⇒ Object


216
217
218
219
220
221
222
# File 'lib/api/helpers.rb', line 216

def find_tag!(tag_name)
  if Gitlab::GitRefValidator.validate(tag_name)
    user_project.repository.find_tag(tag_name) || not_found!('Tag')
  else
    render_api_error!('The tag refname is invalid', 400)
  end
end

#find_user(id) ⇒ Object


114
115
116
# File 'lib/api/helpers.rb', line 114

def find_user(id)
  UserFinder.new(id).find_by_id_or_username
end

#forbidden!(reason = nil) ⇒ Object

error helpers


404
405
406
407
408
# File 'lib/api/helpers.rb', line 404

def forbidden!(reason = nil)
  message = ['403 Forbidden']
  message << "- #{reason}" if reason
  render_api_error!(message.join(' '), 403)
end

#handle_api_exception(exception) ⇒ Object


505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
# File 'lib/api/helpers.rb', line 505

def handle_api_exception(exception)
  if report_exception?(exception)
    define_params_for_grape_middleware
    Gitlab::ApplicationContext.push(user: current_user, remote_ip: request.ip)
    Gitlab::ErrorTracking.track_exception(exception)
  end

  # This is used with GrapeLogging::Loggers::ExceptionLogger
  env[API_EXCEPTION_ENV] = exception

  # lifted from https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb#L60
  trace = exception.backtrace

  message = ["\n#{exception.class} (#{exception.message}):\n"]
  message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
  message << "  " << trace.join("\n  ")
  message = message.join

  API.logger.add Logger::FATAL, message

  response_message =
    if Rails.env.test?
      message
    else
      '500 Internal Server Error'
    end

  rack_response({ 'message' => response_message }.to_json, 500)
end

#increment_counter(event_name) ⇒ Object


581
582
583
584
585
586
587
588
# File 'lib/api/helpers.rb', line 581

def increment_counter(event_name)
  feature_name = "usage_data_#{event_name}"
  return unless Feature.enabled?(feature_name)

  Gitlab::UsageDataCounters.count(event_name)
rescue StandardError => error
  Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}")
end

#increment_unique_values(event_name, values) ⇒ Object

Parameters:

  • event_name (String)

    the event name

  • values (Array|String)

    the values counted


592
593
594
595
596
597
598
# File 'lib/api/helpers.rb', line 592

def increment_unique_values(event_name, values)
  return unless values.present?

  Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: values)
rescue StandardError => error
  Gitlab::AppLogger.warn("Redis tracking event failed for event: #{event_name}, message: #{error.message}")
end

#job_token_authentication?Boolean

Returns:

  • (Boolean)

45
46
47
# File 'lib/api/helpers.rb', line 45

def job_token_authentication?
  initial_current_user && @current_authenticated_job.present? # rubocop:disable Gitlab/ModuleWithInstanceVariables
end

#model_error_messages(model) ⇒ Object


483
484
485
# File 'lib/api/helpers.rb', line 483

def model_error_messages(model)
  model.errors.messages
end

#no_content!Object


465
466
467
# File 'lib/api/helpers.rb', line 465

def no_content!
  render_api_error!('204 No Content', 204)
end

#not_acceptable!Object


441
442
443
# File 'lib/api/helpers.rb', line 441

def not_acceptable!
  render_api_error!('406 Not Acceptable', 406)
end

#not_allowed!(message = nil) ⇒ Object


437
438
439
# File 'lib/api/helpers.rb', line 437

def not_allowed!(message = nil)
  render_api_error!(message || '405 Method Not Allowed', :method_not_allowed)
end

#not_found!(resource = nil) ⇒ Object


420
421
422
423
424
425
# File 'lib/api/helpers.rb', line 420

def not_found!(resource = nil)
  message = ["404"]
  message << resource if resource
  message << "Not Found"
  render_api_error!(message.join(' '), 404)
end

#not_modified!Object


461
462
463
# File 'lib/api/helpers.rb', line 461

def not_modified!
  render_api_error!('304 Not Modified', 304)
end

#order_by_similarity?(allow_unauthorized: true) ⇒ Boolean

Returns:

  • (Boolean)

600
601
602
# File 'lib/api/helpers.rb', line 600

def order_by_similarity?(allow_unauthorized: true)
  params[:order_by] == 'similarity' && params[:search].present? && (allow_unauthorized || current_user.present?)
end

#order_options_with_tie_breakerObject


396
397
398
399
400
# File 'lib/api/helpers.rb', line 396

def order_options_with_tie_breaker
  order_options = { params[:order_by] => params[:sort] }
  order_options['id'] ||= params[:sort] || 'asc'
  order_options
end

#present_carrierwave_file!(file, supports_direct_download: true) ⇒ Object


565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
# File 'lib/api/helpers.rb', line 565

def present_carrierwave_file!(file, supports_direct_download: true)
  return not_found! unless file&.exists?

  log_artifact_size(file) if file.is_a?(JobArtifactUploader)

  if file.file_storage?
    present_disk_file!(file.path, file.filename)
  elsif supports_direct_download && file.class.direct_download_enabled?
    redirect(file.url)
  else
    header(*Gitlab::Workhorse.send_url(file.url))
    status :ok
    body '' # to avoid an error from API::APIGuard::ResponseCoercerMiddleware
  end
end

#present_disk_file!(path, filename, content_type = 'application/octet-stream') ⇒ Object

file helpers


549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
# File 'lib/api/helpers.rb', line 549

def present_disk_file!(path, filename, content_type = 'application/octet-stream')
  filename ||= File.basename(path)
  header['Content-Disposition'] = ActionDispatch::Http::ContentDisposition.format(disposition: 'attachment', filename: filename)
  header['Content-Transfer-Encoding'] = 'binary'
  content_type content_type

  # Support download acceleration
  case headers['X-Sendfile-Type']
  when 'X-Sendfile'
    header['X-Sendfile'] = path
    body '' # to avoid an error from API::APIGuard::ResponseCoercerMiddleware
  else
    sendfile path
  end
end

#process_create_params(args) ⇒ Object


74
75
76
77
78
79
80
81
# File 'lib/api/helpers/snippets_helpers.rb', line 74

def process_create_params(args)
  args[:snippet_actions] = args.delete(:files)&.map do |file|
    file[:action] = :create
    file.symbolize_keys
  end

  args
end

#process_update_params(args) ⇒ Object


83
84
85
86
87
# File 'lib/api/helpers/snippets_helpers.rb', line 83

def process_update_params(args)
  args[:snippet_actions] = args.delete(:files)&.map(&:symbolize_keys)

  args
end

#project_finder_paramsObject

rubocop: enable CodeReuse/ActiveRecord


543
544
545
# File 'lib/api/helpers.rb', line 543

def project_finder_params
  project_finder_params_ce.merge(project_finder_params_ee)
end

#render_api_error!(message, status) ⇒ Object


487
488
489
# File 'lib/api/helpers.rb', line 487

def render_api_error!(message, status)
  render_structured_api_error!({ 'message' => message }, status)
end

#render_structured_api_error!(hash, status) ⇒ Object


491
492
493
494
495
496
# File 'lib/api/helpers.rb', line 491

def render_structured_api_error!(hash, status)
  # Use this method instead of `render_api_error!` when you have additional top-level
  # hash entries in addition to 'message' which need to be passed to `#error!`
  set_status_code_in_env(status)
  error!(hash, status, header)
end

#render_validation_error!(model) ⇒ Object


477
478
479
480
481
# File 'lib/api/helpers.rb', line 477

def render_validation_error!(model)
  if model.errors.any?
    render_api_error!(model_error_messages(model) || '400 Bad Request', 400)
  end
end

#reorder_projects(projects) ⇒ Object

rubocop: disable CodeReuse/ActiveRecord


538
539
540
# File 'lib/api/helpers.rb', line 538

def reorder_projects(projects)
  projects.reorder(order_options_with_tie_breaker)
end

#require_gitlab_workhorse!Object


329
330
331
332
333
334
335
# File 'lib/api/helpers.rb', line 329

def require_gitlab_workhorse!
  verify_workhorse_api!

  unless env['HTTP_GITLAB_WORKHORSE'].present?
    forbidden!('Request should be executed via GitLab Workhorse')
  end
end

#require_pages_config_enabled!Object


349
350
351
# File 'lib/api/helpers.rb', line 349

def require_pages_config_enabled!
  not_found! unless Gitlab.config.pages.enabled
end

#require_pages_enabled!Object


345
346
347
# File 'lib/api/helpers.rb', line 345

def require_pages_enabled!
  not_found! unless user_project.pages_available?
end

#require_repository_enabled!(subject = :global) ⇒ Object


325
326
327
# File 'lib/api/helpers.rb', line 325

def require_repository_enabled!(subject = :global)
  not_found!("Repository") unless user_project.feature_available?(:repository, current_user)
end

#required_attributes!(keys) ⇒ Object

Checks the occurrences of required attributes, each attribute must be present in the params hash or a Bad Request error is invoked.

Parameters:

keys (required) - A hash consisting of keys that must be present

362
363
364
365
366
# File 'lib/api/helpers.rb', line 362

def required_attributes!(keys)
  keys.each do |key|
    bad_request_missing_attribute!(key) unless params[key].present?
  end
end

#save_current_user_in_env(user) ⇒ Object

rubocop:enable Gitlab/ModuleWithInstanceVariables


87
88
89
# File 'lib/api/helpers.rb', line 87

def save_current_user_in_env(user)
  env[API_USER_ENV] = { user_id: user.id, username: user.username }
end

#service_unavailable!(message = nil) ⇒ Object


445
446
447
# File 'lib/api/helpers.rb', line 445

def service_unavailable!(message = nil)
  render_api_error!(message || '503 Service Unavailable', 503)
end

#set_status_code_in_env(status) ⇒ Object


498
499
500
501
502
503
# File 'lib/api/helpers.rb', line 498

def set_status_code_in_env(status)
  # grape-logging doesn't pass the status code, so this is a
  # workaround for getting that information in the loggers:
  # https://github.com/aserafin/grape_logging/issues/71
  env[API_RESPONSE_STATUS_CODE] = Rack::Utils.status_code(status)
end

#sudo?Boolean

Returns:

  • (Boolean)

91
92
93
# File 'lib/api/helpers.rb', line 91

def sudo?
  initial_current_user != current_user
end

#unauthorized!Object


433
434
435
# File 'lib/api/helpers.rb', line 433

def unauthorized!
  render_api_error!('401 Unauthorized', 401)
end

#unprocessable_entity!(message = nil) ⇒ Object


453
454
455
# File 'lib/api/helpers.rb', line 453

def unprocessable_entity!(message = nil)
  render_api_error!(message || '422 Unprocessable Entity', :unprocessable_entity)
end

#user_groupObject


95
96
97
# File 'lib/api/helpers.rb', line 95

def user_group
  @group ||= find_group!(params[:id])
end

#user_projectObject


99
100
101
# File 'lib/api/helpers.rb', line 99

def user_project
  @project ||= find_project!(params[:id])
end

#validate_params_for_multiple_files(snippet) ⇒ Object


89
90
91
92
93
94
95
# File 'lib/api/helpers/snippets_helpers.rb', line 89

def validate_params_for_multiple_files(snippet)
  return unless params[:content] || params[:file_name]

  if snippet.multiple_files?
    render_api_error!({ error: _('To update Snippets with multiple files, you must use the `files` parameter') }, 400)
  end
end

#verify_workhorse_api!Object


337
338
339
340
341
342
343
# File 'lib/api/helpers.rb', line 337

def verify_workhorse_api!
  Gitlab::Workhorse.verify_api_request!(request.headers)
rescue StandardError => e
  Gitlab::ErrorTracking.track_exception(e)

  forbidden!
end