app/controllers/forest_liana/resources_controller.rb
module ForestLiana
class ResourcesController < ForestLiana::ApplicationController
include ForestLiana::Ability
begin
prepend ResourcesExtensions
rescue NameError
end
rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found
if Rails::VERSION::MAJOR < 4
before_filter :find_resource, except: :count
else
before_action :find_resource, except: :count
end
def index
action = request.format == 'csv' ? 'export' : 'browse'
forest_authorize!(action, forest_user, @resource)
begin
getter = ForestLiana::ResourcesGetter.new(@resource, params, forest_user)
getter.perform
respond_to do |format|
format.json { render_jsonapi(getter) }
format.csv { render_csv(getter, @resource) }
end
rescue ForestLiana::Errors::LiveQueryError => error
render json: { errors: [{ status: 422, detail: error.message }] },
status: :unprocessable_entity, serializer: nil
rescue ForestLiana::Errors::ExpectedError => error
error.display_error
error_data = ForestAdmin::JSONAPI::Serializer.serialize_errors([{
status: error.error_code,
detail: error.message
}])
render(serializer: nil, json: error_data, status: error.status)
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Records Index error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
def count
find_resource
forest_authorize!('browse', forest_user, @resource)
begin
getter = ForestLiana::ResourcesGetter.new(@resource, params, forest_user)
getter.count
render serializer: nil, json: { count: getter.records_count }
rescue ForestLiana::Errors::LiveQueryError => error
render json: { errors: [{ status: 422, detail: error.message }] },
status: :unprocessable_entity, serializer: nil
rescue ForestLiana::Errors::ExpectedError => error
error.display_error
error_data = ForestAdmin::JSONAPI::Serializer.serialize_errors([{
status: error.error_code,
detail: error.message
}])
render(serializer: nil, json: error_data, status: error.status)
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Records Index Count error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
def show
forest_authorize!('read', forest_user, @resource)
begin
getter = ForestLiana::ResourceGetter.new(@resource, params, forest_user)
getter.perform
render serializer: nil, json: render_record_jsonapi(getter.record)
rescue ActiveRecord::RecordNotFound
render serializer: nil, json: { status: 404 }, status: :not_found
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Record Show error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
def create
forest_authorize!('add', forest_user, @resource)
begin
creator = ForestLiana::ResourceCreator.new(@resource, params)
creator.perform
if creator.errors
render serializer: nil, json: ForestAdmin::JSONAPI::Serializer.serialize_errors(
creator.errors), status: 400
elsif creator.record.valid?
render serializer: nil, json: render_record_jsonapi(creator.record)
else
render serializer: nil, json: ForestAdmin::JSONAPI::Serializer.serialize_errors(
creator.record.errors), status: 400
end
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Record Create error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
def update
forest_authorize!('edit', forest_user, @resource)
begin
updater = ForestLiana::ResourceUpdater.new(@resource, params, forest_user)
updater.perform
if updater.errors
render serializer: nil, json: ForestAdmin::JSONAPI::Serializer.serialize_errors(
updater.errors), status: 400
elsif updater.record.valid?
render serializer: nil, json: render_record_jsonapi(updater.record)
else
render serializer: nil, json: ForestAdmin::JSONAPI::Serializer.serialize_errors(
updater.record.errors), status: 400
end
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Record Update error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
def destroy
forest_authorize!('delete', forest_user, @resource)
begin
collection_name = ForestLiana.name_for(@resource)
scoped_records = ForestLiana::ScopeManager.apply_scopes_on_records(@resource, forest_user, collection_name, params[:timezone])
unless scoped_records.exists?(params[:id])
return render serializer: nil, json: { status: 404 }, status: :not_found
end
if scoped_records.destroy(params[:id])
head :no_content
else
restrict_error = ActiveRecord::DeleteRestrictionError.new
render json: { errors: [{ status: :bad_request, detail: restrict_error.message }] }, status: :bad_request
end
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Record Destroy error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
def destroy_bulk
forest_authorize!('delete', forest_user, @resource)
begin
ids = ForestLiana::ResourcesGetter.get_ids_from_request(params, forest_user)
@resource.transaction do
ids.each do |id|
record = @resource.find(id)
record.destroy!
end
end
rescue ActiveRecord::RecordNotDestroyed => error
render json: { errors: [{ status: :bad_request, detail: error.message }] }, status: :bad_request
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Records Destroy error: #{error}\n#{format_stacktrace(error)}"
internal_server_error
end
end
private
def find_resource
begin
@resource = SchemaUtils.find_model_from_collection_name(params[:collection])
if @resource.nil? || !SchemaUtils.model_included?(@resource) ||
!@resource.ancestors.include?(ActiveRecord::Base)
render serializer: nil, json: { status: 404 }, status: :not_found
end
rescue => error
FOREST_REPORTER.report error
FOREST_LOGGER.error "Find Collection error: #{error}\n#{format_stacktrace(error)}"
render serializer: nil, json: { status: 404 }, status: :not_found
end
end
def includes(getter)
getter.includes_for_serialization
end
def record_includes
ForestLiana::QueryHelper.get_one_association_names_string(@resource)
end
def record_not_found
head :not_found
end
def is_sti_model?
@is_sti_model ||= (@resource.inheritance_column.present? &&
@resource.columns.any? { |column| column.name == @resource.inheritance_column })
end
def get_record record
is_sti_model? ? record.becomes(@resource) : record
end
def render_record_jsonapi record
collection = ForestLiana::SchemaHelper.find_collection_from_model(@resource)
collection_fields = collection.fields.map { |field| field[:field] }
fields_to_serialize = {
ForestLiana.name_for(@resource) => collection_fields.join(',')
}
serialize_model(get_record(record), {
include: record_includes,
fields: fields_to_serialize
})
end
def render_jsonapi getter
records = getter.records.map { |record| get_record(record) }
fields_to_serialize = fields_per_model(params[:fields], @resource)
json = serialize_models(
records,
{
include: includes(getter),
fields: fields_to_serialize,
params: params
},
getter.search_query_builder.fields_searched
)
render serializer: nil, json: json
end
def get_collection
collection_name = ForestLiana.name_for(@resource)
@collection ||= ForestLiana.apimap.find { |collection| collection.name.to_s == collection_name }
end
# NOTICE: Return a formatted object containing the request condition filters and
# the user id used by the scope validator class to validate if scope is
# in request
def get_collection_list_permission_info(user, collection_list_request)
{
user_id: user['id'],
filters: collection_list_request[:filters],
segmentQuery: collection_list_request[:segmentQuery],
}
end
end
end