class Admin::MasterController < ApplicationController layout 'admin' include Typus::Authentication include Typus::Format include Typus::Locale include Typus::Reloader if Typus::Configuration.options[:ssl] include SslRequirement ssl_required :index, :new, :create, :edit, :show, :update, :destroy, :toggle, :position, :relate, :unrelate end filter_parameter_logging :password before_filter :reload_config_et_roles before_filter :require_login before_filter :set_locale before_filter :set_resource before_filter :find_item, :only => [ :show, :edit, :update, :destroy, :toggle, :position, :relate, :unrelate ] before_filter :check_ownership_of_item, :only => [ :edit, :update, :destroy, :toggle, :position, :relate, :unrelate ] before_filter :check_if_user_can_perform_action_on_user, :only => [ :edit, :update, :toggle, :destroy ] before_filter :check_if_user_can_perform_action_on_resource before_filter :set_order, :only => [ :index ] before_filter :set_fields, :only => [ :index, :new, :edit, :create, :update, :show ] ## # This is the main index of the model. With filters, conditions # and more. # # By default application can respond_to html, csv and xml, but you # can add your formats. # def index @conditions, @joins = @resource[:class].build_conditions(params) check_ownership_of_items if @resource[:class].typus_options_for(:only_user_items) respond_to do |format| format.html { generate_html } @resource[:class].typus_export_formats.each do |f| format.send(f) { send("generate_#{f}") } end end rescue Exception => error error_handler(error) end def new item_params = params.dup %w( controller action resource resource_id back_to selected ).each do |param| item_params.delete(param) end @item = @resource[:class].new(item_params.symbolize_keys) select_template :new end ## # Create new items. There's an special case when we create an # item from another item. In this case, after the item is # created we also create the relationship between these items. # def create @item = @resource[:class].new(params[:item]) if @item.attributes.include?(Typus.user_fk) @item.attributes = { Typus.user_fk => session[:typus_user_id] } end if @item.valid? create_with_back_to and return if params[:back_to] @item.save flash[:success] = _("{{model}} successfully created.", :model => @resource[:class].human_name) if @resource[:class].typus_options_for(:index_after_save) redirect_to :action => 'index' else redirect_to :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id end else select_template :new end end def edit item_params = params.dup %w( action controller model model_id back_to id resource resource_id ).each { |p| item_params.delete(p) } # We assign the params passed trough the url @item.attributes = item_params @previous, @next = @item.previous_and_next(item_params) select_template :edit end def show @previous, @next = @item.previous_and_next respond_to do |format| format.html { select_template :show } format.xml { render :xml => @item } end end def update if @item.update_attributes(params[:item]) flash[:success] = _("{{model}} successfully updated.", :model => @resource[:class].human_name) path = if @resource[:class].typus_options_for(:index_after_save) params[:back_to] ? "#{params[:back_to]}##{@resource[:self]}" : { :action => 'index' } else { :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id } end redirect_to path else @previous, @next = @item.previous_and_next select_template :edit end end def destroy @item.destroy flash[:success] = _("{{model}} successfully removed.", :model => @resource[:class].human_name) redirect_to :back rescue Exception => error error_handler(error, params.merge(:action => 'index', :id => nil)) end def toggle if @resource[:class].typus_options_for(:toggle) @item.toggle!(params[:field]) flash[:success] = _("{{model}} {{attribute}} changed.", :model => @resource[:class].human_name, :attribute => params[:field].humanize.downcase) else flash[:notice] = _("Toggle is disabled.") end redirect_to :back end ## # Change item position. This only works if acts_as_list is # installed. We can then move items: # # params[:go] = 'move_to_top' # # Available positions are move_to_top, move_higher, move_lower, # move_to_bottom. # def position @item.send(params[:go]) flash[:success] = _("Record moved {{to}}.", :to => params[:go].gsub(/move_/, '').humanize.downcase) redirect_to :back end ## # Relate a model object to another, this action is used only by the # has_and_belongs_to_many relationships. # def relate resource_class = params[:related][:model].constantize resource_tableized = params[:related][:model].tableize @item.send(resource_tableized) << resource_class.find(params[:related][:id]) flash[:success] = _("{{model_a}} related to {{model_b}}.", :model_a => resource_class.human_name, :model_b => @resource[:class].human_name) redirect_to :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id, :anchor => resource_tableized end ## # Remove relationship between models. # def unrelate resource_class = params[:resource].classify.constantize resource = resource_class.find(params[:resource_id]) case params[:association] when 'has_and_belongs_to_many' @item.send(resource_class.table_name).delete(resource) message = "{{model_a}} unrelated from {{model_b}}." when 'has_many', 'has_one' resource.destroy message = "{{model_a}} removed from {{model_b}}." end flash[:success] = _(message, :model_a => resource_class.human_name, :model_b => @resource[:class].human_name) redirect_to :controller => @resource[:self], :action => @resource[:class].typus_options_for(:default_action_on_item), :id => @item.id, :anchor => resource_class.table_name end private def set_resource resource = params[:controller].split('/').last @resource = { :self => resource, :class => resource.classify.constantize } rescue Exception => error error_handler(error) end ## # Find model when performing an edit, update, destroy, relate, # unrelate ... # def find_item @item = @resource[:class].find(params[:id]) end ## # If item is owned by another user, we only can perform a # show action on the item. Updated item is also blocked. # # before_filter :check_ownership_of_item, :only => [ :edit, :update, :destroy ] # def check_ownership_of_item # If current_user is a root user, by-pass. return if @current_user.is_root? # If the current model doesn't include a key which relates it with the # current_user, by-pass. return unless @item.respond_to?(Typus.user_fk) # If item is owned by the user ... unless @item.send(Typus.user_fk) == session[:typus_user_id] flash[:notice] = _("Record owned by another user.") redirect_to :action => 'show', :id => @item.id end end def check_ownership_of_items # If current_user is a root user, by-pass. return if @current_user.is_root? # If current user is not root and @resource has a foreign_key which # is related to the logged user (Typus.user_fk) we only show the user # related items. if @resource[:class].columns.map { |u| u.name }.include?(Typus.user_fk) condition = { Typus.user_fk => @current_user } @conditions = @resource[:class].merge_conditions(@conditions, condition) end end def set_fields @fields = case params[:action] when 'index' @resource[:class].typus_fields_for(:list) when 'new', 'edit', 'create', 'update' @resource[:class].typus_fields_for(:form) else @resource[:class].typus_fields_for(params[:action]) end end def set_order params[:sort_order] ||= 'desc' @order = params[:order_by] ? "#{@resource[:class].table_name}.#{params[:order_by]} #{params[:sort_order]}" : @resource[:class].typus_order_by end def select_template(template, resource = @resource[:self]) folder = (File.exist?("app/views/admin/#{resource}/#{template}.html.erb")) ? resource : 'resources' render "admin/#{folder}/#{template}" end ## # When params[:back_to] is defined this action is used. # # - has_and_belongs_to_many relationships. # - has_many relationships (polymorphic ones). # def create_with_back_to if params[:resource] && params[:resource_id] resource_class = params[:resource].classify.constantize resource_id = params[:resource_id] resource = resource_class.find(resource_id) association = @resource[:class].reflect_on_association(params[:resource].to_sym).macro rescue :polymorphic else association = :has_many end case association when :belongs_to @item.save when :has_and_belongs_to_many @item.save @item.send(params[:resource]) << resource when :has_many @item.save message = _("{{model}} successfully created.", :model => @resource[:class].human_name) path = "#{params[:back_to]}?#{params[:selected]}=#{@item.id}" when :polymorphic resource.send(@item.class.name.tableize).create(params[:item]) end flash[:success] = message || _("{{model_a}} successfully assigned to {{model_b}}.", :model_a => @item.class, :model_b => resource_class.name) redirect_to path || "#{params[:back_to]}##{@resource[:self]}" end def error_handler(error, path = admin_dashboard_path) raise error unless Rails.env.production? flash[:error] = "#{error.message} (#{@resource[:class]})" redirect_to path end end