Files
danbooru/app/controllers/application_controller.rb
evazion 9a6add9730 newrelic: refactor error logging.
* Factor out New Relic logging to DanbooruLogger class.
* Log all exceptions to New Relic, not just statement timeouts.
2019-08-08 22:16:39 -05:00

212 lines
6.3 KiB
Ruby

class ApplicationController < ActionController::Base
protect_from_forgery
helper :pagination
before_action :reset_current_user
before_action :set_current_user
after_action :reset_current_user
before_action :set_title
before_action :normalize_search
before_action :set_started_at_session
before_action :api_check
before_action :set_safe_mode
before_action :set_variant
before_action :track_only_param
layout "default"
helper_method :show_moderation_notice?
before_action :enable_cors
rescue_from Exception, :with => :rescue_exception
rescue_from User::PrivilegeError, :with => :access_denied
rescue_from SessionLoader::AuthenticationFailure, :with => :authentication_failed
rescue_from ActionController::UnpermittedParameters, :with => :access_denied
# This is raised on requests to `/blah.js`. Rails has already rendered StaticController#not_found
# here, so calling `rescue_exception` would cause a double render error.
rescue_from ActionController::InvalidCrossOriginRequest, with: -> {}
protected
def show_moderation_notice?
CurrentUser.can_approve_posts? && (cookies[:moderated].blank? || Time.at(cookies[:moderated].to_i) < 20.hours.ago)
end
def enable_cors
response.headers["Access-Control-Allow-Origin"] = "*"
end
def track_only_param
if params[:only]
RequestStore[:only_param] = params[:only].split(/,/)
end
end
def api_check
if !CurrentUser.is_anonymous? && !request.get? && !request.head?
if CurrentUser.user.token_bucket.nil?
TokenBucket.create_default(CurrentUser.user)
CurrentUser.user.reload
end
throttled = CurrentUser.user.token_bucket.throttled?
headers["X-Api-Limit"] = CurrentUser.user.token_bucket.token_count.to_s
if throttled
respond_to do |format|
format.json do
render json: {success: false, reason: "too many requests"}.to_json, status: 429
end
format.xml do
render xml: {success: false, reason: "too many requests"}.to_xml(:root => "response"), status: 429
end
format.html do
render :template => "static/too_many_requests", :status => 429
end
end
return false
end
end
return true
end
def rescue_exception(exception)
@exception = exception
case exception
when ActiveRecord::QueryCanceled
render_error_page(500, exception, message: "The database timed out running your query.")
when ActiveRecord::RecordNotFound
render_error_page(404, exception, message: "That record was not found", expected: true)
when ActionController::UnknownFormat
@error_message = "#{request.format.to_s} is not a supported format for this page."
render "static/error.html", status: 406
when Danbooru::Paginator::PaginationError
render_error_page(410, exception, expected: true)
when NotImplementedError
render_error_page(501, exception, message: "This feature isn't available: #{exception.message}")
when PG::ConnectionBad
render_error_page(503, exception, message: "The database is unavailable. Try again later.")
else
render_error_page(500, exception)
end
end
def render_error_page(status, exception, message: exception.message, expected: false)
@error_message = message
DanbooruLogger.log(exception, expected: expected)
if request.format.symbol.in?(%i[html json xml js atom])
render template: "static/error", status: status
else
render template: "static/error.html", status: status
end
end
def authentication_failed
respond_to do |fmt|
fmt.html do
render :plain => "authentication failed", :status => 401
end
fmt.xml do
render :xml => {:sucess => false, :reason => "authentication failed"}.to_xml(:root => "response"), :status => 401
end
fmt.json do
render :json => {:success => false, :reason => "authentication failed"}.to_json, :status => 401
end
end
end
def access_denied(exception = nil)
previous_url = params[:url] || request.fullpath
respond_to do |fmt|
fmt.html do
if CurrentUser.is_anonymous?
if request.get?
redirect_to new_session_path(:url => previous_url), :notice => "Access denied"
else
redirect_to new_session_path, :notice => "Access denied"
end
else
render :template => "static/access_denied", :status => 403
end
end
fmt.xml do
render :xml => {:success => false, :reason => "access denied"}.to_xml(:root => "response"), :status => 403
end
fmt.json do
render :json => {:success => false, :reason => "access denied"}.to_json, :status => 403
end
fmt.js do
render js: "", :status => 403
end
end
end
def set_current_user
session_loader = SessionLoader.new(session, cookies, request, params)
session_loader.load
end
def reset_current_user
CurrentUser.user = nil
CurrentUser.ip_addr = nil
CurrentUser.root_url = root_url.chomp("/")
end
def set_started_at_session
if session[:started_at].blank?
session[:started_at] = Time.now
end
end
def set_variant
request.variant = params[:variant].try(:to_sym)
end
User::Roles.each do |role|
define_method("#{role}_only") do
if !CurrentUser.user.send("is_#{role}?") || CurrentUser.user.is_banned? || IpBan.is_banned?(CurrentUser.ip_addr)
access_denied
end
end
end
def set_title
@page_title = Danbooru.config.app_name + "/#{params[:controller]}"
end
# Remove blank `search` params from the url.
#
# /tags?search[name]=touhou&search[category]=&search[order]=
# => /tags?search[name]=touhou
def normalize_search
return unless request.get?
params[:search] ||= ActionController::Parameters.new
deep_reject_blank = lambda do |hash|
hash.reject { |k, v| v.blank? || (v.is_a?(Hash) && deep_reject_blank.call(v).blank?) }
end
nonblank_search_params = deep_reject_blank.call(params[:search])
if nonblank_search_params != params[:search]
params[:search] = nonblank_search_params
redirect_to url_for(params: params.except(:controller, :action, :index).permit!)
end
end
def search_params
params.fetch(:search, {}).permit!
end
def set_safe_mode
CurrentUser.set_safe_mode(request)
end
end