module Symphonia module ControllerExtensions extend ActiveSupport::Concern class Unauthorized < RuntimeError end included do before_action :current_user, :menu_item before_action :set_default_locale add_flash_types :notice add_flash_types :info add_flash_types :warning add_flash_types :error rescue_from ::ActiveRecord::RecordNotFound, with: :render_404 rescue_from Unauthorized, CanCan::AccessDenied, with: :render_403 rescue_from ActionController::InvalidAuthenticityToken do |_exception| head :service_unavailable end helper_method :current_user, :back_url end def back_url url = params[:back_url].presence if url.nil? && (referer = request.env["HTTP_REFERER"].presence) url = CGI.unescape(referer.to_s) end url end # Redirects to the request referer if present, redirects to args or call block otherwise. def redirect_to_referer_or(*args, &block) redirect_to :back rescue ::ActionController::RedirectBackError if args.any? redirect_to(*args) elsif block_given? block.call else raise "#redirect_to_referer_or takes arguments or a block" end end # private def set_locale params_locale = params.fetch(:locale, nil).presence params_locale ||= session[:locale].presence params_locale ||= request.env["HTTP_ACCEPT_LANGUAGE"].to_s.split(",").collect { |l| l.scan(/^[a-z]{2}/) }.flatten client_lang = Array(params_locale).compact client_lang.unshift current_user.language if current_user.language @client_lang = client_lang.detect { |l| I18n.available_locales.include?(l.to_sym) } I18n.locale = (@client_lang || I18n.default_locale) session[:locale] = I18n.locale logger.debug "* Locale set to '#{I18n.locale}'" end def set_default_locale return unless (enforce_default = Symphonia.config.default_locale) I18n.locale = enforce_default end # protected def login_require(_format = nil) if current_user.nil? || !current_user.logged_in? respond_to do |format| format.html do store_location redirect_to symphonia.login_path, flash: { error: t(:text_login_require) } end format.json do render json: { errors: "You must be logged in to access this endpoint" }, status: :unauthorized end format.any { head :unauthorized } end return false end true end alias require_login login_require alias require_user login_require def admin_require return unless login_require return if current_user.admin? render_403 false end alias require_admin admin_require def render_403 respond_to do |format| format.html { render template: "common/403", message: :notice_not_authorized, status: :forbidden } format.js do render plain: "alert('#{t :text_access_deny}')", message: :notice_not_authorized, status: :forbidden end format.any { head :forbidden, message: :notice_not_authorized } end end def render_404 respond_to do |format| format.html { render template: "common/404", message: :notice_page_not_found, status: :not_found } format.any { head :not_found, message: :not_found } end end # Renders a 200 response for successful updates or deletions via the API def render_api_ok render_api_head :ok end # Renders a head API response def render_api_head(status) head status end def menu_item(item = nil) @menu_item = item || controller_name end def current_user_session return @current_user_session if defined?(@current_user_session) @current_user_session = UserSession.find end def current_user return (Symphonia::User.current ||= @current_user) if defined?(@current_user) @current_user = current_user_session&.user Symphonia::User.current = @current_user || Symphonia::User::Anonymous.new end def authorize return true if Symphonia::User.current.admin? raise Unauthorized if Symphonia::User.current.logged_in? login_require end def handle_unverified_request return true if current_user&.logged_in? && request.format&.json? current_user_session&.destroy # raise ActionController::InvalidAuthenticityToken super end def store_location session[:return_to] = request.url end def redirect_back_or_default(default, options = {}) options ||= {} redirect_to(params[:back_url] || default, options) end end end