app/controllers/application_controller.rb
# -*- encoding : utf-8 -*-
# Filters added to this controller apply to all controllers in the application.
# Likewise, all the methods added will be available for all controllers.
class ApplicationController < ActionController::Base
helper :all # include all helpers, all the time
protect_from_forgery # See ActionController::RequestForgeryProtection for details
include AuthenticatedSystem
before_filter :set_locale,
:rss_token,
:set_client,
:confirmed_user?,
:load_project,
:load_organizations,
:login_required,
:touch_user,
:belongs_to_project?,
:load_community_organization,
:add_chrome_frame_header
# If the parameter ?nolayout=1 is passed, then we will render without a layout
# If the parameter ?extractparts=1 is passed, then we will render blocks for content and sidebar
layout proc { |controller|
if controller.params[:nolayout]
nil
else
controller.params[:extractparts] ? "parts" : "application"
end
}
private
def check_permissions
unless @current_project.editable?(current_user)
render :text => "You don't have permission to edit/update/delete within \"#{@current_project.name}\" project", :status => :forbidden
end
end
def handle_cancan_error(exception)
if request.xhr?
head :forbidden
else
flash[:error] = exception.message
redirect_to root_url
end
end
def handle_no_permissions
render :text => "You don't have permission to edit/update/delete within \"#{@current_project.name}\" project", :status => :forbidden
end
def confirmed_user?
if current_user and not current_user.is_active?
redirect_to unconfirmed_email_user_path(current_user)
end
end
def rss_token
unless params[:rss_token].nil? or !%w(rss ics).include?(params[:format])
user = User.find_by_rss_token(params[:rss_token])
set_current_user user if user
end
end
def belongs_to_project?
if @current_project and logged_in?
if current_user.projects.exists? @current_project
# user is a project member
unless @current_project.archived?
current_user.add_recent_project(@current_project)
end
elsif @current_project.invitations.exists?(:invited_user_id => current_user)
# there is an invitation pending for accept
redirect_to project_invitations_path(@current_project)
else
# sorry, no dice
if [:rss, :ics].include? request.formats.map(&:symbol)
render :nothing => true
else
respond_to do |f|
f.any(:html, :m) { render 'projects/not_in_project', :status => :forbidden }
end
end
end
end
end
def load_project
if project_id = params[:project_id] || params[:id]
unless @current_project = Project.find_by_id_or_permalink(project_id)
flash[:error] = t('not_found.project', :id => project_id)
redirect_to projects_path
end
end
end
# When you only belong to one organization, every page will be branded with its logo and colors.
# If you belong to 2+ organizations, common pages will not be branded and others will be organization branded
def load_organizations
if logged_in?
@organizations = current_user.organizations
@organization = case @organizations.size
when 0
current_user.projects.try(:first).try(:organization)
when 1
@organizations.first
else
@current_project.try(:organization)
end
end
end
def set_locale
locale = logged_in? ? current_user.locale : (params[:locale] || user_agent_locale)
I18n.locale = (locale.present? && I18n.available_locales.include?(locale.to_sym)) ? locale : I18n.default_locale
end
LOCALES_REGEX = /\b(#{ I18n.available_locales.join('|') })\b/
def user_agent_locale
unless (Rails.env.test? || Rails.env.cucumber?)
request.headers['HTTP_ACCEPT_LANGUAGE'].to_s =~ LOCALES_REGEX && $&
else
:en
end
end
def fragment_cache_key(key)
super(key).tap { |str|
str << "_#{I18n.locale}"
if logged_in? and current_user.time_zone?
str << "-#{current_user.time_zone.gsub(/\W/,'')}"
end
}
end
def touch_user
current_user.update_visited_at if logged_in?
end
def set_page_title
location_name = "#{params[:action]}_#{params[:controller]}"
translate_location_name = t("page_title.#{location_name}", :default => '')
if params.has_key?(:id) && ['show_projects','edit_projects'].include?(location_name)
project_name = @current_project.name
@page_title = h("#{project_name} — #{translate_location_name}")
elsif params.has_key?(:project_id)
project_name = @current_project.name
name = nil
case location_name
when 'show_tasks'
name = @task ? @task.name : nil
when 'show_task_lists'
name = @task_list ? @task_list.name : nil
when 'show_conversations'
name = @conversation ? @conversation.name : nil
when 'show_pages'
name = @page ? @page.name : nil
end
@page_title = h("#{project_name} — #{name || translate_location_name}")
else
name = nil
user_name = nil
case location_name
when 'edit_users'
user_name = current_user.name
when 'show_users'
user_name = @user.name
end
@page_title = h("#{user_name ? user_name + ' — ' : ''}#{translate_location_name}")
end
end
MobileClients = /(iPhone|iPod|Android|Opera mini|Blackberry|Palm|Windows CE|Opera mobi|iemobile|webOS|Mobile)/i
def set_client
if [:html, :m].include?(request.format.try(:to_sym)) and session[:format]
# Format has been forced by Sessions#change_format
request.format = session[:format].to_sym
else
# We should autodetect mobile clients and redirect if they ask for html
mobile = request.env["HTTP_USER_AGENT"] && request.env["HTTP_USER_AGENT"][MobileClients]
mobile ||= request.env["HTTP_PROFILE"] || request.env["HTTP_X_WAP_PROFILE"]
if mobile and request.format == :html
request.format = :m
end
end
end
def mobile?
request.format == :m
end
helper_method :mobile?
def iframe?
params[:iframe] == 'true'
end
def output_errors_json(record)
if request.xhr?
response.content_type = Mime::JSON
render :json => record.errors.as_json, :status => 400
elsif iframe?
render :template => 'shared/iframe_error', :layout => false, :locals => { :data => record.errors.as_json }
end
end
def split_events_by_date(events, start_date=nil)
start_date ||= Date.today.monday.to_date
split_events = Array.new
Array(events).each do |event|
if (event.due_on - start_date) >= 0
split_events[(event.due_on - start_date)] ||= []
split_events[(event.due_on - start_date)] << event
end
end
split_events
end
# http://www.coffeepowered.net/2009/02/16/powerful-easy-dry-multi-format-rest-apis-part-2/
def render(opts = nil, extra_options = {}, &block)
if opts && opts.is_a?(Hash) then
if opts[:to_yaml] or opts[:as_yaml] then
headers["Content-Type"] = "text/plain;"
text = nil
if opts[:as_yaml] then
text = Hash.from_xml(opts[:as_yaml]).to_yaml
else
text = Hash.from_xml(render_to_string(:template => opts[:to_yaml], :layout => false)).to_yaml
end
super opts.merge(:text => content, :layout => false)
elsif opts[:to_json] or opts[:as_json] then
content = nil
if opts[:to_json] then
content = Hash.from_xml(render_to_string(:template => opts[:to_json], :layout => false)).to_json
elsif opts[:as_json] then
content = Hash.from_xml(opts[:as_json]).to_json
end
cbparam = params[:callback] || params[:jsonp]
content = "#{cbparam}(#{content})" unless cbparam.blank?
super opts.merge(:json => content, :layout => false)
else
super(opts, extra_options, &block)
end
else
super(opts, extra_options, &block)
end
end
def handle_api_error(f,object)
error_list = object.nil? ? [] : object.errors
f.xml { render :xml => error_list.to_xml, :status => :unprocessable_entity }
f.json { render :as_json => error_list.to_xml, :status => :unprocessable_entity }
f.yaml { render :as_yaml => error_list.to_xml, :status => :unprocessable_entity }
end
def handle_api_success(f,object,is_new=false)
if is_new
f.xml { render :xml => object.to_xml, :status => :created }
f.json { render :as_json => object.to_xml, :status => :created }
f.yaml { render :as_yaml => object.to_xml, :status => :created }
else
f.xml { head :ok }
f.json { head :ok }
f.yaml { head :ok }
end
end
def calculate_position(obj)
options = {}
if pos = params[:position].presence
options[:id] = pos[:slot].to_i
if options[:id] < 0
options[:id] = 0
options[:before] = false
options[:footer] = true
else
options[:before] = options[:id] == 0 ? true : (pos[:before].to_i == 1)
options[:footer] = false
end
else
options[:id] = nil
options[:before] = true
options[:footer] = false
end
obj.slot_insert = options
end
def signups_enabled?
Teambox.config.allow_signups || User.count == 0
end
def time_tracking_enabled?
Teambox.config.allow_time_tracking || false
end
def load_community_organization
if logged_in? and Teambox.config.community
@community_organization = Organization.first
@community_role = if @community_organization
role_id = @community_organization.memberships.find_by_user_id(current_user.id).try(:role)
Membership::ROLES.index(role_id)
end
end
end
def h(text)
ERB::Util.h(text)
end
def add_chrome_frame_header
headers['X-UA-Compatible'] = 'chrome=1' if chrome_frame? && request.format == :html
end
def redirect_back_or_to(path)
begin
redirect_to :back
rescue ActionController::RedirectBackError
redirect_to path
end
end
def chrome_frame?
request.user_agent =~ /chromeframe/
end
helper_method :chrome_frame?
def set_time_zone
if logged_in?
Time.use_zone(current_user.time_zone) do
yield
end
else
yield
end
end
end