diff --git a/.gitignore b/.gitignore index 1bd85063..1daf5e90 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ public/javascripts/cache public/stylesheets/cache tmp vendor/plugins/query_trace/ +rerun.txt diff --git a/app/controllers/application.rb b/app/controllers/application_controller.rb similarity index 96% rename from app/controllers/application.rb rename to app/controllers/application_controller.rb index 497c2fa1..fb4ee359 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application_controller.rb @@ -20,7 +20,7 @@ class CannotAccessContext < RuntimeError; end class ApplicationController < ActionController::Base - protect_from_forgery :secret => SITE_CONFIG['salt'] + protect_from_forgery helper :application include LoginSystem @@ -28,6 +28,7 @@ class ApplicationController < ActionController::Base layout proc{ |controller| controller.mobile? ? "mobile" : "standard" } exempt_from_layout /\.js\.erb$/ + before_filter :set_session_expiration before_filter :set_time_zone @@ -217,6 +218,22 @@ class ApplicationController < ActionController::Base self.class.openid_enabled? end + def self.cas_enabled? + Tracks::Config.cas_enabled? + end + + def cas_enabled? + self.class.cas_enabled? + end + + def self.prefered_auth? + Tracks::Config.prefered_auth? + end + + def prefered_auth? + self.class.prefered_auth? + end + private def parse_date_per_user_prefs( s ) @@ -259,6 +276,8 @@ class ApplicationController < ActionController::Base def set_time_zone Time.zone = current_user.prefs.time_zone if logged_in? + locale = params[:locale] || 'en-US' + I18n.locale = locale end def set_zindex_counter diff --git a/app/controllers/contexts_controller.rb b/app/controllers/contexts_controller.rb index 5177c399..75f3d1c5 100644 --- a/app/controllers/contexts_controller.rb +++ b/app/controllers/contexts_controller.rb @@ -7,7 +7,6 @@ class ContextsController < ApplicationController before_filter :set_context_from_params, :only => [:update, :destroy] skip_before_filter :login_required, :only => [:index] prepend_before_filter :login_or_feed_token_required, :only => [:index] - session :off, :only => :index, :if => Proc.new { |req| ['rss','atom','txt'].include?(req.parameters[:format]) } def index # #true is passed here to force an immediate load so that size and empty? diff --git a/app/controllers/login_controller.rb b/app/controllers/login_controller.rb index 360a8455..0c1037ed 100644 --- a/app/controllers/login_controller.rb +++ b/app/controllers/login_controller.rb @@ -6,12 +6,32 @@ class LoginController < ApplicationController skip_before_filter :login_required before_filter :login_optional before_filter :get_current_user - + if ( SITE_CONFIG['authentication_schemes'].include? 'cas') + # This will allow the user to view the index page without authentication + # but will process CAS authentication data if the user already + # has an SSO session open. + if defined? CASClient + # Only require sub-library if gem is installed and loaded + require 'casclient/frameworks/rails/filter' + before_filter CASClient::Frameworks::Rails::GatewayFilter, :only => :login_cas + + # This requires the user to be authenticated for viewing all other pages. + before_filter CASClient::Frameworks::Rails::Filter, :only => [:login_cas ] + end + end + def login + if cas_enabled? + @username = session[:cas_user] + @login_url = CASClient::Frameworks::Rails::Filter.login_url(self) + end if openid_enabled? && using_open_id? login_openid + elsif cas_enabled? && session[:cas_user] + login_cas else @page_title = "TRACKS::Login" + cookies[:preferred_auth] = prefered_auth? unless cookies[:preferred_auth] case request.method when :post if @user = User.authenticate(params['user_login'], params['user_password']) @@ -49,9 +69,13 @@ class LoginController < ApplicationController @user.forget_me if logged_in? cookies.delete :auth_token session['user_id'] = nil - reset_session - notify :notice, "You have been logged out of Tracks." - redirect_to_login + if ( SITE_CONFIG['authentication_schemes'].include? 'cas') && session[:cas_user] + CASClient::Frameworks::Rails::Filter.logout(self) + else + reset_session + notify :notice, "You have been logged out of Tracks." + redirect_to_login + end end def check_expiry @@ -73,6 +97,33 @@ class LoginController < ApplicationController respond_to do |format| format.js end + end + + def login_cas + # If checkbox on login page checked, we don't expire the session after 1 hour + # of inactivity and we remember this user for future browser sessions + + session['noexpiry'] ||= params['user_noexpiry'] + if session[:cas_user] + if @user = User.find_by_login(session[:cas_user]) + session['user_id'] = @user.id + msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire." + notify :notice, "Login successful: session #{msg}" + cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => SITE_CONFIG['secure_cookies'] } + unless should_expire_sessions? + @user.remember_me + cookies[:auth_token] = { :value => @user.remember_token, :expires => @user.remember_token_expires_at, :secure => SITE_CONFIG['secure_cookies'] } + end + #redirect_back_or_home + else + notify :warning, "Sorry, no user by that CAS username exists (#{session[:cas_user]})" + redirect_to signup_url ; return + end + else + notify :warning, result.message + end + redirect_back_or_home + end private @@ -80,7 +131,7 @@ class LoginController < ApplicationController def redirect_to_login respond_to do |format| format.html { redirect_to login_path } - format.m { redirect_to formatted_login_path(:format => 'm') } + format.m { redirect_to login_path(:format => 'm') } end end @@ -114,4 +165,6 @@ class LoginController < ApplicationController end end end + + end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 56da269e..a6604cb3 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -6,7 +6,6 @@ class ProjectsController < ApplicationController before_filter :default_context_filter, :only => [:create, :update] skip_before_filter :login_required, :only => [:index] prepend_before_filter :login_or_feed_token_required, :only => [:index] - session :off, :only => :index, :if => Proc.new { |req| ['rss','atom','txt'].include?(req.parameters[:format]) } def index @source_view = params['_source_view'] || 'project_list' diff --git a/app/controllers/todos_controller.rb b/app/controllers/todos_controller.rb index 95e29b8c..fc928a03 100644 --- a/app/controllers/todos_controller.rb +++ b/app/controllers/todos_controller.rb @@ -10,8 +10,6 @@ class TodosController < ApplicationController append_before_filter :get_todo_from_params, :only => [ :edit, :toggle_check, :toggle_star, :show, :update, :destroy, :remove_predecessor] protect_from_forgery :except => [:auto_complete_for_tag, :auto_complete_for_predecessor] - session :off, :only => :index, :if => Proc.new { |req| is_feed_request(req) } - def index current_user.deferred_todos.find_and_activate_ready @projects = current_user.projects.find(:all, :include => [:default_context]) @@ -351,7 +349,7 @@ class TodosController < ApplicationController cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']} redirect_to old_path else - redirect_to formatted_todos_path(:m) + redirect_to todos_path(:format => 'm') end else render :action => "edit", :format => :m @@ -463,12 +461,12 @@ class TodosController < ApplicationController def filter_to_context context = current_user.contexts.find(params['context']['id']) - redirect_to formatted_context_todos_path(context, :m) + redirect_to context_todos_path(context, :format => 'm') end def filter_to_project project = current_user.projects.find(params['project']['id']) - redirect_to formatted_project_todos_path(project, :m) + redirect_to project_todos_path(project, :format => 'm') end # /todos/tag/[tag_name] shows all the actions tagged with tag_name @@ -607,9 +605,9 @@ class TodosController < ApplicationController # Begin matching todos in current project @items = current_user.todos.find(:all, :select => 'description, project_id, context_id, created_at', - :conditions => [ '(todos.state = ? OR todos.state = ?) AND ' + + :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' + 'NOT (id = ?) AND lower(description) LIKE ? AND project_id = ?', - 'active', 'pending', + 'active', 'pending', 'deferred', @todo.id, '%' + params[:predecessor_list].downcase + '%', @todo.project_id ], @@ -619,9 +617,9 @@ class TodosController < ApplicationController if @items.empty? # Match todos in other projects @items = current_user.todos.find(:all, :select => 'description, project_id, context_id, created_at', - :conditions => [ '(todos.state = ? OR todos.state = ?) AND ' + + :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND ' + 'NOT (id = ?) AND lower(description) LIKE ?', - 'active', 'pending', + 'active', 'pending', 'deferred', params[:id], '%' + params[:q].downcase + '%' ], :order => 'description ASC', :limit => 10 @@ -631,8 +629,8 @@ class TodosController < ApplicationController # New todo - TODO: Filter on project @items = current_user.todos.find(:all, :select => 'description, project_id, context_id, created_at', - :conditions => [ '(todos.state = ? OR todos.state = ?) AND lower(description) LIKE ?', - 'active', 'pending', + :conditions => [ '(todos.state = ? OR todos.state = ? OR todos.state = ?) AND lower(description) LIKE ?', + 'active', 'pending', 'deferred', '%' + params[:q].downcase + '%' ], :order => 'description ASC', :limit => 10 @@ -640,6 +638,15 @@ class TodosController < ApplicationController end render :inline => "<%= auto_complete_result2(@items) %>" end + + def convert_to_project + @todo = Todo.find(params[:id]) + @project = Project.new(:name => @todo.description, :description => @todo.notes, + :default_context => @todo.context) + @todo.destroy + @project.save! + redirect_to project_url(@project) + end private diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 55d38ad7..5aa985ba 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -27,6 +27,13 @@ class UsersController < ApplicationController # GET /users/new def new + @auth_types = [] + unless session[:cas_user] + Tracks::Config.auth_schemes.each {|auth| @auth_types << [auth,auth]} + else + @auth_types << ['cas','cas'] + end + if User.no_users_yet? @page_title = "TRACKS::Sign up as the admin user" @heading = "Welcome to TRACKS. To get started, please create an admin account:" @@ -66,6 +73,13 @@ class UsersController < ApplicationController end user = User.new(params['user']) + + if Tracks::Config.auth_schemes.include?('cas') + if user.auth_type.eql? "cas" + user.crypted_password = "cas" + end + end + unless user.valid? session['new_user'] = user redirect_to :action => 'new' @@ -94,6 +108,9 @@ class UsersController < ApplicationController return end user = User.new(params[:request]) + if Tracks::Config.auth_schemes.include?('cas') && session[:cas_user] + user.auth_type = "cas" #if they area cas user + end user.password_confirmation = params[:request][:password] if user.save render :text => "User created.", :status => 200 @@ -203,4 +220,4 @@ class UsersController < ApplicationController return true end -end \ No newline at end of file +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 26bff1b3..645be1c4 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -112,7 +112,7 @@ module ApplicationHelper end def link_to_project_mobile(project, accesskey, descriptor = sanitize(project.name)) - link_to( descriptor, formatted_project_path(project, :m), {:title => "View project: #{project.name}", :accesskey => accesskey} ) + link_to( descriptor, project_path(project, :format => 'm'), {:title => "View project: #{project.name}", :accesskey => accesskey} ) end def item_link_to_context(item) @@ -170,13 +170,41 @@ module ApplicationHelper standard_format = current_user.prefs.date_format translations = [ ['%m', 'mm'], + ['%b', 'M'], + ['%B', 'MM'], ['%d', 'dd'], - ['%Y', 'yy'], - ['%y', 'y'] + ['%a', 'D'], + ['%A', 'DD'], + ['%y', 'y'], + ['%Y', 'yy'] ] translations.inject(standard_format) do |str, translation| str.gsub(*translation) end end + AUTO_LINK_MESSAGE_RE = %r{message://<[^>]+>} unless const_defined?(:AUTO_LINK_MESSAGE_RE) + + # Converts message:// links to href. This URL scheme is used on Mac OS X + # to link to a mail message in Mail.app. + def auto_link_message(text) + text.gsub(AUTO_LINK_MESSAGE_RE) do + href = $& + left, right = $`, $' + # detect already linked URLs and URLs in the middle of a tag + if left =~ /<[^>]+$/ && right =~ /^[^>]*>/ + # do not change string; URL is alreay linked + href + else + content_tag(:a, h(href), :href => h(href)) + end + end + end + + def format_note(note) + note = auto_link_message(note) + note = auto_link(note) + note = markdown(note) + note = sanitize(note) + end end diff --git a/app/helpers/todos_helper.rb b/app/helpers/todos_helper.rb index d8be9d1f..1230efa3 100644 --- a/app/helpers/todos_helper.rb +++ b/app/helpers/todos_helper.rb @@ -64,6 +64,14 @@ module TodosHelper :complete => todo_stop_waiting_js(todo)) end end + + def remote_promote_to_project_menu_item(todo) + url = {:controller => 'todos', :action => 'convert_to_project', :id => todo.id, + :_source_view => (@source_view.underscore.gsub(/\s+/,'_') rescue "")} + url[:_tag_name] = @tag_name if @source_view == 'tag' + + return link_to("Promote to project", url) + end def todo_start_waiting_js(todo) return "$('#ul#{dom_id(todo)}').css('visibility', 'hidden'); $('##{dom_id(todo)}').block({message: null})" @@ -262,9 +270,10 @@ module TodosHelper end def empty_container_msg_div_id - return "tickler-empty-nd" if source_view_is_one_of(:project, :tag) && @todo.deferred? - return "p#{@todo.project_id}empty-nd" if source_view_is :project - return "c#{@todo.context_id}empty-nd" + todo = @todo || @successor + return "tickler-empty-nd" if source_view_is_one_of(:project, :tag) && todo.deferred? + return "p#{todo.project_id}empty-nd" if source_view_is :project + return "c#{todo.context_id}empty-nd" end def project_names_for_autocomplete @@ -315,5 +324,5 @@ module TodosHelper def auto_complete_result2(entries, phrase = nil) return entries.map{|e| e.specification()}.join("\n") rescue '' end - + end diff --git a/app/models/todo.rb b/app/models/todo.rb index df7aca4f..82c19cb2 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -17,7 +17,7 @@ class Todo < ActiveRecord::Base after_save :save_predecessors named_scope :active, :conditions => { :state => 'active' } - named_scope :not_completed, :conditions => ['NOT (state = ? )', 'completed'] + named_scope :not_completed, :conditions => ['NOT (todos.state = ? )', 'completed'] named_scope :are_due, :conditions => ['NOT (todos.due IS NULL)'] STARRED_TAG_NAME = "starred" diff --git a/app/models/user.rb b/app/models/user.rb index 30c5a6fb..068c0cb3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -153,11 +153,14 @@ class User < ActiveRecord::Base if Tracks::Config.auth_schemes.include?('ldap') return candidate if candidate.auth_type == 'ldap' && SimpleLdapAuthenticator.valid?(login, pass) end + if Tracks::Config.auth_schemes.include?('cas') && candidate.auth_type.eql?("cas") + return candidate #because we can not auth them with out thier real password we have to settle for this + end return nil end def self.find_by_open_id_url(raw_identity_url) - normalized_open_id_url = OpenIdAuthentication.normalize_url(raw_identity_url) + normalized_open_id_url = OpenIdAuthentication.normalize_identifier(raw_identity_url) find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url]) end @@ -248,6 +251,6 @@ protected def normalize_open_id_url return if open_id_url.nil? - self.open_id_url = OpenIdAuthentication.normalize_url(open_id_url) + self.open_id_url = OpenIdAuthentication.normalize_identifier(open_id_url) end end diff --git a/app/views/contexts/_mobile_context_listing.rhtml b/app/views/contexts/_mobile_context_listing.rhtml index 4f770186..c2360ce7 100644 --- a/app/views/contexts/_mobile_context_listing.rhtml +++ b/app/views/contexts/_mobile_context_listing.rhtml @@ -1,2 +1,2 @@ <% context = mobile_context_listing -%> -