git-subtree-dir: plugins/redmine_hourglass git-subtree-split: ec937a4ed4717e358207dd3857fac248b9e625e9
157 lines
5.2 KiB
Ruby
157 lines
5.2 KiB
Ruby
module Hourglass
|
|
class ApiBaseController < ApplicationController
|
|
include QueryConcern
|
|
include SortConcern
|
|
include BooleanParsing
|
|
around_action :catch_halt
|
|
before_action :require_login
|
|
|
|
rescue_from StandardError, with: :internal_server_error
|
|
rescue_from ActionController::ParameterMissing, with: :missing_parameters
|
|
rescue_from(ActiveRecord::RecordNotFound) { render_404 no_halt: true }
|
|
rescue_from Query::StatementInvalid, with: :query_statement_invalid
|
|
rescue_from Hourglass::TimeLog::AlreadyBookedException, with: :already_booked
|
|
|
|
include ::AuthorizationConcern
|
|
|
|
private
|
|
|
|
# use only these codes:
|
|
# :ok (200)
|
|
# :not_modified (304)
|
|
# :bad_request (400)
|
|
# :unauthorized (401)
|
|
# :forbidden (403)
|
|
# :not_found (404)
|
|
# :internal_server_error (500)
|
|
def respond_with_error(status, message, **options)
|
|
render json: {
|
|
message: message.is_a?(Array) && options[:array_mode] == :sentence ? message.to_sentence : message,
|
|
status: Rack::Utils.status_code(status)
|
|
},
|
|
status: status
|
|
throw :halt unless options[:no_halt]
|
|
end
|
|
|
|
def respond_with_success(response_obj = nil)
|
|
if response_obj
|
|
render json: response_obj
|
|
else
|
|
head :no_content
|
|
end
|
|
throw :halt
|
|
end
|
|
|
|
def render_403(options = {})
|
|
respond_with_error :forbidden, options[:message] || t('hourglass.api.errors.forbidden'), no_halt: options[:no_halt]
|
|
end
|
|
|
|
def render_404(options = {})
|
|
respond_with_error :not_found, options[:message] || t("hourglass.api.#{controller_name}.errors.not_found", default: t('hourglass.api.errors.not_found')), no_halt: options[:no_halt]
|
|
end
|
|
|
|
def catch_halt
|
|
catch :halt do
|
|
yield
|
|
end
|
|
end
|
|
|
|
def do_update(record, params_hash)
|
|
record = authorize_update record, params_hash
|
|
if record.errors.empty?
|
|
respond_with_success
|
|
else
|
|
respond_with_error :bad_request, record.errors.full_messages, array_mode: :sentence
|
|
end
|
|
end
|
|
|
|
def list_records(klass)
|
|
authorize klass
|
|
@query_identifier = klass.name.demodulize.tableize
|
|
retrieve_query force_new: true
|
|
init_sort
|
|
scope = @query.results_scope order: sort_clause
|
|
offset, limit = api_offset_and_limit
|
|
respond_with_success(
|
|
count: scope.count,
|
|
offset: offset,
|
|
limit: limit,
|
|
records: scope.offset(offset).limit(limit).to_a
|
|
)
|
|
end
|
|
|
|
def bulk(params_key = controller_name, &block)
|
|
@bulk_success = []
|
|
@bulk_errors = []
|
|
entries = params[params_key]
|
|
entries = entries.to_unsafe_h if Rails::VERSION::MAJOR >= 5 && entries.instance_of?(ActionController::Parameters)
|
|
entries.each_with_index do |(id, params), index|
|
|
if Rails::VERSION::MAJOR <= 4
|
|
id, params = "new#{index}", id if id.is_a?(Hash)
|
|
else
|
|
id, params = "new#{index}", id if id.instance_of?(ActionController::Parameters)
|
|
params = ActionController::Parameters.new(params) if params.is_a?(Hash)
|
|
end
|
|
error_preface = id.start_with?('new') ? bulk_error_preface(index, mode: :create) : bulk_error_preface(id)
|
|
evaluate_entry bulk_entry(id, params, &block), error_preface
|
|
end
|
|
|
|
if @bulk_success.length > 0
|
|
flash_array :error, @bulk_errors if @bulk_errors.length > 0 && !api_request?
|
|
respond_with_success success: @bulk_success, errors: @bulk_errors
|
|
else
|
|
respond_with_error :bad_request, @bulk_errors
|
|
end
|
|
end
|
|
|
|
def evaluate_entry(entry, error_preface)
|
|
if entry
|
|
if entry.is_a? String
|
|
@bulk_errors.push "#{error_preface} #{entry}"
|
|
elsif entry.errors.empty?
|
|
@bulk_success.push entry
|
|
else
|
|
@bulk_errors.push "#{error_preface} #{entry.errors.full_messages.to_sentence}"
|
|
end
|
|
else
|
|
@bulk_errors.push "#{error_preface} #{t("hourglass.api.#{controller_name}.errors.not_found")}"
|
|
end
|
|
end
|
|
|
|
def bulk_entry(id, params)
|
|
yield id, params
|
|
rescue ActiveRecord::RecordNotFound
|
|
nil
|
|
rescue Pundit::NotAuthorizedError => e
|
|
e.policy.message || t('hourglass.api.errors.forbidden')
|
|
end
|
|
|
|
def bulk_error_preface(id, mode: nil)
|
|
"[#{t("hourglass.api.#{controller_name}.errors.bulk_#{'create_' if mode == :create}error_preface", id: id)}:]"
|
|
end
|
|
|
|
def missing_parameters(_e)
|
|
respond_with_error :bad_request, t('hourglass.api.errors.missing_parameters'), no_halt: true
|
|
end
|
|
|
|
def internal_server_error(e)
|
|
messages = [e.message] + e.backtrace
|
|
Rails.logger.error messages.join("\n")
|
|
respond_with_error :internal_server_error, Rails.env.production? ? t('hourglass.api.errors.internal_server_error') : messages, no_halt: true
|
|
end
|
|
|
|
def already_booked(_e)
|
|
respond_with_error :bad_request, t('hourglass.api.time_logs.errors.already_booked'), no_halt: true
|
|
end
|
|
|
|
def flash_array(type, messages)
|
|
flash[type] = render_to_string partial: 'hourglass_ui/flash_array', locals: { messages: messages }
|
|
end
|
|
|
|
def custom_field_keys(params_hash)
|
|
return {} unless params_hash[:custom_field_values]
|
|
params_hash[:custom_field_values].keys
|
|
end
|
|
end
|
|
end
|