lib/masterview/extras/app/controllers/masterview_controller.rb in masterview-0.1.5 vs lib/masterview/extras/app/controllers/masterview_controller.rb in masterview-0.2.0
- old
+ new
@@ -1,17 +1,77 @@
+#
+# == MasterView Admin Controller
+#
+# The MasterviewController is a Rails controller that you can enable
+# in your Rails application to provide administrative operations
+# for the MasterView template engine.
+#
+# To enable or disable the admin controller, use the
+# MasterView::Configuration setting +enable_admin_pages+
+# to enable or disable its availability in your
+# config/masterview/settngs.rb or a suitable environment
+# settings file, according to your intended usage:
+#
+# config.enable_admin_pages = true
+#
+# When enabled, the MasterView admin controller is accessable
+# in your application at the address:
+#
+# http://yourapp.foo/masterview
+#
+# The controller places its stylesheets in a +masterview+ subdirectory
+# in your rails stylesheets directory (app/stylesheets/masterview).
+#
+# The MasterView admin controller is primarily a developer facility;
+# it is not generally appropriate for end-users of your rails application.
+# If you enable this facility in your production environment,
+# you should consider restricting access to authorized users.
+#
+#--
+# ISSUE: we need to work through scenario of how mv admin controller fits
+# into overall scheme of one's rails application. How/when would developer
+# integrate stylesheets and layout into their overal app look?
+# How/when would access restriction actually be hooked up?
+# Standard technique is to do something along the lines of using
+# a before_filter which invokes things like :check_authentication
+# and :check_authorization services in the app framework
+# (or, say, predicate can_access? or has_permission? or...].
+# But... this whole area of user authentication and authorization
+# has no specific conventions in the Rails ecosystem yet,
+# so we really can't make any assumptions yet about any particular
+# approach that MasterviewController itself could hook into.
+# We'll have to leave this as an exercise for the user and give
+# them tips on how to make it happen.
+# [DJL 17-Jun-2006]
+#++
+#
class MasterviewController < ApplicationController
+
+ before_filter :check_authorization, :except => [ :access_not_allowed ]
+
+ # Describe the MasterView configuration option settings
+ def configuration
+ render :text => configuration_html, :layout => true
+ end
def index
redirect_to :action => :list
end
+ # List the templates in the application and their status.
+ # Provide operations to force rebuild (reparse and regenerate)
+ # of specific templates or all templates and
+ # create utility to ...mumble...
+ #
def list
template_specs, content_hash = MasterView::TemplateSpec.scan
@template_specs_sorted = template_specs.sort
smart_render 'masterview/admin/list'
end
+ # Rebuild all templates in the application.
+ # Invoked from the main masterview admin page.
def rebuild_all
files_rebuilt = []
MasterView::TemplateSpec.scan do |template_spec, content_hash|
if template_spec.status == MasterView::TemplateSpec::Status::ImportsOutdated &&
template_spec.rebuild_template(content_hash, :write_to_file => true)
@@ -22,10 +82,12 @@
flash[:notice] = files_rebuilt.join(', ')+' were updated'
end
redirect_to :action => :list
end
+ # Rebuild a specific template.
+ # Invoked from the main masterview admin page.
def rebuild
path = params[:id]
template_specs, content_hash = MasterView::TemplateSpec.scan
template_spec = template_specs[path]
raise 'Template '+path+' not found' unless template_spec
@@ -35,24 +97,114 @@
flash[:notice] = 'Identical content - no update needed for '+path
end
redirect_to :action => :list
end
+ # Create a new, empty template.
+ # Invoked from the main masterview admin page.
def create
if @request.post?
action_to_create = params[:action_name]
- short_name = File.basename(params[:id])
- src_file = File.join('app/views', MasterView::TemplateSrcRelativePath, short_name)
+ src_file = params[:id]
empty_file_path = find_path('app/views/masterview/admin/empty.rhtml')
empty_insert_erb = File.readlines(empty_file_path).join
dst_file = MasterView::TemplateSpec.create_empty_shell_for_action(src_file, action_to_create, empty_insert_erb, :write_to_file => true)
flash[:notice] = dst_file+' was created'
redirect_to :action => :list
else
smart_render 'masterview/admin/create'
end
+ end
+
+ # View the generated rhtml
+ def view_rhtml
+ raise "View RHTML is disabled. Edit your config/masterview/settings.rb (or config/masterview/environments/xxxx.rb) file and set config.enable_view_rhtml = true. Restart application for change to take effect." unless MasterView::EnableMasterViewAdminViewRHTML
+ @rhtml_file = params[:id]
+ raise "RHTML file not specified" unless @rhtml_file
+ f = MasterView::IOMgr.erb.path(@rhtml_file)
+ raise "RHTML file ("+@rhtml_file+") not found. Maybe automatic parsing is disabled. You may invoke parsing manually by using rake mv:parse" unless f.exist?
+ @rhtml_content = f.read
+ smart_render 'masterview/admin/view_rhtml'
+ end
+
+ def access_not_allowed #:nodoc:
+ render :text => '<p>We\'re sorry, but the page you have requested is only available to authorized users.</p>',
+ :status => 500
+ end
+
+ protected
+
+ # Default implementation of authorization check
+ # to restrict access to administrative services
+ def allow_access?
+ # a more general solution might look something like:
+ # current_user && user_has_perm?('mv-admin')
+ # backstop: only allow for developer testing on local machine
+ local_request?
+ end
+
+ # Check that the current user has authorization to access admin operations
+ def check_authorization
+ if ! allow_access?
+ redirect_to :action => :access_not_allowed
+ end
+ end
+
+ # Answer an HTML rendering of the current MasterView configuration
+ def configuration_html
+ # This is a quick-and-dirty impl until a more elegant solution is provided
+ #e.g. do something more like Rails::Info
+
+ config = MasterView::ConfigSettings
+
+ section_general_options = 'General Options'
+ section_specs = [
+ # [ <section-name>, [prop-name [, prop-name]... ] ]
+ [ 'MasterView Roots',
+ [ :mv_installation_dir, :rails_app?, :on_rails? ] ],
+ [ section_general_options,
+ [ :root_path, :config_dir_path, :environment ] ], #:directive_paths
+ [ 'Template Source Options',
+ [ :template_src_dir_path, :template_filename_pattern ] ],
+ [ 'Template Generation Options',
+ [ :template_dst_dir_path, :output_filename_extension, :generated_file_default_extension, :include_generated_file_comment ] ],
+ [ 'Template Parsing Options',
+ [ :default_parser_options, :namespace_prefix ] ],
+ [ 'Rails Application Options',
+ [ :parse_masterview_templates_at_startup, :reparse_changed_masterview_templates, :generate_rhtml_files ] ]
+ ]
+
+ #"<h1>MasterView Configuration</h1>\n<table>\n<tbody>\n#{html}</tbody>\n</table>\n<div style=\"padding-top: 6px;\">(back to <a href=\".\">Admin home</a>)</div>"
+ html_config_settings = "<h1>MasterView Configuration</h1>\n<table>\n<tbody>\n%s</tbody>\n</table>\n<div style=\"padding-top: 6px;\">(back to <a href=\".\">Admin home</a>)</div>" % '%s'
+
+ #"<tr style=\"background-color: #dcdcdc; font-weight: bold; margin-top: 6px;\"><td colspan=\"2\">#{section_name}</td></tr>"
+ html_subsection_entry = '<tr style="background-color: #dcdcdc; font-weight: bold; margin-top: 6px;"><td colspan="2">%s</td></tr>' #parm: section_name
+
+ # "<tr><td><b>#{option_name}</b></td><td>#{option_value}</td></tr>"
+ html_option_entry = '<tr><td style="padding-left: 6px; padding-right: 6px; font-weight: bold;">%s</td><td>%s</td></tr>' #parms: option_name, option_value
+
+ html = []
+ section_specs.each { | section_name, options |
+ html << html_subsection_entry % section_name
+ options.each { | option |
+ option_name = CGI.escapeHTML(option.to_s)
+ option_value = config.send(option)
+ #tbd: option_value.kind_of?(Hash) then make it pretty?
+ option_value = option_value.nil? ? '(nil)' : CGI.escapeHTML(option_value.inspect)
+ html << html_option_entry % [ option_name, option_value ]
+ }
+ if section_name == section_general_options
+ option_name = 'logger'
+ option_value = MasterView::Log.class.name
+ html << html_option_entry % [ option_name, option_value ]
+ option_name = 'log_level'
+ option_value = MasterView.log_level
+ html << html_option_entry % [ option_name, option_value ]
+ end
+ }
+ html_config_settings % html.join("\n")
end
private
# checks app path first for views and files, then falls back to files in MV