Implemented routing filter for foodcoop select.

* Allows now a multi coop installation for one domain!
* SSL, we are coming...
* TODO: Remove all the hardcoded urls, check email-links etc.
This commit is contained in:
Benjamin Meichsner 2010-03-20 02:26:30 +01:00
parent b9576dd669
commit e7af7e82b5
4 changed files with 151 additions and 105 deletions

View file

@ -23,128 +23,133 @@ class ApplicationController < ActionController::Base
protected protected
def current_user def current_user
begin begin
# check if there is a valid session and return the logged-in user (its object) # check if there is a valid session and return the logged-in user (its object)
if session['user_and_subdomain'] if session['user_and_subdomain']
id, subdomain = session['user_and_subdomain'].split id, subdomain = session['user_and_subdomain'].split
# for shared-host installations. check if the cookie-subdomain fits to request. # for shared-host installations. check if the cookie-subdomain fits to request.
return User.current_user = User.find(id) if request.subdomains.first == subdomain return User.current_user = User.find(id) if request.subdomains.first == subdomain
end
rescue
reset_session
flash[:error]= _("An error has occurred. Please login again.")
redirect_to :controller => 'login'
end end
rescue
reset_session
flash[:error]= _("An error has occurred. Please login again.")
redirect_to :controller => 'login'
end end
end
def current_user=(user) def current_user=(user)
session['user_and_subdomain'] = [user.id, request.subdomains.first].join(" ") session['user_and_subdomain'] = [user.id, request.subdomains.first].join(" ")
end end
def return_to def return_to
session['return_to'] session['return_to']
end end
def return_to=(uri) def return_to=(uri)
session['return_to'] = uri session['return_to'] = uri
end end
def deny_access def deny_access
self.return_to = request.request_uri self.return_to = request.request_uri
redirect_to :controller => '/login', :action => 'denied' redirect_to :controller => '/login', :action => 'denied'
return false return false
end end
private private
def authenticate(role = 'any') def authenticate(role = 'any')
# Attempt to retrieve authenticated user from controller instance or session... # Attempt to retrieve authenticated user from controller instance or session...
if !(user = current_user) if !(user = current_user)
# No user at all: redirect to login page. # No user at all: redirect to login page.
self.return_to = request.request_uri self.return_to = request.request_uri
redirect_to :controller => '/login' redirect_to :controller => '/login'
return false return false
else
# We have an authenticated user, now check role...
# Roles gets the user through his memberships.
hasRole = case role
when "admin" then user.role_admin?
when "finance" then user.role_finance?
when "article_meta" then user.role_article_meta?
when "suppliers" then user.role_suppliers?
when "orders" then user.role_orders?
when "any" then true # no role required
else false # any unknown role will always fail
end
if hasRole
@current_user = user
else else
# We have an authenticated user, now check role... deny_access
# Roles gets the user through his memberships.
hasRole = case role
when "admin" then user.role_admin?
when "finance" then user.role_finance?
when "article_meta" then user.role_article_meta?
when "suppliers" then user.role_suppliers?
when "orders" then user.role_orders?
when "any" then true # no role required
else false # any unknown role will always fail
end
if hasRole
@current_user = user
else
deny_access
end
end
end
def authenticate_admin
authenticate('admin')
end
def authenticate_finance
authenticate('finance')
end
def authenticate_article_meta
authenticate('article_meta')
end
def authenticate_suppliers
authenticate('suppliers')
end
def authenticate_orders
authenticate('orders')
end
# checks if the current_user is member of given group.
# if fails the user will redirected to startpage
def authenticate_membership_or_admin
@group = Group.find(params[:id])
unless @group.member?(@current_user) or @current_user.role_admin?
flash[:error] = "Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!"
if request.xml_http_request?
render(:update) {|page| page.redirect_to root_path }
else
redirect_to root_path
end
end end
end end
end
# Stores this controller instance as a thread local varibale to be accessible from outside ActionController/ActionView.
def store_controller
Thread.current[:application_controller] = self
end
# Sets the thread local variable that holds a reference to the current controller to nil. def authenticate_admin
def remove_controller authenticate('admin')
Thread.current[:application_controller] = nil end
end
def authenticate_finance
authenticate('finance')
end
def authenticate_article_meta
authenticate('article_meta')
end
# Get supplier in nested resources def authenticate_suppliers
def find_supplier authenticate('suppliers')
@supplier = Supplier.find(params[:supplier_id]) if params[:supplier_id] end
end
# Set config and database connection for each request def authenticate_orders
# It uses the subdomain to select the appropriate section in the config files authenticate('orders')
# Use this method as a before filter (first filter!) in ApplicationController end
def select_foodcoop
if Foodsoft.config[:multi_coop_install] # checks if the current_user is member of given group.
# Get subdomain # if fails the user will redirected to startpage
subdomain = request.subdomains.first def authenticate_membership_or_admin
@group = Group.find(params[:id])
unless @group.member?(@current_user) or @current_user.role_admin?
flash[:error] = "Diese Aktion ist nur für Mitglieder der Gruppe erlaubt!"
if request.xml_http_request?
render(:update) {|page| page.redirect_to root_path }
else
redirect_to root_path
end
end
end
# Stores this controller instance as a thread local varibale to be accessible from outside ActionController/ActionView.
def store_controller
Thread.current[:application_controller] = self
end
# Sets the thread local variable that holds a reference to the current controller to nil.
def remove_controller
Thread.current[:application_controller] = nil
end
# Get supplier in nested resources
def find_supplier
@supplier = Supplier.find(params[:supplier_id]) if params[:supplier_id]
end
# Set config and database connection for each request
# It uses the subdomain to select the appropriate section in the config files
# Use this method as a before filter (first filter!) in ApplicationController
def select_foodcoop
if Foodsoft.config[:multi_coop_install]
if !params[:foodcoop].blank?
# Set Config # Set Config
Foodsoft.env = subdomain Foodsoft.env = params[:foodcoop]
# Set database-connection # Set database-connection
ActiveRecord::Base.establish_connection(Foodsoft.database(subdomain)) ActiveRecord::Base.establish_connection(Foodsoft.database)
else
redirect_to root_path
end end
else
# Deactivate routing filter
RoutingFilter::Foodcoop.active = false
end end
end
end end

