app/controllers/api/v2/base_controller.rb
# frozen_string_literal: true
module Api
# Version the API explicitly in the URL to allow different versions with breaking changes to co-exist if necessary.
# The roll over to the next number should happen when code written against the old version will not work
# with the new version.
module V2
class BaseController < ApplicationController
skip_before_action :verify_authenticity_token
before_action :restrict_access
# Prevent unhandled errors from returning the normal HTML page
rescue_from StandardError, with: :render_standard_error_response
private
# Look for a token in the Authorization header only and check that the token isn't currently banned
def restrict_access
authenticate_or_request_with_http_token do |token, _|
ApiKey.exists?(access_token: token) && !ApiKey.find_by(access_token: token).banned?
end
end
# Top-level error handling: returns a 403 forbidden if a valid archivist isn't supplied and a 400
# if no works are supplied. If there is neither a valid archivist nor valid works, a 400 is returned
# with both errors as a message
def batch_errors(archivist, import_items)
errors = []
status = ""
if archivist&.is_archivist?
if import_items.nil? || import_items.empty?
status = :empty_request
errors << "No items to import were provided."
elsif import_items.size >= ArchiveConfig.IMPORT_MAX_WORKS_BY_ARCHIVIST
status = :too_many_request
errors << "This request contains too many items to import. A maximum of #{ArchiveConfig.IMPORT_MAX_WORKS_BY_ARCHIVIST} " \
"items can be imported at one time by an archivist."
end
else
status = :forbidden
errors << "The \"archivist\" field must specify the name of an Archive user with archivist privileges."
end
status = :ok if errors.empty?
[status, errors]
end
# Return a standard HTTP + Json envelope for all API responses
def render_api_response(status, messages, response = {})
# It's a bad request unless it's ok or an authorisation error
http_status = %i[forbidden ok].include?(status) ? status : :bad_request
render status: http_status, json: { status: status, messages: messages }.merge(response)
end
# Return a standard HTTP + Json envelope for errors that drop through other handling
def render_standard_error_response(exception)
message = "An error occurred in the Archive code: #{exception.message}"
render status: :internal_server_error, json: { status: :internal_server_error, messages: [message] }
end
end
end
end