-
-
Notifications
You must be signed in to change notification settings - Fork 256
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into feature/hw-combobox-field
- Loading branch information
Showing
33 changed files
with
1,351 additions
and
1,631 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,340 +1,4 @@ | ||
module Avo | ||
class ApplicationController < ::ActionController::Base | ||
if defined?(Pundit::Authorization) | ||
Avo::ApplicationController.include Pundit::Authorization | ||
elsif defined?(Pundit) | ||
Avo::ApplicationController.include Pundit | ||
end | ||
|
||
include Avo::InitializesAvo | ||
include Avo::CommonController | ||
include Avo::ApplicationHelper | ||
include Avo::UrlHelpers | ||
include Avo::Concerns::Breadcrumbs | ||
include Avo::Concerns::FindAssociationField | ||
|
||
protect_from_forgery with: :exception | ||
around_action :set_avo_locale | ||
around_action :set_force_locale, if: -> { params[:force_locale].present? } | ||
before_action :init_app | ||
before_action :set_active_storage_current_host | ||
before_action :set_resource_name | ||
before_action :_authenticate! | ||
before_action :set_authorization | ||
before_action :set_container_classes | ||
before_action :add_initial_breadcrumbs | ||
before_action :set_view | ||
before_action :set_sidebar_open | ||
before_action :set_stylesheet_assets_path | ||
|
||
rescue_from Avo::NotAuthorizedError, with: :render_unauthorized | ||
rescue_from ActiveRecord::RecordInvalid, with: :exception_logger | ||
|
||
helper_method :_current_user, :resources_path, :resource_path, :new_resource_path, :edit_resource_path, :resource_attach_path, :resource_detach_path, :related_resources_path, :turbo_frame_request?, :resource_view_path, :preview_resource_path | ||
add_flash_types :info, :warning, :success, :error | ||
|
||
def exception_logger(exception) | ||
respond_to do |format| | ||
format.html { raise exception } | ||
format.json { | ||
render json: { | ||
errors: (exception.respond_to?(:record) && exception.record.present?) ? exception.record.errors : [], | ||
message: exception.message, | ||
traces: exception.backtrace | ||
}, status: ActionDispatch::ExceptionWrapper.status_code_for_exception(exception.class.name) | ||
} | ||
end | ||
end | ||
|
||
# This is coming from Turbo::Frames::FrameRequest module. | ||
# Exposing it as public method | ||
def turbo_frame_request? | ||
super | ||
end | ||
|
||
private | ||
|
||
# Get the pluralized resource name for this request | ||
# Ex: projects, teams, users | ||
def resource_name | ||
return params[:resource_name] if params[:resource_name].present? | ||
|
||
return controller_name if controller_name.present? | ||
|
||
begin | ||
request.path | ||
.match(/\/?#{Avo.root_path.delete("/")}\/resources\/([a-z1-9\-_]*)\/?/mi) | ||
.captures | ||
.first | ||
rescue | ||
end | ||
end | ||
|
||
def related_resource_name | ||
params[:related_name] | ||
end | ||
|
||
# Gets the Avo resource for this request based on the request from the `resource_name` "param" | ||
# Ex: Avo::Resources::Project, Avo::Resources::Team, Avo::Resources::User | ||
def resource | ||
resource = Avo.resource_manager.get_resource @resource_name.to_s.camelize.singularize | ||
|
||
return resource if resource.present? | ||
|
||
Avo.resource_manager.get_resource_by_controller_name @resource_name | ||
end | ||
|
||
def related_resource | ||
# Find the field from the parent resource | ||
field = find_association_field(resource: @resource, association: params[:related_name]) | ||
|
||
return field.use_resource if field&.use_resource.present? | ||
|
||
reflection = @record.class.reflect_on_association(field&.for_attribute || params[:related_name]) | ||
|
||
reflected_model = reflection.klass | ||
|
||
Avo.resource_manager.get_resource_by_model_class reflected_model | ||
end | ||
|
||
def set_resource_name | ||
@resource_name = resource_name | ||
end | ||
|
||
def set_related_resource_name | ||
@related_resource_name = related_resource_name | ||
end | ||
|
||
def set_resource | ||
raise ActionController::RoutingError.new "No route matches" if resource.nil? | ||
|
||
@resource = resource.new(view: params[:view].presence || action_name.to_s, user: _current_user, params: params) | ||
|
||
set_authorization | ||
end | ||
|
||
def detect_fields | ||
@resource.detect_fields | ||
end | ||
|
||
def set_related_resource | ||
raise Avo::MissingResourceError.new(related_resource_name) if related_resource.nil? | ||
|
||
action_view = action_name.to_sym | ||
|
||
# Get view from params unless actions is index or show or forms... | ||
# Else, for example for detach action we want the view from params to can fetch the correct fields | ||
# This logic avoid the following scenario: | ||
# When a has many field is rendered the action is index and params[:view] is show or edit but we want to | ||
# keep @view as index for the related_resource | ||
# Same do not happen with other actions except the list below. | ||
view = if action_view.in?([:index, :show, :new, :edit, :create]) | ||
action_view | ||
else | ||
params[:view].presence || action_view | ||
end | ||
|
||
@related_resource = related_resource.new( | ||
params: params, | ||
view: view, | ||
user: _current_user, | ||
record: @related_record | ||
).detect_fields | ||
end | ||
|
||
def set_record | ||
id = if @resource.model_class.primary_key.is_a?(Array) && params.respond_to?(:extract_value) | ||
params.extract_value(:id) | ||
else | ||
params[:id] | ||
end | ||
|
||
@record = @resource.find_record(id, query: model_scope, params:) | ||
@resource.hydrate(record: @record) | ||
end | ||
|
||
def set_related_record | ||
association_name = BaseResource.valid_association_name(@record, params[:related_name]) | ||
@related_record = if @field.is_a? Avo::Fields::HasOneField | ||
@record.send association_name | ||
else | ||
@related_resource.find_record params[:related_id], query: @record.send(association_name), params: params | ||
end | ||
@related_resource.hydrate(record: @related_record) | ||
end | ||
|
||
def model_scope | ||
# abort @resource.inspect | ||
@resource.class.find_scope | ||
end | ||
|
||
# Force actions to have specific view | ||
unless defined? VIEW_ACTION_MAPPING | ||
VIEW_ACTION_MAPPING = { | ||
update: :edit, | ||
create: :new | ||
} | ||
end | ||
|
||
def set_view | ||
@view = Avo::ViewInquirer.new(VIEW_ACTION_MAPPING[action_name.to_sym] || action_name) | ||
end | ||
|
||
def set_record_to_fill | ||
@record_to_fill = if @view.new? | ||
@resource.model_class.new | ||
elsif @view.edit? | ||
@record | ||
end | ||
|
||
# If resource.record is nil, most likely the user is creating a new record. | ||
# In that case, to access resource.record in visible and readonly blocks we hydrate the resource with a new record. | ||
# TODO: commented this | ||
@resource.hydrate(record: @record_to_fill) if @resource.record.nil? | ||
end | ||
|
||
def fill_record | ||
# We have to skip filling the the record if this is an attach action | ||
return if is_attach_action? | ||
|
||
@record = @resource.fill_record(@record_to_fill, cast_nullable(model_params), extra_params: extra_params) | ||
assign_default_value_to_disabled_fields if @view.create? | ||
end | ||
|
||
def is_attach_action? | ||
params[model_param_key].blank? && params[:related_name].present? && params[:fields].present? | ||
end | ||
|
||
def assign_default_value_to_disabled_fields | ||
@resource.get_field_definitions.select do |field| | ||
field.is_disabled? && field.visible? && !field.computed | ||
end.each do |field| | ||
# Get the default value from the field default definition | ||
# If there is no default value specified on the resource, get the value from the record (DB, Callbacks, etc.) | ||
default_value = field.default || @record.send(field.id) | ||
field.fill_field @record, field.id, default_value, params | ||
end | ||
end | ||
|
||
def authorize_base_action | ||
class_to_authorize = @record || @resource.model_class | ||
|
||
authorize_action class_to_authorize | ||
end | ||
|
||
def authorize_action(class_to_authorize, action = nil) | ||
# Use the provided action or figure it out from the request | ||
action_to_authorize = action || action_name | ||
|
||
@authorization.set_record(class_to_authorize).authorize_action action_to_authorize.to_sym | ||
end | ||
|
||
def _authenticate! | ||
instance_eval(&Avo.configuration.authenticate) | ||
end | ||
|
||
def render_unauthorized(exception) | ||
flash[:notice] = t "avo.not_authorized" | ||
|
||
redirect_url = if request.referrer.blank? || (request.referrer == request.url) | ||
root_url | ||
else | ||
request.referrer | ||
end | ||
|
||
redirect_to(redirect_url) | ||
end | ||
|
||
def set_authorization | ||
# We need to set @resource_name for the #resource method to work properly | ||
set_resource_name | ||
@authorization = if @resource | ||
@resource.authorization(user: _current_user) | ||
else | ||
Services::AuthorizationService.new _current_user | ||
end | ||
end | ||
|
||
def set_container_classes | ||
contain = true | ||
|
||
if Avo.configuration.full_width_container | ||
contain = false | ||
elsif Avo.configuration.full_width_index_view && action_name.to_sym == :index && self.class.superclass.to_s == "Avo::ResourcesController" | ||
contain = false | ||
end | ||
|
||
@container_classes = contain ? "2xl:container 2xl:mx-auto" : "" | ||
end | ||
|
||
def add_initial_breadcrumbs | ||
instance_eval(&Avo.configuration.initial_breadcrumbs) if Avo.configuration.initial_breadcrumbs.present? | ||
end | ||
|
||
def model_param_key | ||
@resource.form_scope | ||
end | ||
|
||
# Sets the locale set in avo.rb initializer or if to something that the user set using the `?set_locale=pt-BR` param | ||
def set_avo_locale(&action) | ||
locale = Avo.configuration.default_locale | ||
|
||
if params[:set_locale].present? | ||
locale = params[:set_locale] | ||
Avo.configuration.locale = locale | ||
end | ||
|
||
I18n.with_locale(locale, &action) | ||
end | ||
|
||
# Temporary set the locale and reverting at the end of the request. | ||
def set_force_locale(&action) | ||
I18n.with_locale(params[:force_locale], &action) | ||
end | ||
|
||
def set_sidebar_open | ||
value = cookies["#{Avo::COOKIES_KEY}.sidebar.open"] | ||
@sidebar_open = value.blank? || value == "1" | ||
end | ||
|
||
# Set the current host for ActiveStorage | ||
def set_active_storage_current_host | ||
if defined?(ActiveStorage::Current) | ||
if Rails::VERSION::MAJOR === 6 | ||
ActiveStorage::Current.host = request.base_url | ||
elsif Rails::VERSION::MAJOR === 7 | ||
ActiveStorage::Current.url_options = {protocol: request.protocol, host: request.host, port: request.port} | ||
end | ||
end | ||
rescue => exception | ||
Avo.logger.debug "Failed to set ActiveStorage::Current.url_options, #{exception.inspect}" | ||
end | ||
|
||
def set_stylesheet_assets_path | ||
# Prefer the user's tailwind config if it exists, otherwise use the default one from Avo | ||
@stylesheet_assets_path = if Rails.root.join("config", "avo", "tailwind.config.js").exist? | ||
"avo.tailwind" | ||
elsif Avo::PACKED | ||
"/avo-assets/avo.base" | ||
else | ||
"avo.base" | ||
end | ||
end | ||
|
||
def choose_layout | ||
if turbo_frame_request? | ||
"avo/blank" | ||
else | ||
"avo/application" | ||
end | ||
end | ||
|
||
def authenticate_developer_or_admin! | ||
raise_404 unless Avo::Current.user_is_developer? || Avo::Current.user_is_admin? | ||
end | ||
|
||
def raise_404 | ||
raise ActionController::RoutingError.new "No route matches" | ||
end | ||
class ApplicationController < BaseApplicationController | ||
end | ||
end |
Oops, something went wrong.