2013-05-14 08:33:31 -04:00
|
|
|
module API
|
2012-06-27 07:32:56 -04:00
|
|
|
module APIHelpers
|
2013-03-28 14:37:44 -04:00
|
|
|
PRIVATE_TOKEN_HEADER = "HTTP_PRIVATE_TOKEN"
|
|
|
|
PRIVATE_TOKEN_PARAM = :private_token
|
|
|
|
SUDO_HEADER ="HTTP_SUDO"
|
|
|
|
SUDO_PARAM = :sudo
|
|
|
|
|
2014-07-28 01:01:01 -04:00
|
|
|
def parse_boolean(value)
|
|
|
|
[ true, 1, '1', 't', 'T', 'true', 'TRUE', 'on', 'ON' ].include?(value)
|
|
|
|
end
|
|
|
|
|
2012-06-27 07:32:56 -04:00
|
|
|
def current_user
|
2013-11-08 11:49:38 -05:00
|
|
|
private_token = (params[PRIVATE_TOKEN_PARAM] || env[PRIVATE_TOKEN_HEADER]).to_s
|
2014-12-19 09:15:29 -05:00
|
|
|
@current_user ||= (User.find_by(authentication_token: private_token) || doorkeeper_guard)
|
2014-05-15 04:03:26 -04:00
|
|
|
|
|
|
|
unless @current_user && Gitlab::UserAccess.allowed?(@current_user)
|
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
2013-03-28 14:37:44 -04:00
|
|
|
identifier = sudo_identifier()
|
2013-11-08 11:49:38 -05:00
|
|
|
|
2013-03-28 14:37:44 -04:00
|
|
|
# If the sudo is the current user do nothing
|
2015-03-24 21:28:10 -04:00
|
|
|
if identifier && !(@current_user.id == identifier || @current_user.username == identifier)
|
2013-03-28 14:37:44 -04:00
|
|
|
render_api_error!('403 Forbidden: Must be admin to use sudo', 403) unless @current_user.is_admin?
|
2013-10-16 13:31:46 -04:00
|
|
|
@current_user = User.by_username_or_id(identifier)
|
2013-10-16 13:28:39 -04:00
|
|
|
not_found!("No user id or username for: #{identifier}") if @current_user.nil?
|
2013-03-28 14:37:44 -04:00
|
|
|
end
|
2013-11-08 11:49:38 -05:00
|
|
|
|
2013-03-28 14:37:44 -04:00
|
|
|
@current_user
|
|
|
|
end
|
|
|
|
|
|
|
|
def sudo_identifier()
|
2013-06-28 08:59:05 -04:00
|
|
|
identifier ||= params[SUDO_PARAM] ||= env[SUDO_HEADER]
|
2013-11-08 11:49:38 -05:00
|
|
|
|
2013-06-28 08:59:05 -04:00
|
|
|
# Regex for integers
|
2015-03-24 21:28:10 -04:00
|
|
|
if !!(identifier =~ /^[0-9]+$/)
|
2013-03-28 14:37:44 -04:00
|
|
|
identifier.to_i
|
|
|
|
else
|
|
|
|
identifier
|
|
|
|
end
|
2012-06-27 07:32:56 -04:00
|
|
|
end
|
|
|
|
|
2012-07-06 09:08:17 -04:00
|
|
|
def user_project
|
2013-06-27 17:49:26 -04:00
|
|
|
@project ||= find_project(params[:id])
|
2014-12-30 07:36:13 -05:00
|
|
|
@project || not_found!("Project")
|
2012-12-12 05:54:28 -05:00
|
|
|
end
|
|
|
|
|
2013-06-27 17:49:26 -04:00
|
|
|
def find_project(id)
|
2014-03-14 09:58:52 -04:00
|
|
|
project = Project.find_with_namespace(id) || Project.find_by(id: id)
|
2012-12-12 05:54:28 -05:00
|
|
|
|
|
|
|
if project && can?(current_user, :read_project, project)
|
|
|
|
project
|
2012-07-25 08:24:28 -04:00
|
|
|
else
|
2012-12-12 05:54:28 -05:00
|
|
|
nil
|
2012-07-25 08:24:28 -04:00
|
|
|
end
|
2012-07-06 09:08:17 -04:00
|
|
|
end
|
|
|
|
|
2015-08-26 19:58:49 -04:00
|
|
|
def project_service
|
|
|
|
@project_service ||= begin
|
|
|
|
underscored_service = params[:service_slug].underscore
|
|
|
|
|
|
|
|
if Service.available_services_names.include?(underscored_service)
|
|
|
|
user_project.build_missing_services
|
|
|
|
|
|
|
|
service_method = "#{underscored_service}_service"
|
2015-10-03 02:29:58 -04:00
|
|
|
|
2015-08-26 19:58:49 -04:00
|
|
|
send_service(service_method)
|
|
|
|
end
|
|
|
|
end
|
2015-10-03 02:29:58 -04:00
|
|
|
|
2015-08-26 19:58:49 -04:00
|
|
|
@project_service || not_found!("Service")
|
|
|
|
end
|
|
|
|
|
|
|
|
def send_service(service_method)
|
|
|
|
user_project.send(service_method)
|
|
|
|
end
|
|
|
|
|
|
|
|
def service_attributes
|
|
|
|
@service_attributes ||= project_service.fields.inject([]) do |arr, hash|
|
|
|
|
arr << hash[:name].to_sym
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-01-30 04:46:08 -05:00
|
|
|
def find_group(id)
|
|
|
|
begin
|
|
|
|
group = Group.find(id)
|
|
|
|
rescue ActiveRecord::RecordNotFound
|
|
|
|
group = Group.find_by!(path: id)
|
|
|
|
end
|
|
|
|
|
|
|
|
if can?(current_user, :read_group, group)
|
|
|
|
group
|
|
|
|
else
|
|
|
|
forbidden!("#{current_user.username} lacks sufficient "\
|
|
|
|
"access to #{group.name}")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2013-10-29 05:41:20 -04:00
|
|
|
def paginate(relation)
|
|
|
|
per_page = params[:per_page].to_i
|
|
|
|
paginated = relation.page(params[:page]).per(per_page)
|
|
|
|
add_pagination_headers(paginated, per_page)
|
|
|
|
|
|
|
|
paginated
|
2012-09-03 07:46:29 -04:00
|
|
|
end
|
|
|
|
|
2012-06-27 07:32:56 -04:00
|
|
|
def authenticate!
|
2012-09-10 03:41:46 -04:00
|
|
|
unauthorized! unless current_user
|
2012-06-27 07:32:56 -04:00
|
|
|
end
|
2012-09-10 02:06:11 -04:00
|
|
|
|
2014-10-15 11:26:15 -04:00
|
|
|
def authenticate_by_gitlab_shell_token!
|
2015-03-06 13:49:38 -05:00
|
|
|
input = params['secret_token'].try(:chomp)
|
|
|
|
unless Devise.secure_compare(secret_token, input)
|
|
|
|
unauthorized!
|
|
|
|
end
|
2014-10-15 11:26:15 -04:00
|
|
|
end
|
|
|
|
|
2012-10-02 05:46:01 -04:00
|
|
|
def authenticated_as_admin!
|
|
|
|
forbidden! unless current_user.is_admin?
|
|
|
|
end
|
|
|
|
|
2014-09-25 18:07:40 -04:00
|
|
|
def authorize!(action, subject)
|
2012-09-10 02:06:11 -04:00
|
|
|
unless abilities.allowed?(current_user, action, subject)
|
2012-09-10 03:41:46 -04:00
|
|
|
forbidden!
|
2012-09-10 02:06:11 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2014-04-01 03:39:53 -04:00
|
|
|
def authorize_push_project
|
|
|
|
authorize! :push_code, user_project
|
|
|
|
end
|
|
|
|
|
2013-09-29 09:04:57 -04:00
|
|
|
def authorize_admin_project
|
|
|
|
authorize! :admin_project, user_project
|
|
|
|
end
|
|
|
|
|
2012-12-12 05:54:28 -05:00
|
|
|
def can?(object, action, subject)
|
|
|
|
abilities.allowed?(object, action, subject)
|
|
|
|
end
|
|
|
|
|
2013-02-27 11:50:30 -05:00
|
|
|
# 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
|
|
|
|
def required_attributes!(keys)
|
|
|
|
keys.each do |key|
|
|
|
|
bad_request!(key) unless params[key].present?
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-09-14 11:14:17 -04:00
|
|
|
def attributes_for_keys(keys, custom_params = nil)
|
2012-09-16 12:51:04 -04:00
|
|
|
attrs = {}
|
|
|
|
keys.each do |key|
|
2014-06-26 16:24:17 -04:00
|
|
|
if params[key].present? or (params.has_key?(key) and params[key] == false)
|
|
|
|
attrs[key] = params[key]
|
|
|
|
end
|
2012-09-16 12:51:04 -04:00
|
|
|
end
|
2014-06-26 16:24:17 -04:00
|
|
|
ActionController::Parameters.new(attrs).permit!
|
2012-09-16 12:51:04 -04:00
|
|
|
end
|
|
|
|
|
2014-08-14 04:17:52 -04:00
|
|
|
# Helper method for validating all labels against its names
|
|
|
|
def validate_label_params(params)
|
2014-08-17 16:22:01 -04:00
|
|
|
errors = {}
|
|
|
|
|
2014-08-14 04:17:52 -04:00
|
|
|
if params[:labels].present?
|
|
|
|
params[:labels].split(',').each do |label_name|
|
|
|
|
label = user_project.labels.create_with(
|
|
|
|
color: Label::DEFAULT_COLOR).find_or_initialize_by(
|
|
|
|
title: label_name.strip)
|
2014-08-17 16:22:01 -04:00
|
|
|
|
2014-08-14 04:17:52 -04:00
|
|
|
if label.invalid?
|
2014-08-17 16:22:01 -04:00
|
|
|
errors[label.title] = label.errors
|
2014-08-14 04:17:52 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2014-08-17 16:22:01 -04:00
|
|
|
|
|
|
|
errors
|
2014-08-14 04:17:52 -04:00
|
|
|
end
|
|
|
|
|
2015-01-30 04:46:08 -05:00
|
|
|
def validate_access_level?(level)
|
|
|
|
Gitlab::Access.options_with_owner.values.include? level.to_i
|
|
|
|
end
|
|
|
|
|
2015-02-06 01:00:54 -05:00
|
|
|
def issuable_order_by
|
|
|
|
if params["order_by"] == 'updated_at'
|
|
|
|
'updated_at'
|
|
|
|
else
|
|
|
|
'created_at'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def issuable_sort
|
|
|
|
if params["sort"] == 'asc'
|
|
|
|
:asc
|
|
|
|
else
|
|
|
|
:desc
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2015-01-17 17:45:39 -05:00
|
|
|
def filter_by_iid(items, iid)
|
|
|
|
items.where(iid: iid)
|
|
|
|
end
|
|
|
|
|
2012-09-10 03:41:46 -04:00
|
|
|
# error helpers
|
|
|
|
|
2015-01-30 04:46:08 -05:00
|
|
|
def forbidden!(reason = nil)
|
|
|
|
message = ['403 Forbidden']
|
|
|
|
message << " - #{reason}" if reason
|
|
|
|
render_api_error!(message.join(' '), 403)
|
2012-09-10 03:41:46 -04:00
|
|
|
end
|
|
|
|
|
2013-02-13 09:48:52 -05:00
|
|
|
def bad_request!(attribute)
|
|
|
|
message = ["400 (Bad request)"]
|
|
|
|
message << "\"" + attribute.to_s + "\" not given"
|
|
|
|
render_api_error!(message.join(' '), 400)
|
|
|
|
end
|
|
|
|
|
2012-09-10 03:41:46 -04:00
|
|
|
def not_found!(resource = nil)
|
|
|
|
message = ["404"]
|
|
|
|
message << resource if resource
|
|
|
|
message << "Not Found"
|
2012-09-10 06:49:00 -04:00
|
|
|
render_api_error!(message.join(' '), 404)
|
2012-09-10 03:41:46 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def unauthorized!
|
2012-09-10 06:49:00 -04:00
|
|
|
render_api_error!('401 Unauthorized', 401)
|
2012-09-10 03:41:46 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def not_allowed!
|
2014-08-18 14:09:09 -04:00
|
|
|
render_api_error!('405 Method Not Allowed', 405)
|
|
|
|
end
|
|
|
|
|
|
|
|
def conflict!(message = nil)
|
|
|
|
render_api_error!(message || '409 Conflict', 409)
|
|
|
|
end
|
|
|
|
|
|
|
|
def render_validation_error!(model)
|
2015-03-07 13:23:43 -05:00
|
|
|
if model.errors.any?
|
2014-08-18 14:09:09 -04:00
|
|
|
render_api_error!(model.errors.messages || '400 Bad Request', 400)
|
|
|
|
end
|
2012-09-10 06:49:00 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def render_api_error!(message, status)
|
2015-02-02 23:36:54 -05:00
|
|
|
error!({ 'message' => message }, status)
|
2012-09-10 03:41:46 -04:00
|
|
|
end
|
|
|
|
|
2015-09-15 06:50:24 -04:00
|
|
|
# Projects helpers
|
|
|
|
|
|
|
|
def filter_projects(projects)
|
|
|
|
# If the archived parameter is passed, limit results accordingly
|
|
|
|
if params[:archived].present?
|
|
|
|
projects = projects.where(archived: parse_boolean(params[:archived]))
|
|
|
|
end
|
|
|
|
|
|
|
|
if params[:search].present?
|
|
|
|
projects = projects.search(params[:search])
|
|
|
|
end
|
|
|
|
|
|
|
|
if params[:ci_enabled_first].present?
|
|
|
|
projects.includes(:gitlab_ci_service).
|
|
|
|
reorder("services.active DESC, projects.#{project_order_by} #{project_sort}")
|
|
|
|
else
|
|
|
|
projects.reorder(project_order_by => project_sort)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def project_order_by
|
|
|
|
order_fields = %w(id name path created_at updated_at last_activity_at)
|
|
|
|
|
|
|
|
if order_fields.include?(params['order_by'])
|
|
|
|
params['order_by']
|
|
|
|
else
|
|
|
|
'created_at'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def project_sort
|
|
|
|
if params["sort"] == 'asc'
|
|
|
|
:asc
|
|
|
|
else
|
|
|
|
:desc
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2012-09-21 06:22:30 -04:00
|
|
|
private
|
2012-09-10 02:06:11 -04:00
|
|
|
|
2013-10-29 05:41:20 -04:00
|
|
|
def add_pagination_headers(paginated, per_page)
|
|
|
|
request_url = request.url.split('?').first
|
|
|
|
|
|
|
|
links = []
|
|
|
|
links << %(<#{request_url}?page=#{paginated.current_page - 1}&per_page=#{per_page}>; rel="prev") unless paginated.first_page?
|
|
|
|
links << %(<#{request_url}?page=#{paginated.current_page + 1}&per_page=#{per_page}>; rel="next") unless paginated.last_page?
|
|
|
|
links << %(<#{request_url}?page=1&per_page=#{per_page}>; rel="first")
|
|
|
|
links << %(<#{request_url}?page=#{paginated.total_pages}&per_page=#{per_page}>; rel="last")
|
|
|
|
|
|
|
|
header 'Link', links.join(', ')
|
|
|
|
end
|
|
|
|
|
2012-09-10 02:06:11 -04:00
|
|
|
def abilities
|
|
|
|
@abilities ||= begin
|
2013-06-28 08:59:05 -04:00
|
|
|
abilities = Six.new
|
|
|
|
abilities << Ability
|
|
|
|
abilities
|
|
|
|
end
|
2012-09-10 02:06:11 -04:00
|
|
|
end
|
2014-10-15 11:26:15 -04:00
|
|
|
|
|
|
|
def secret_token
|
2015-02-16 07:16:26 -05:00
|
|
|
File.read(Gitlab.config.gitlab_shell.secret_file).chomp
|
2014-10-15 11:26:15 -04:00
|
|
|
end
|
2015-01-20 22:34:09 -05:00
|
|
|
|
|
|
|
def handle_member_errors(errors)
|
|
|
|
error!(errors[:access_level], 422) if errors[:access_level].any?
|
|
|
|
not_found!(errors)
|
|
|
|
end
|
2012-06-27 07:32:56 -04:00
|
|
|
end
|
|
|
|
end
|