mirror of
https://github.com/TracksApp/tracks.git
synced 2025-12-24 11:10:12 +01:00
Also, for developers: two new gems are required for running tests: zentest and flexmock. I applied James Kebinger's patch to add starred actions. These are implemented behind the scenes as a tag, so you can see all starred actions the way you would look at actions for any tag. Closes #387. Thanks, James! Tests now rely the ZenTest gem. Thanks Ryan Davis & Eric Hodel. I improved test coverage of a few models and created a test for the new helper methods to support the stars. (Helper method tests are made possible by ZenTest. The helper tests use mock objects to isolate them, courtesy of flexmock. Thanks, Jim Weirich!) Modified a few selenium tests to work properly with mysql. Upgraded the has_many_polymorphs plugin. Add rails_rcov plugin to get test coverage numbers more easily. Convert toggle_check action to correspond to a PUT instead of a POST (follows CRUD<->HTTP mapping better). I'm having some issues running tests with sqlite3 that I haven't been able to figure out. I'll work on it, but wanted to check in so I can check out and work from the beach this weekend. Happy holiday weekend to those of you in the U.S.! git-svn-id: http://www.rousette.org.uk/svn/tracks-repos/trunk@544 a4c988fc-2ded-0310-b66e-134b36920a42
211 lines
7 KiB
Ruby
211 lines
7 KiB
Ruby
# The filters added to this controller will be run for all controllers in the application.
|
|
# Likewise will all the methods added be available for all controllers.
|
|
|
|
require_dependency "login_system"
|
|
require_dependency "source_view"
|
|
require "redcloth"
|
|
|
|
require 'date'
|
|
require 'time'
|
|
#Tag # We need this in development mode, or you get 'method missing' errors
|
|
|
|
class ApplicationController < ActionController::Base
|
|
|
|
helper :application
|
|
include LoginSystem
|
|
|
|
layout proc{ |controller| controller.mobile? ? "mobile" : "standard" }
|
|
|
|
before_filter :set_session_expiration
|
|
prepend_before_filter :login_required
|
|
prepend_before_filter :enable_mobile_content_negotiation
|
|
after_filter :restore_content_type_for_mobile
|
|
after_filter :set_charset
|
|
|
|
include ActionView::Helpers::TextHelper
|
|
helper_method :format_date, :markdown
|
|
|
|
# By default, sets the charset to UTF-8 if it isn't already set
|
|
def set_charset
|
|
headers["Content-Type"] ||= "text/html; charset=UTF-8"
|
|
end
|
|
|
|
def set_session_expiration
|
|
# http://wiki.rubyonrails.com/rails/show/HowtoChangeSessionOptions
|
|
unless session == nil
|
|
return if @controller_name == 'feed' or session['noexpiry'] == "on"
|
|
# If the method is called by the feed controller (which we don't have under session control)
|
|
# or if we checked the box to keep logged in on login
|
|
# don't set the session expiry time.
|
|
if session
|
|
# Get expiry time (allow ten seconds window for the case where we have none)
|
|
expiry_time = session['expiry_time'] || Time.now + 10
|
|
if expiry_time < Time.now
|
|
# Too late, matey... bang goes your session!
|
|
reset_session
|
|
else
|
|
# Okay, you get another hour
|
|
session['expiry_time'] = Time.now + (60*60)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def render_failure message, status = 404
|
|
render :text => message, :status => status
|
|
end
|
|
|
|
def rescue_action(exception)
|
|
log_error(exception) if logger
|
|
respond_to do |format|
|
|
format.html do
|
|
notify :warning, "An error occurred on the server."
|
|
render :action => "index"
|
|
end
|
|
format.js { render :action => 'error' }
|
|
format.xml { render :text => 'An error occurred on the server.' + $! }
|
|
end
|
|
end
|
|
|
|
# Returns a count of next actions in the given context or project
|
|
# The result is count and a string descriptor, correctly pluralised if there are no
|
|
# actions or multiple actions
|
|
#
|
|
def count_undone_todos_phrase(todos_parent, string="actions")
|
|
count = count_undone_todos(todos_parent)
|
|
if count == 1
|
|
word = string.singularize
|
|
else
|
|
word = string.pluralize
|
|
end
|
|
return count.to_s + " " + word
|
|
end
|
|
|
|
def count_undone_todos(todos_parent)
|
|
if todos_parent.nil?
|
|
count = 0
|
|
elsif (todos_parent.is_a?(Project) && todos_parent.hidden?)
|
|
count = eval "@project_project_hidden_todo_counts[#{todos_parent.id}]"
|
|
else
|
|
count = eval "@#{todos_parent.class.to_s.downcase}_not_done_counts[#{todos_parent.id}]"
|
|
end
|
|
count || 0
|
|
end
|
|
|
|
# Convert a date object to the format specified
|
|
# in config/settings.yml
|
|
#
|
|
def format_date(date)
|
|
if date
|
|
date_format = @user.prefs.date_format
|
|
formatted_date = date.strftime("#{date_format}")
|
|
else
|
|
formatted_date = ''
|
|
end
|
|
formatted_date
|
|
end
|
|
|
|
# Uses RedCloth to transform text using either Textile or Markdown
|
|
# Need to require redcloth above
|
|
# RedCloth 3.0 or greater is needed to use Markdown, otherwise it only handles Textile
|
|
#
|
|
def markdown(text)
|
|
RedCloth.new(text).to_html
|
|
end
|
|
|
|
def build_default_project_context_name_map(projects)
|
|
Hash[*projects.reject{ |p| p.default_context.nil? }.map{ |p| [p.name, p.default_context.name] }.flatten].to_json
|
|
end
|
|
|
|
# Here's the concept behind this "mobile content negotiation" hack:
|
|
# In addition to the main, AJAXy Web UI, Tracks has a lightweight
|
|
# low-feature 'mobile' version designed to be suitablef or use
|
|
# from a phone or PDA. It makes some sense that tne pages of that
|
|
# mobile version are simply alternate representations of the same
|
|
# Todo resources. The implementation goal was to treat mobile
|
|
# as another format and be able to use respond_to to render both
|
|
# versions. Unfortunately, I ran into a lot of trouble simply
|
|
# registering a new mime type 'text/html' with format :m because
|
|
# :html already is linked to that mime type and the new
|
|
# registration was forcing all html requests to be rendered in
|
|
# the mobile view. The before_filter and after_filter hackery
|
|
# below accomplishs that implementation goal by using a 'fake'
|
|
# mime type during the processing and then setting it to
|
|
# 'text/html' in an 'after_filter' -LKM 2007-04-01
|
|
def mobile?
|
|
return params[:format] == 'm' || response.content_type == MOBILE_CONTENT_TYPE
|
|
end
|
|
|
|
def enable_mobile_content_negotiation
|
|
if mobile?
|
|
request.accepts.unshift(Mime::Type::lookup(MOBILE_CONTENT_TYPE))
|
|
end
|
|
end
|
|
|
|
def restore_content_type_for_mobile
|
|
if mobile?
|
|
response.content_type = 'text/html'
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
def admin_login_required
|
|
unless User.find_by_id_and_is_admin(session['user_id'], true)
|
|
render :text => "401 Unauthorized: Only admin users are allowed access to this function.", :status => 401
|
|
return false
|
|
end
|
|
end
|
|
|
|
def redirect_back_or_home
|
|
respond_to do |format|
|
|
format.html { redirect_back_or_default home_url }
|
|
format.m { redirect_back_or_default mobile_url }
|
|
end
|
|
end
|
|
|
|
def boolean_param(param_name)
|
|
return false if param_name.blank?
|
|
s = params[param_name]
|
|
return false if s.blank? || s == false || s =~ /^false$/i
|
|
return true if s == true || s =~ /^true$/i
|
|
raise ArgumentError.new("invalid value for Boolean: \"#{s}\"")
|
|
end
|
|
|
|
private
|
|
|
|
def parse_date_per_user_prefs( s )
|
|
return nil if s.blank?
|
|
Date.strptime(s, @user.prefs.date_format)
|
|
end
|
|
|
|
def init_data_for_sidebar
|
|
@projects = @projects || @user.projects
|
|
@contexts = @contexts || @user.contexts
|
|
init_not_done_counts
|
|
if @prefs.show_hidden_projects_in_sidebar
|
|
init_project_hidden_todo_counts(['project'])
|
|
end
|
|
end
|
|
|
|
def init_not_done_counts(parents = ['project','context'])
|
|
parents.each do |parent|
|
|
eval("@#{parent}_not_done_counts = @#{parent}_not_done_counts || Todo.count(:conditions => ['user_id = ? and state = ?', @user.id, 'active'], :group => :#{parent}_id)")
|
|
end
|
|
end
|
|
|
|
def init_project_hidden_todo_counts(parents = ['project','context'])
|
|
parents.each do |parent|
|
|
eval("@#{parent}_project_hidden_todo_counts = @#{parent}_project_hidden_todo_counts || Todo.count(:conditions => ['user_id = ? and state = ?', @user.id, 'project_hidden'], :group => :#{parent}_id)")
|
|
end
|
|
end
|
|
|
|
# Set the contents of the flash message from a controller
|
|
# Usage: notify :warning, "This is the message"
|
|
# Sets the flash of type 'warning' to "This is the message"
|
|
def notify(type, message)
|
|
flash[type] = message
|
|
logger.error("ERROR: #{message}") if type == :error
|
|
end
|
|
|
|
end
|