View file

@ -68,6 +68,7 @@ Rails::Initializer.run do |config|
config.gem "fastercsv" config.gem "fastercsv"
config.gem "prawn" config.gem "prawn"
config.gem "haml", :version => '>=2.0.6' config.gem "haml", :version => '>=2.0.6'
config.gem "routing-filter", :lib => "routing_filter"
# The internationalization framework can be changed to have another default locale (standard is :en) or more load paths. # The internationalization framework can be changed to have another default locale (standard is :en) or more load paths.
# All files from config/locales/*.rb,yml are added automatically. # All files from config/locales/*.rb,yml are added automatically.

View file

@ -1,4 +1,7 @@
ActionController::Routing::Routes.draw do |map| ActionController::Routing::Routes.draw do |map|
map.filter 'foodcoop', :file => File.join(RAILS_ROOT, "lib", "foodcoop_filter")
map.resources :pages, :collection => { :all => :get }, :member => {:version => :get, :revert => :get} map.resources :pages, :collection => { :all => :get }, :member => {:version => :get, :revert => :get}
map.wiki_page "/wiki/:permalink", :controller => 'pages', :action => 'show', :permalink => /[^\s]+/ map.wiki_page "/wiki/:permalink", :controller => 'pages', :action => 'show', :permalink => /[^\s]+/
map.wiki "/wiki", :controller => 'pages', :action => 'show', :permalink => 'Home' map.wiki "/wiki", :controller => 'pages', :action => 'show', :permalink => 'Home'

37
lib/foodcoop_filter.rb Normal file
View file

@ -0,0 +1,37 @@
require 'routing_filter/base'
module RoutingFilter
class Foodcoop < Base
def around_recognize(path, env, &block)
token = extract_token!(path) # remove the token from the beginning of the path
returning yield do |params| # invoke the given block (calls more filters and finally routing)
params[:foodcoop] = token if token # set recognized token to the resulting params hash
end
end
def around_generate(*args, &block)
token = args.extract_options!.delete(:foodcoop) # extract the passed :token option
token = Foodsoft.env if token.nil? # default to Foodsoft.env
returning yield do |result|
if token
url = result.is_a?(Array) ? result.first : result
prepend_token!(url, token)
end
end
end
protected
def extract_token!(path)
foodcoop = nil
path.sub! %r(^/([a-zA-Z0-9]*)(?=/|$)) do foodcoop = $1; '' end
foodcoop
end
def prepend_token!(url, token)
url.sub!(%r(^(http.?://[^/]*)?(.*))) { "#{$1}/#{token}#{$2}" }
end
end
end