all unit and functional tests are passing

This commit is contained in:
Reinier Balt 2012-04-24 20:47:07 +02:00
parent 96db48dd86
commit 13b58f3a10
40 changed files with 1107 additions and 1494 deletions

View file

@ -1,261 +0,0 @@
== Welcome to Rails
Rails is a web-application framework that includes everything needed to create
database-backed web applications according to the Model-View-Control pattern.
This pattern splits the view (also called the presentation) into "dumb"
templates that are primarily responsible for inserting pre-built data in between
HTML tags. The model contains the "smart" domain objects (such as Account,
Product, Person, Post) that holds all the business logic and knows how to
persist themselves to a database. The controller handles the incoming requests
(such as Save New Account, Update Product, Show Post) by manipulating the model
and directing data to the view.
In Rails, the model is handled by what's called an object-relational mapping
layer entitled Active Record. This layer allows you to present the data from
database rows as objects and embellish these data objects with business logic
methods. You can read more about Active Record in
link:files/vendor/rails/activerecord/README.html.
The controller and view are handled by the Action Pack, which handles both
layers by its two parts: Action View and Action Controller. These two layers
are bundled in a single package due to their heavy interdependence. This is
unlike the relationship between the Active Record and Action Pack that is much
more separate. Each of these packages can be used independently outside of
Rails. You can read more about Action Pack in
link:files/vendor/rails/actionpack/README.html.
== Getting Started
1. At the command prompt, create a new Rails application:
<tt>rails new myapp</tt> (where <tt>myapp</tt> is the application name)
2. Change directory to <tt>myapp</tt> and start the web server:
<tt>cd myapp; rails server</tt> (run with --help for options)
3. Go to http://localhost:3000/ and you'll see:
"Welcome aboard: You're riding Ruby on Rails!"
4. Follow the guidelines to start developing your application. You can find
the following resources handy:
* The Getting Started Guide: http://guides.rubyonrails.org/getting_started.html
* Ruby on Rails Tutorial Book: http://www.railstutorial.org/
== Debugging Rails
Sometimes your application goes wrong. Fortunately there are a lot of tools that
will help you debug it and get it back on the rails.
First area to check is the application log files. Have "tail -f" commands
running on the server.log and development.log. Rails will automatically display
debugging and runtime information to these files. Debugging info will also be
shown in the browser on requests from 127.0.0.1.
You can also log your own messages directly into the log file from your code
using the Ruby logger class from inside your controllers. Example:
class WeblogController < ActionController::Base
def destroy
@weblog = Weblog.find(params[:id])
@weblog.destroy
logger.info("#{Time.now} Destroyed Weblog ID ##{@weblog.id}!")
end
end
The result will be a message in your log file along the lines of:
Mon Oct 08 14:22:29 +1000 2007 Destroyed Weblog ID #1!
More information on how to use the logger is at http://www.ruby-doc.org/core/
Also, Ruby documentation can be found at http://www.ruby-lang.org/. There are
several books available online as well:
* Programming Ruby: http://www.ruby-doc.org/docs/ProgrammingRuby/ (Pickaxe)
* Learn to Program: http://pine.fm/LearnToProgram/ (a beginners guide)
These two books will bring you up to speed on the Ruby language and also on
programming in general.
== Debugger
Debugger support is available through the debugger command when you start your
Mongrel or WEBrick server with --debugger. This means that you can break out of
execution at any point in the code, investigate and change the model, and then,
resume execution! You need to install ruby-debug to run the server in debugging
mode. With gems, use <tt>sudo gem install ruby-debug</tt>. Example:
class WeblogController < ActionController::Base
def index
@posts = Post.all
debugger
end
end
So the controller will accept the action, run the first line, then present you
with a IRB prompt in the server window. Here you can do things like:
>> @posts.inspect
=> "[#<Post:0x14a6be8
@attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>,
#<Post:0x14a6620
@attributes={"title"=>"Rails", "body"=>"Only ten..", "id"=>"2"}>]"
>> @posts.first.title = "hello from a debugger"
=> "hello from a debugger"
...and even better, you can examine how your runtime objects actually work:
>> f = @posts.first
=> #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
>> f.
Display all 152 possibilities? (y or n)
Finally, when you're ready to resume execution, you can enter "cont".
== Console
The console is a Ruby shell, which allows you to interact with your
application's domain model. Here you'll have all parts of the application
configured, just like it is when the application is running. You can inspect
domain models, change values, and save to the database. Starting the script
without arguments will launch it in the development environment.
To start the console, run <tt>rails console</tt> from the application
directory.
Options:
* Passing the <tt>-s, --sandbox</tt> argument will rollback any modifications
made to the database.
* Passing an environment name as an argument will load the corresponding
environment. Example: <tt>rails console production</tt>.
To reload your controllers and models after launching the console run
<tt>reload!</tt>
More information about irb can be found at:
link:http://www.rubycentral.org/pickaxe/irb.html
== dbconsole
You can go to the command line of your database directly through <tt>rails
dbconsole</tt>. You would be connected to the database with the credentials
defined in database.yml. Starting the script without arguments will connect you
to the development database. Passing an argument will connect you to a different
database, like <tt>rails dbconsole production</tt>. Currently works for MySQL,
PostgreSQL and SQLite 3.
== Description of Contents
The default directory structure of a generated Ruby on Rails application:
|-- app
| |-- assets
| |-- images
| |-- javascripts
| `-- stylesheets
| |-- controllers
| |-- helpers
| |-- mailers
| |-- models
| `-- views
| `-- layouts
|-- config
| |-- environments
| |-- initializers
| `-- locales
|-- db
|-- doc
|-- lib
| `-- tasks
|-- log
|-- public
|-- script
|-- test
| |-- fixtures
| |-- functional
| |-- integration
| |-- performance
| `-- unit
|-- tmp
| |-- cache
| |-- pids
| |-- sessions
| `-- sockets
`-- vendor
|-- assets
`-- stylesheets
`-- plugins
app
Holds all the code that's specific to this particular application.
app/assets
Contains subdirectories for images, stylesheets, and JavaScript files.
app/controllers
Holds controllers that should be named like weblogs_controller.rb for
automated URL mapping. All controllers should descend from
ApplicationController which itself descends from ActionController::Base.
app/models
Holds models that should be named like post.rb. Models descend from
ActiveRecord::Base by default.
app/views
Holds the template files for the view that should be named like
weblogs/index.html.erb for the WeblogsController#index action. All views use
eRuby syntax by default.
app/views/layouts
Holds the template files for layouts to be used with views. This models the
common header/footer method of wrapping views. In your views, define a layout
using the <tt>layout :default</tt> and create a file named default.html.erb.
Inside default.html.erb, call <% yield %> to render the view using this
layout.
app/helpers
Holds view helpers that should be named like weblogs_helper.rb. These are
generated for you automatically when using generators for controllers.
Helpers can be used to wrap functionality for your views into methods.
config
Configuration files for the Rails environment, the routing map, the database,
and other dependencies.
db
Contains the database schema in schema.rb. db/migrate contains all the
sequence of Migrations for your schema.
doc
This directory is where your application documentation will be stored when
generated using <tt>rake doc:app</tt>
lib
Application specific libraries. Basically, any kind of custom code that
doesn't belong under controllers, models, or helpers. This directory is in
the load path.
public
The directory available for the web server. Also contains the dispatchers and the
default HTML files. This should be set as the DOCUMENT_ROOT of your web
server.
script
Helper scripts for automation and generation.
test
Unit and functional tests along with fixtures. When using the rails generate
command, template test files will be generated for you and placed in this
directory.
vendor
External libraries that the application depends on. Also includes the plugins
subdirectory. If the app has frozen rails, those gems also go here, under
vendor/rails/. This directory is in the load path.

View file

@ -18,7 +18,7 @@ class DataController < ApplicationController
def yaml_export
all_tables = {}
all_tables['todos'] = current_user.todos.includes(:tags)
all_tables['todos'] = current_user.todos.includes(:tags).all
all_tables['contexts'] = current_user.contexts.all
all_tables['projects'] = current_user.projects.all
@ -37,10 +37,10 @@ class DataController < ApplicationController
tags = Tag.where("id IN (?) OR id IN (?)", todo_tag_ids, rec_todo_tag_ids)
taggings = Tagging.where("tag_id IN (?) OR tag_id IN(?)", todo_tag_ids, rec_todo_tag_ids)
all_tables['tags'] = tags
all_tables['taggings'] = taggings
all_tables['notes'] = current_user.notes
all_tables['recurring_todos'] = current_user.recurring_todos
all_tables['tags'] = tags.all
all_tables['taggings'] = taggings.all
all_tables['notes'] = current_user.notes.all
all_tables['recurring_todos'] = current_user.recurring_todos.all
result = all_tables.to_yaml
result.gsub!(/\n/, "\r\n") # TODO: general functionality for line endings
@ -72,13 +72,13 @@ class DataController < ApplicationController
def csv_notes
content_type = 'text/csv'
CSV::Writer.generate(result = "") do |csv|
CSV.generate(result = "") do |csv|
csv << ["id", "User ID", "Project", "Note",
"Created at", "Updated at"]
# had to remove project include because it's association order is leaking
# through and causing an ambiguous column ref even with_exclusive_scope
# didn't seem to help -JamesKebinger
current_user.notes.order("notes.created_at").each do |note|
current_user.notes.reorder("notes.created_at").each do |note|
# Format dates in ISO format for easy sorting in spreadsheet Print
# context and project names for easy viewing
csv << [note.id, note.user_id,

View file

@ -113,7 +113,7 @@ class ProjectsController < ApplicationController
@done = {}
@done = @project.todos.completed.
order("todos.completed_at DESC").
reorder("todos.completed_at DESC").
limit(current_user.prefs.show_number_completed).
includes(Todo::DEFAULT_INCLUDES) unless current_user.prefs.show_number_completed == 0

View file

@ -10,12 +10,12 @@ class SearchController < ApplicationController
@found_not_complete_todos = current_user.todos.
where("(todos.description LIKE ? OR todos.notes LIKE ?) AND todos.completed_at IS NULL", terms, terms).
includes(Todo::DEFAULT_INCLUDES).
order("todos.due IS NULL, todos.due ASC, todos.created_at ASC")
reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC")
@found_complete_todos = current_user.todos.
where("(todos.description LIKE ? OR todos.notes LIKE ?) AND NOT (todos.completed_at IS NULL)", terms, terms).
includes(Todo::DEFAULT_INCLUDES).
order("todos.completed_at DESC")
reorder("todos.completed_at DESC")
@found_todos = @found_not_complete_todos + @found_complete_todos

View file

@ -6,10 +6,10 @@ class StatsController < ApplicationController
def index
@page_title = t('stats.index_title')
@first_action = current_user.todos.reorder("created_at ASC").first
@tags_count = get_total_number_of_tags_of_user
@unique_tags_count = get_unique_tags_of_user.size
@hidden_contexts = current_user.contexts.hidden
@first_action = current_user.todos.order("created_at ASC").first
get_stats_actions
get_stats_contexts
@ -55,8 +55,8 @@ class StatsController < ApplicationController
end
def actions_done_lastyears_data
@actions_done_last_months = current_user.todos.completed.select("completed_at").order("completed_at DESC")
@actions_created_last_months = current_user.todos.select("created_at").order("created_at DESC" )
@actions_done_last_months = current_user.todos.completed.select("completed_at").reorder("completed_at DESC")
@actions_created_last_months = current_user.todos.select("created_at").reorder("created_at DESC" )
# query is sorted, so use last todo to calculate number of months
@month_count = [difference_in_months(@today, @actions_created_last_months.last.created_at),
@ -101,7 +101,7 @@ class StatsController < ApplicationController
end
def actions_completion_time_data
@actions_completion_time = current_user.todos.completed.select("completed_at, created_at").order("completed_at DESC" )
@actions_completion_time = current_user.todos.completed.select("completed_at, created_at").reorder("completed_at DESC" )
# convert to array and fill in non-existing weeks with 0
@max_weeks = difference_in_weeks(@today, @actions_completion_time.last.completed_at)
@ -121,7 +121,7 @@ class StatsController < ApplicationController
end
def actions_running_time_data
@actions_running_time = current_user.todos.not_completed.select("created_at").order("created_at DESC")
@actions_running_time = current_user.todos.not_completed.select("created_at").reorder("created_at DESC")
# convert to array and fill in non-existing weeks with 0
@max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at)
@ -151,7 +151,7 @@ class StatsController < ApplicationController
@actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.
select("todos.created_at").
order("todos.created_at DESC")
reorder("todos.created_at DESC")
@max_weeks = difference_in_weeks(@today, @actions_running_time.last.created_at)
@actions_running_per_week_array = convert_to_weeks_from_today_array(@actions_running_time, @max_weeks+1, :created_at)
@ -172,7 +172,7 @@ class StatsController < ApplicationController
def actions_open_per_week_data
@actions_started = current_user.todos.created_after(@today-53.weeks).
select("todos.created_at, todos.completed_at").
order("todos.created_at DESC")
reorder("todos.created_at DESC")
@max_weeks = difference_in_weeks(@today, @actions_started.last.created_at)
@ -358,7 +358,7 @@ class StatsController < ApplicationController
# get all running actions that are visible
@actions_running_time = current_user.todos.not_completed.not_hidden.not_deferred_or_blocked.
select("todos.id, todos.created_at").
order("todos.created_at DESC")
reorder("todos.created_at DESC")
selected_todo_ids = get_ids_from(@actions_running_time, week_from, week_to, params['id']== 'avrt_end')
@selected_actions = selected_todo_ids.size == 0 ? [] : current_user.todos.where("id in (" + selected_todo_ids.join(",") + ")")
@ -399,10 +399,10 @@ class StatsController < ApplicationController
init_not_done_counts
@done_recently = current_user.todos.completed.limit(10).order('completed_at DESC').includes(Todo::DEFAULT_INCLUDES)
@last_completed_projects = current_user.projects.completed.limit(10).order('completed_at DESC').includes(:todos, :notes)
@done_recently = current_user.todos.completed.limit(10).reorder('completed_at DESC').includes(Todo::DEFAULT_INCLUDES)
@last_completed_projects = current_user.projects.completed.limit(10).reorder('completed_at DESC').includes(:todos, :notes)
@last_completed_contexts = []
@last_completed_recurring_todos = current_user.recurring_todos.completed.limit(10).order('completed_at DESC').includes(:tags, :taggings)
@last_completed_recurring_todos = current_user.recurring_todos.completed.limit(10).reorder('completed_at DESC').includes(:tags, :taggings)
#TODO: @last_completed_contexts = current_user.contexts.completed.all(:limit => 10, :order => 'completed_at DESC')
end

View file

@ -1,36 +1,152 @@
class TodosController < ApplicationController
helper :todos
skip_before_filter :login_required, :only => [:index, :calendar, :tag]
prepend_before_filter :login_or_feed_token_required, :only => [:index, :calendar, :tag]
append_before_filter :find_and_activate_ready, :only => [:index, :list_deferred]
# TODO: replace :except with :only
append_before_filter :init, :except => [ :tag, :tags, :destroy, :done,
:check_deferred, :toggle_check, :toggle_star, :edit, :update, :defer, :create,
:calendar, :auto_complete_for_predecessor, :remove_predecessor, :add_predecessor]
# # TODO: replace :except with :only
# append_before_filter :init, :except => [ :tag, :tags, :destroy, :done,
# :check_deferred, :toggle_check, :toggle_star, :edit, :update, :defer, :create,
# :calendar, :auto_complete_for_predecessor, :remove_predecessor, :add_predecessor]
protect_from_forgery :except => :check_deferred
# these are needed for todo_feed_content. TODO: remove this view stuff from controller
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
# # these are needed for todo_feed_content. TODO: remove this view stuff from controller
# include ActionView::Helpers::SanitizeHelper
# extend ActionView::Helpers::SanitizeHelper::ClassMethods
def with_feed_query_scope(&block)
unless TodosController.is_feed_request(request)
Todo.send(:where, ['todos.state = ?', 'active']) do
yield
return
end
end
condition_builder = FindConditionBuilder.new
if params.key?('done')
condition_builder.add 'todos.state = ?', 'completed'
else
condition_builder.add 'todos.state = ?', 'active'
end
@title = t('todos.next_actions_title')
@description = t('todos.next_actions_description')
if params.key?('due')
due_within = params['due'].to_i
due_within_when = Time.zone.now + due_within.days
condition_builder.add('todos.due <= ?', due_within_when)
due_within_date_s = due_within_when.strftime("%Y-%m-%d")
@title << t('todos.next_actions_title_additions.due_today') if (due_within == 0)
@title << t('todos.next_actions_title_additions.due_within_a_week') if (due_within == 6)
@description << t('todos.next_actions_description_additions.due_date', :due_date => due_within_date_s)
end
if params.key?('done')
done_in_last = params['done'].to_i
condition_builder.add('todos.completed_at >= ?', Time.zone.now - done_in_last.days)
@title << t('todos.next_actions_title_additions.completed')
@description << t('todos.next_actions_description_additions.completed', :count => done_in_last.to_s)
end
if params.key?('tag')
tag = Tag.find_by_name(params['tag'])
if tag.nil?
tag = Tag.new(:name => params['tag'])
end
condition_builder.add('taggings.tag_id = ?', tag.id)
end
Todo.send :where, condition_builder.to_conditions do
yield
end
end
def with_parent_resource_scope(&block)
@feed_title = t('common.actions')
if (params[:context_id])
@context = current_user.contexts.find_by_params(params)
@feed_title = @feed_title + t('todos.feed_title_in_context', :context => @context.name)
Todo.send :where, ['todos.context_id = ?', @context.id] do
yield
end
elsif (params[:project_id])
@project = current_user.projects.find_by_params(params)
@feed_title = @feed_title + t('todos.feed_title_in_project', :project => @project.name)
@project_feed = true
Todo.send :where, ['todos.project_id = ?', @project.id] do
yield
end
else
yield
end
end
def with_limit_scope(&block)
if params.key?('limit')
Todo.send :with_scope, :find => { :limit => params['limit'] } do
yield
end
if TodosController.is_feed_request(request) && @description
if params.key?('limit')
@description << t('todos.list_incomplete_next_actions_with_limit', :count => params['limit'])
else
@description << t('todos.list_incomplete_next_actions')
end
end
else
yield
end
end
def index
@source_view = params['_source_view'] || 'todo'
init_data_for_sidebar unless mobile?
if mobile?
@not_done_todos = current_user.todos.
where('todos.state = ? AND contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', 'active', false, 'active').
reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC").
includes(:project, :context, :tags)
else
@todos = current_user.todos.includes(Todo::DEFAULT_INCLUDES)
@not_done_todos = current_user.todos.
where('contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', false, 'active').
reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC").
includes(Todo::DEFAULT_INCLUDES)
end
@projects = current_user.projects.includes(:default_context)
@contexts = current_user.contexts
@contexts_to_show = current_user.contexts.active
# If you've set no_completed to zero, the completed items box isn't shown
# on the home page
max_completed = current_user.prefs.show_number_completed
@done = current_user.todos.completed.limit(max_completed).includes(Todo::DEFAULT_INCLUDES) unless max_completed == 0
respond_to do |format|
format.html &render_todos_html
format.m &render_todos_mobile
format.html do
@page_title = t('todos.task_list_title')
# Set count badge to number of not-done, not hidden context items
@count = current_user.todos.active.not_hidden.count(:all)
end
format.m do
@page_title = t('todos.mobile_todos_page_title')
@home = true
cookies[:mobile_url]= { :value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
determine_down_count
render :action => 'index'
end
format.xml { render :xml => @todos.to_xml( *to_xml_params ) }
format.rss &render_rss_feed
format.atom &render_atom_feed
format.text &render_text_feed
format.ics &render_ical_feed
format.rss
format.atom
format.text
format.ics
end
end
@ -315,7 +431,7 @@ class TodosController < ApplicationController
# Toggles the 'done' status of the action
#
def toggle_check
@todo = current_user.todos.find_by_id(params['id'])
@todo = current_user.todos.find(params['id'])
@source_view = params['_source_view'] || 'todo'
@original_item_due = @todo.due
@original_item_was_deferred = @todo.deferred?
@ -565,7 +681,7 @@ class TodosController < ApplicationController
@source_view = 'done'
@page_title = t('todos.completed_tasks_title')
@done = current_user.todos.completed.includes(Todo::DEFAULT_INCLUDES).order('completed_at DESC').paginate :page => params[:page], :per_page => 20
@done = current_user.todos.completed.includes(Todo::DEFAULT_INCLUDES).reorder('completed_at DESC').paginate :page => params[:page], :per_page => 20
@count = @done.size
end
@ -624,26 +740,26 @@ class TodosController < ApplicationController
@not_done_todos = todos_with_tag_ids.
active.not_hidden.
order('todos.due IS NULL, todos.due ASC, todos.created_at ASC').
reorder('todos.due IS NULL, todos.due ASC, todos.created_at ASC').
includes(Todo::DEFAULT_INCLUDES)
@hidden_todos = todos_with_tag_ids.
hidden.
order('todos.completed_at DESC, todos.created_at DESC').
reorder('todos.completed_at DESC, todos.created_at DESC').
includes(Todo::DEFAULT_INCLUDES)
@deferred = todos_with_tag_ids.
deferred.
order('todos.show_from ASC, todos.created_at DESC').
reorder('todos.show_from ASC, todos.created_at DESC').
includes(Todo::DEFAULT_INCLUDES)
@pending = todos_with_tag_ids.
blocked.
order('todos.show_from ASC, todos.created_at DESC').
reorder('todos.show_from ASC, todos.created_at DESC').
includes(Todo::DEFAULT_INCLUDES)
# If you've set no_completed to zero, the completed items box isn't shown on
# the tag page
@done = todos_with_tag_ids.completed.
limit(current_user.prefs.show_number_completed).
order('todos.completed_at DESC').
reorder('todos.completed_at DESC').
includes(Todo::DEFAULT_INCLUDES)
@projects = current_user.projects
@ -696,7 +812,7 @@ class TodosController < ApplicationController
@tag = Tag.find_by_name(@tag_name)
@tag = Tag.new(:name => @tag_name) if @tag.nil?
@done = current_user.todos.completed.with_tag(@tag.id).order('completed_at DESC').includes(Todo::DEFAULT_INCLUDES).paginate :page => params[:page], :per_page => 20
@done = current_user.todos.completed.with_tag(@tag.id).reorder('completed_at DESC').includes(Todo::DEFAULT_INCLUDES).paginate :page => params[:page], :per_page => 20
@count = @done.size
render :template => 'todos/all_done'
end
@ -772,34 +888,34 @@ class TodosController < ApplicationController
@due_today = current_user.todos.not_completed.
where('todos.due <= ?', due_today_date).
includes(included_tables).
order("due")
reorder("due")
@due_this_week = current_user.todos.not_completed.
where('todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date).
includes(included_tables).
order("due")
reorder("due")
@due_next_week = current_user.todos.not_completed.
where('todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date).
includes(included_tables).
order("due")
reorder("due")
@due_this_month = current_user.todos.not_completed.
where('todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date).
includes(included_tables).
order("due")
reorder("due")
@due_after_this_month = current_user.todos.not_completed.
where('todos.due > ?', due_this_month_date).
includes(included_tables).
order("due")
reorder("due")
@count = current_user.todos.not_completed.are_due.count
respond_to do |format|
format.html
format.ics {
@due_all = current_user.todos.not_completed.are_due.order("due")
@due_all = current_user.todos.not_completed.are_due.reorder("due")
render :action => 'calendar', :layout => false, :content_type => Mime::ICS
}
format.xml {
@due_all = current_user.todos.not_completed.are_due.order("due")
@due_all = current_user.todos.not_completed.are_due.reorder("due")
render :xml => @due_all.to_xml( *to_xml_params )
}
end
@ -821,26 +937,26 @@ class TodosController < ApplicationController
@items = @todo.project.todos.not_completed.
where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
includes(:context, :project).
order('description ASC').
reorder('description ASC').
limit(10) unless @todo.project.nil?
# Then look in the current context, excluding @todo itself
@items = @todo.context.todos.not_completed
where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
includes(:context, :project).
order('description ASC').
reorder('description ASC').
limit(10) unless !@items.empty? || @todo.context.nil?
# Match todos in other projects, excluding @todo itself
@items = current_user.todos.not_completed.
where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
includes(:context, :project).
order('description ASC').
reorder('description ASC').
limit(10) unless !@items.empty?
else
# New todo - TODO: Filter on current project in project view
@items = current_user.todos.not_completed.
where('(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%").
includes(:context, :project).
order('description ASC').
reorder('description ASC').
limit(10)
end
render :inline => format_dependencies_as_json_for_auto_complete(@items)
@ -894,136 +1010,6 @@ class TodosController < ApplicationController
current_user.deferred_todos.find_and_activate_ready
end
def init
@source_view = params['_source_view'] || 'todo'
init_data_for_sidebar unless mobile?
init_todos
end
def with_feed_query_scope(&block)
unless TodosController.is_feed_request(request)
Todo.send(:where, ['todos.state = ?', 'active']) do
yield
return
end
end
condition_builder = FindConditionBuilder.new
if params.key?('done')
condition_builder.add 'todos.state = ?', 'completed'
else
condition_builder.add 'todos.state = ?', 'active'
end
@title = t('todos.next_actions_title')
@description = t('todos.next_actions_description')
if params.key?('due')
due_within = params['due'].to_i
due_within_when = Time.zone.now + due_within.days
condition_builder.add('todos.due <= ?', due_within_when)
due_within_date_s = due_within_when.strftime("%Y-%m-%d")
@title << t('todos.next_actions_title_additions.due_today') if (due_within == 0)
@title << t('todos.next_actions_title_additions.due_within_a_week') if (due_within == 6)
@description << t('todos.next_actions_description_additions.due_date', :due_date => due_within_date_s)
end
if params.key?('done')
done_in_last = params['done'].to_i
condition_builder.add('todos.completed_at >= ?', Time.zone.now - done_in_last.days)
@title << t('todos.next_actions_title_additions.completed')
@description << t('todos.next_actions_description_additions.completed', :count => done_in_last.to_s)
end
if params.key?('tag')
tag = Tag.find_by_name(params['tag'])
if tag.nil?
tag = Tag.new(:name => params['tag'])
end
condition_builder.add('taggings.tag_id = ?', tag.id)
end
Todo.send :where, condition_builder.to_conditions do
yield
end
end
def with_parent_resource_scope(&block)
@feed_title = t('common.actions')
if (params[:context_id])
@context = current_user.contexts.find_by_params(params)
@feed_title = @feed_title + t('todos.feed_title_in_context', :context => @context.name)
Todo.send :where, ['todos.context_id = ?', @context.id] do
yield
end
elsif (params[:project_id])
@project = current_user.projects.find_by_params(params)
@feed_title = @feed_title + t('todos.feed_title_in_project', :project => @project.name)
@project_feed = true
Todo.send :where, ['todos.project_id = ?', @project.id] do
yield
end
else
yield
end
end
def with_limit_scope(&block)
if params.key?('limit')
Todo.send :with_scope, :find => { :limit => params['limit'] } do
yield
end
if TodosController.is_feed_request(request) && @description
if params.key?('limit')
@description << t('todos.list_incomplete_next_actions_with_limit', :count => params['limit'])
else
@description << t('todos.list_incomplete_next_actions')
end
end
else
yield
end
end
def init_todos
with_feed_query_scope do
with_parent_resource_scope do # @context or @project may get defined here
with_limit_scope do
if mobile?
init_todos_for_mobile_view
else
# Note: these next two finds were previously using
# current_users.todos.find but that broke with_scope for :limit
# Exclude hidden projects from count on home page
@todos = current_user.todos.includes(Todo::DEFAULT_INCLUDES)
# Exclude hidden projects from the home page
@not_done_todos = current_user.todos.
where('contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', false, 'active').
order("todos.due IS NULL, todos.due ASC, todos.created_at ASC").
includes(Todo::DEFAULT_INCLUDES)
end
end
end
end
end
def init_todos_for_mobile_view
# Note: these next two finds were previously using current_users.todos.find
# but that broke with_scope for :limit
# Exclude hidden projects from the home page
@not_done_todos = current_user.todos.
where('todos.state = ? AND contexts.hide = ? AND (projects.state = ? OR todos.project_id IS NULL)', 'active', false, 'active').
order("todos.due IS NULL, todos.due ASC, todos.created_at ASC").
includes(:project, :context, :tags)
end
def tag_title(tag_expr)
and_list = tag_expr.inject([]) { |s,tag_list| s << tag_list.join(',') }
return and_list.join(' AND ')
@ -1194,99 +1180,6 @@ class TodosController < ApplicationController
@remaining_deferred_or_pending_count = tag.nil? ? 0 : current_user.todos.deferred.with_tag(tag.id).count
end
def render_todos_html
lambda do
@page_title = t('todos.task_list_title')
# If you've set no_completed to zero, the completed items box isn't shown
# on the home page
max_completed = current_user.prefs.show_number_completed
@done = current_user.todos.completed.limit(max_completed).includes(Todo::DEFAULT_INCLUDES) unless max_completed == 0
# Set count badge to number of not-done, not hidden context items
@count = current_user.todos.active.not_hidden.count(:all)
render
end
end
def render_todos_mobile
lambda do
@page_title = t('todos.mobile_todos_page_title')
@home = true
max_completed = current_user.prefs.show_number_completed
@done = current_user.todos.completed.limit(max_completed).includes(Todo::DEFAULT_INCLUDES) unless max_completed == 0
cookies[:mobile_url]= { :value => request.request_uri, :secure => SITE_CONFIG['secure_cookies']}
determine_down_count
render :action => 'index'
end
end
def render_rss_feed
lambda do
render_rss_feed_for @todos, :feed => todo_feed_options,
:item => {
:title => :description,
:link => lambda { |t| @project_feed.nil? ? context_url(t.context) : project_url(t.project) },
:guid => lambda { |t| todo_url(t) },
:description => todo_feed_content
}
end
end
def todo_feed_options
options = Todo.feed_options(current_user)
options[:title] = @feed_title
return options
end
def todo_feed_content
# TODO: move view stuff into view, also the includes at the top
lambda do |i|
item_notes = i.rendered_notes if i.notes?
due = "<div>#{t('todos.feeds.due', :date => format_date(i.due))}</div>\n" if i.due?
done = "<div>#{t('todos.feeds.completed', :date => format_date(i.completed_at))}</div>\n" if i.completed?
context_link = "<a href=\"#{ context_url(i.context) }\">#{ i.context.name }</a>"
if i.project_id?
project_link = "<a href=\"#{ project_url(i.project) }\">#{ i.project.name }</a>"
else
project_link = "<em>#{t('common.none')}</em>"
end
"#{done||''}#{due||''}#{item_notes||''}\n<div>#{t('common.project')}: #{project_link}</div>\n<div>#{t('common.context')}: #{context_link}</div>"
end
end
def render_atom_feed
lambda do
render_atom_feed_for @todos, :feed => todo_feed_options,
:item => {
:title => :description,
:link => lambda { |t| context_url(t.context) },
:description => todo_feed_content,
:author => lambda { |p| nil }
}
end
end
def render_text_feed
lambda do
render :action => 'index', :layout => false, :content_type => Mime::TEXT
end
end
def render_ical_feed
lambda do
render :action => 'index', :layout => false, :content_type => Mime::ICS
end
end
def self.is_feed_request(req)
['rss','atom','txt','ics'].include?(req.parameters[:format])
end
def check_for_next_todo(todo)
# check if this todo has a related recurring_todo. If so, create next todo
new_recurring_todo = nil
@ -1434,7 +1327,7 @@ class TodosController < ApplicationController
begin
params["todo"]["due"] = parse_date_per_user_prefs(params["todo"]["due"])
rescue
@todo.errors.add_to_base("Invalid due date")
@todo.errors[:base] << "Invalid due date"
end
else
params["todo"]["due"] = ""
@ -1443,7 +1336,7 @@ class TodosController < ApplicationController
begin
params['todo']['show_from'] = parse_date_per_user_prefs(params['todo']['show_from'])
rescue
@todo.errors.add_to_base("Invalid show from date")
@todo.errors[:base] << "Invalid show from date"
end
end
end
@ -1530,23 +1423,84 @@ class TodosController < ApplicationController
return !( all_list_uniq_ids.length == all_list_count )
end
class FindConditionBuilder
def initialize
@queries = Array.new
@params = Array.new
end
def add(query, param)
@queries << query
@params << param
end
def to_conditions
[@queries.join(' AND ')] + @params
end
end
# def render_text_feed
# lambda do
# render :action => 'index', :layout => false, :content_type => Mime::TEXT
# end
# end
#
# def render_ical_feed
# lambda do
# render :action => 'index', :layout => false, :content_type => Mime::ICS
# end
# end
#
# def self.is_feed_request(req)
# ['rss','atom','txt','ics'].include?(req.parameters[:format])
# end
#
# class FindConditionBuilder
#
# def initialize
# @queries = Array.new
# @params = Array.new
# end
#
# def add(query, param)
# @queries << query
# @params << param
# end
#
# def to_conditions
# [@queries.join(' AND ')] + @params
# end
# end
# def render_rss_feed
# lambda do
# render_rss_feed_for @todos, :feed => todo_feed_options,
# :item => {
# :title => :description,
# :link => lambda { |t| @project_feed.nil? ? context_url(t.context) : project_url(t.project) },
# :guid => lambda { |t| todo_url(t) },
# :description => todo_feed_content
# }
# end
# end
#
# def todo_feed_options
# options = Todo.feed_options(current_user)
# options[:title] = @feed_title
# return options
# end
#
# def todo_feed_content
# # TODO: move view stuff into view, also the includes at the top
# lambda do |i|
# item_notes = i.rendered_notes if i.notes?
# due = "<div>#{t('todos.feeds.due', :date => format_date(i.due))}</div>\n" if i.due?
# done = "<div>#{t('todos.feeds.completed', :date => format_date(i.completed_at))}</div>\n" if i.completed?
# context_link = "<a href=\"#{ context_url(i.context) }\">#{ i.context.name }</a>"
# if i.project_id?
# project_link = "<a href=\"#{ project_url(i.project) }\">#{ i.project.name }</a>"
# else
# project_link = "<em>#{t('common.none')}</em>"
# end
# "#{done||''}#{due||''}#{item_notes||''}\n<div>#{t('common.project')}: #{project_link}</div>\n<div>#{t('common.context')}: #{context_link}</div>"
# end
# end
#
# def render_atom_feed
# lambda do
# render_atom_feed_for @todos, :feed => todo_feed_options,
# :item => {
# :title => :description,
# :link => lambda { |t| context_url(t.context) },
# :description => todo_feed_content,
# :author => lambda { |p| nil }
# }
# end
# end
class TodoCreateParamsHelper

View file

@ -26,7 +26,7 @@ class UsersController < ApplicationController
# GET /users/id GET /users/id.xml
def show
@user = User.find_by_id(params[:id])
@user = User.find(params[:id])
render :xml => @user.to_xml(:except => [ :password ])
end
@ -83,7 +83,7 @@ class UsersController < ApplicationController
user.auth_type == 'ldap' &&
!SimpleLdapAuthenticator.valid?(user.login, params['user']['password'])
notify :warning, "Incorrect password"
redirect_to :action => 'new'
redirect_to signup_path
return
end
@ -137,7 +137,7 @@ class UsersController < ApplicationController
# DELETE /users/id DELETE /users/id.xml
def destroy
@deleted_user = User.find_by_id(params[:id])
@deleted_user = User.find(params[:id])
@saved = @deleted_user.destroy
@total_users = User.all.size
@ -155,19 +155,18 @@ class UsersController < ApplicationController
end
end
def change_password
@page_title = t('users.change_password_title')
end
def update_password
# is used for focing password change after sha->bcrypt upgrade
@user.change_password(params[:user][:password], params[:user][:password_confirmation])
current_user.change_password(params[:user][:password], params[:user][:password_confirmation])
notify :notice, t('users.password_updated')
redirect_to preferences_path
rescue Exception => error
notify :error, error.message
redirect_to :action => 'change_password'
redirect_to change_password_user_path(current_user)
end
def change_auth_type
@ -175,40 +174,19 @@ class UsersController < ApplicationController
end
def update_auth_type
if (params[:open_id_complete] || (params[:user][:auth_type] == 'open_id')) && openid_enabled?
authenticate_with_open_id do |result, identity_url|
if result.successful?
# Success means that the transaction completed without error. If info
# is nil, it means that the user cancelled the verification.
@user.auth_type = 'open_id'
@user.open_id_url = identity_url
if @user.save
notify :notice, t('users.openid_url_verified', :url => identity_url)
else
debugger
notify :warning, t('users.openid_ok_pref_failed', :url => identity_url)
end
redirect_to preferences_path
else
notify :warning, result.message
redirect_to :action => 'change_auth_type'
end
end
return
end
@user.auth_type = params[:user][:auth_type]
if @user.save
current_user.auth_type = params[:user][:auth_type]
if current_user.save
notify :notice, t('users.auth_type_updated')
redirect_to preferences_path
else
notify :warning, t('users.auth_type_update_error', :error_messages => @user.errors.full_messages.join(', '))
redirect_to :action => 'change_auth_type'
notify :warning, t('users.auth_type_update_error', :error_messages => current_user.errors.full_messages.join(', '))
redirect_to change_auth_type_user_path(current_user)
end
end
def refresh_token
@user.generate_token
@user.save!
current_user.generate_token
current_user.save!
notify :notice, t('users.new_token_generated')
redirect_to preferences_path
end

View file

@ -1,37 +1,25 @@
class MessageGateway < ActionMailer::Base
# include ActionView::Helpers::SanitizeHelper
# extend ActionView::Helpers::SanitizeHelper::ClassMethods
include ActionView::Helpers::SanitizeHelper
extend ActionView::Helpers::SanitizeHelper::ClassMethods
def receive(email)
puts "email = #{email}"
address = ''
if SITE_CONFIG['email_dispatch'] == 'to'
address = email.to[0]
else
address = email.from[0]
end
user = User.where("preferences.sms_email" => address.strip).first(:include => [:preference])
if user.nil?
user = User.where("preferences.sms_email" => address.strip[1.100]).first(:include => [:preference])
end
user = get_user_from_email_address(email)
return if user.nil?
context = user.prefs.sms_context
description = nil
notes = nil
if email.content_type == "multipart/related"
description = sanitize email.subject
body_part = email.parts.find{|m| m.content_type == "text/plain"}
notes = sanitize body_part.body.strip
if email.multipart?
description = get_text_or_nil(email.subject)
notes = get_first_text_plain_part(email)
else
if email.subject && email.subject.blank?
description = sanitize email.body.strip
if email.subject.blank?
description = get_decoded_text_or_nil(email.body)
notes = nil
else
description = sanitize email.subject.strip
notes = sanitize email.body.strip
description = get_text_or_nil(email.subject)
notes = get_decoded_text_or_nil(email.body)
end
end
@ -41,4 +29,33 @@ class MessageGateway < ActionMailer::Base
todo = Todo.from_rich_message(user, context.id, description, notes)
todo.save!
end
private
def get_address(email)
return SITE_CONFIG['email_dispatch'] == 'to' ? email.to[0] : email.from[0]
end
def get_user_from_email_address(email)
address = get_address(email)
user = User.where("preferences.sms_email" => address.strip).includes(:preference).first
if user.nil?
user = User.where("preferences.sms_email" => address.strip[1.100]).includes(:preference).first
end
return user
end
def get_text_or_nil(text)
return text ? sanitize(text.strip) : nil
end
def get_decoded_text_or_nil(text)
return text ? sanitize(text.decoded.strip) : nil
end
def get_first_text_plain_part(email)
parts = email.parts.reject{|part| !part.content_type.start_with?("text/plain") }
return parts ? sanitize(parts[0].decoded.strip) : ""
end
end

View file

@ -3,7 +3,7 @@ class Preference < ActiveRecord::Base
belongs_to :sms_context, :class_name => 'Context'
attr_accessible :date_format, :week_starts, :show_number_completed, :show_completed_projects_in_sidebar,
:show_hidden_contexts_in_sidebar, :staleness_starts, :due_style, :admin_email
:show_hidden_contexts_in_sidebar, :staleness_starts, :due_style, :admin_email, :locale
def self.due_styles
{ :due_in_n_days => 0, :due_on => 1}

View file

@ -51,30 +51,30 @@ class RecurringTodo < ActiveRecord::Base
def validate_daily
if (!only_work_days) && (daily_every_x_days.nil? || daily_every_x_days.blank?)
errors.add_to_base("Every other nth day may not be empty for recurrence setting")
errors[:base] << "Every other nth day may not be empty for recurrence setting"
end
end
def validate_weekly
if weekly_every_x_week.nil? || weekly_every_x_week.blank?
errors.add_to_base("Every other nth week may not be empty for recurrence setting")
errors[:base] << "Every other nth week may not be empty for recurrence setting"
end
something_set = false
%w{sunday monday tuesday wednesday thursday friday saturday}.each do |day|
something_set ||= self.send("on_#{day}")
end
errors.add_to_base("You must specify at least one day on which the todo recurs") if !something_set
errors[:base] << "You must specify at least one day on which the todo recurs" if !something_set
end
def validate_monthly
case recurrence_selector
when 0 # 'monthly_every_x_day'
errors.add_to_base("The day of the month may not be empty for recurrence setting") if monthly_every_x_day.nil? || monthly_every_x_day.blank?
errors.add_to_base("Every other nth month may not be empty for recurrence setting") if monthly_every_x_month.nil? || monthly_every_x_month.blank?
errors[:base] << "The day of the month may not be empty for recurrence setting" if monthly_every_x_day.nil? || monthly_every_x_day.blank?
errors[:base] << "Every other nth month may not be empty for recurrence setting" if monthly_every_x_month.nil? || monthly_every_x_month.blank?
when 1 # 'monthly_every_xth_day'
errors.add_to_base("Every other nth month may not be empty for recurrence setting") if monthly_every_x_month2.nil? || monthly_every_x_month2.blank?
errors.add_to_base("The nth day of the month may not be empty for recurrence setting") if monthly_every_xth_day.nil? || monthly_every_xth_day.blank?
errors.add_to_base("The day of the month may not be empty for recurrence setting") if monthly_day_of_week.nil? || monthly_day_of_week.blank?
errors[:base] <<"Every other nth month may not be empty for recurrence setting" if monthly_every_x_month2.nil? || monthly_every_x_month2.blank?
errors[:base] <<"The nth day of the month may not be empty for recurrence setting" if monthly_every_xth_day.nil? || monthly_every_xth_day.blank?
errors[:base] <<"The day of the month may not be empty for recurrence setting" if monthly_day_of_week.nil? || monthly_day_of_week.blank?
else
raise Exception.new, "unexpected value of recurrence selector '#{self.recurrence_selector}'"
end
@ -83,26 +83,26 @@ class RecurringTodo < ActiveRecord::Base
def validate_yearly
case recurrence_selector
when 0 # 'yearly_every_x_day'
errors.add_to_base("The month of the year may not be empty for recurrence setting") if yearly_month_of_year.nil? || yearly_month_of_year.blank?
errors.add_to_base("The day of the month may not be empty for recurrence setting") if yearly_every_x_day.nil? || yearly_every_x_day.blank?
errors[:base] << "The month of the year may not be empty for recurrence setting" if yearly_month_of_year.nil? || yearly_month_of_year.blank?
errors[:base] << "The day of the month may not be empty for recurrence setting" if yearly_every_x_day.nil? || yearly_every_x_day.blank?
when 1 # 'yearly_every_xth_day'
errors.add_to_base("The month of the year may not be empty for recurrence setting") if yearly_month_of_year2.nil? || yearly_month_of_year2.blank?
errors.add_to_base("The nth day of the month may not be empty for recurrence setting") if yearly_every_xth_day.nil? || yearly_every_xth_day.blank?
errors.add_to_base("The day of the week may not be empty for recurrence setting") if yearly_day_of_week.nil? || yearly_day_of_week.blank?
errors[:base] << "The month of the year may not be empty for recurrence setting" if yearly_month_of_year2.nil? || yearly_month_of_year2.blank?
errors[:base] << "The nth day of the month may not be empty for recurrence setting" if yearly_every_xth_day.nil? || yearly_every_xth_day.blank?
errors[:base] << "The day of the week may not be empty for recurrence setting" if yearly_day_of_week.nil? || yearly_day_of_week.blank?
else
raise Exception.new, "unexpected value of recurrence selector '#{self.recurrence_selector}'"
end
end
def starts_and_ends_on_validations
errors.add_to_base("The start date needs to be filled in") if start_from.nil? || start_from.blank?
errors[:base] << "The start date needs to be filled in" if start_from.nil? || start_from.blank?
case self.ends_on
when 'ends_on_number_of_times'
errors.add_to_base("The number of recurrences needs to be filled in for 'Ends on'") if number_of_occurences.nil? || number_of_occurences.blank?
errors[:base] << "The number of recurrences needs to be filled in for 'Ends on'" if number_of_occurences.nil? || number_of_occurences.blank?
when "ends_on_end_date"
errors.add_to_base("The end date needs to be filled in for 'Ends on'") if end_date.nil? || end_date.blank?
errors[:base] << "The end date needs to be filled in for 'Ends on'" if end_date.nil? || end_date.blank?
else
errors.add_to_base("The end of the recurrence is not selected") unless ends_on == "no_end_date"
errors[:base] << "The end of the recurrence is not selected" unless ends_on == "no_end_date"
end
end
@ -112,9 +112,9 @@ class RecurringTodo < ActiveRecord::Base
when 'show_from_date'
# no validations
when 'due_date'
errors.add_to_base("Please select when to show the action") if show_always.nil?
errors[:base] << "Please select when to show the action" if show_always.nil?
unless show_always
errors.add_to_base("Please fill in the number of days to show the todo before the due date") if show_from_delta.nil? || show_from_delta.blank?
errors[:base] << "Please fill in the number of days to show the todo before the due date" if show_from_delta.nil? || show_from_delta.blank?
end
else
raise Exception.new, "unexpected value of recurrence target selector '#{self.recurrence_target}'"

View file

@ -372,9 +372,9 @@ class Todo < ActiveRecord::Base
context_id = default_context_id
unless(context.nil?)
found_context = user.contexts.active.find_by_namepart(context)
found_context = user.contexts.find_by_namepart(context) if found_context.nil?
context_id = found_context.id unless found_context.nil?
found_context = user.contexts.active.where("name like ?", "%#{context}%").first
found_context = user.contexts.where("name like ?", "%#{context}%").first if !found_context
context_id = found_context.id if found_context
end
unless user.contexts.exists? context_id

View file

@ -5,6 +5,11 @@ class User < ActiveRecord::Base
# Virtual attribute for the unencrypted password
attr_accessor :password
attr_protected :is_admin # don't allow mass-assignment for this
attr_accessible :login, :first_name, :last_name, :password_confirmation, :password, :auth_type, :open_id_url
#for will_paginate plugin
cattr_accessor :per_page
@@per_page = 5
has_many :contexts,
:order => 'position ASC',
@ -91,8 +96,6 @@ class User < ActiveRecord::Base
has_many :notes, :order => "created_at DESC", :dependent => :delete_all
has_one :preference, :dependent => :destroy
attr_protected :is_admin
validates_presence_of :login
validates_presence_of :password, :if => :password_required?
validates_length_of :password, :within => 5..40, :if => :password_required?
@ -105,10 +108,6 @@ class User < ActiveRecord::Base
before_create :crypt_password, :generate_token
before_update :crypt_password
#for will_paginate plugin
cattr_accessor :per_page
@@per_page = 5
def validate_auth_type
unless Tracks::Config.auth_schemes.include?(auth_type)
errors.add("auth_type", "not a valid authentication type (#{auth_type})")

View file

@ -19,5 +19,5 @@
</div>
<div id="input_box">
<%= render :file => "sidebar/sidebar.html.erb" %>
<%= render :file => "sidebar/sidebar" %>
</div>

View file

@ -1,7 +1,7 @@
<%- reset_tab_index %>
<div class="recurring_container">
<%= form_for(@new_recurring_todo, :html=> { :id=>'recurring-todo-form-new-action', :name=>'recurring_todo', :class => 'inline-form' }) do -%>
<div id="error_status"><%= error_messages_for("item", :object_name => 'action') %></div>
<div id="error_status"><%= get_list_of_error_messages_for(@new_recurring_todo) %></div>
<div id="recurring_todo_form_container">
<div id="recurring_todo">

View file

@ -13,5 +13,5 @@
</div><!-- End of display_box -->
<div id="input_box">
<%= render :partial => "shared/add_new_item_form" %>
<%= render :file => "sidebar/sidebar.html.erb" %>
<%= render :file => "sidebar/sidebar" %>
</div><!-- End of input box -->

View file

@ -184,14 +184,26 @@ function remove_source_container(next_steps) {
<% end %>
}
function html_for_todo() {
return "<%= @saved && !source_view_is(:done) ? escape_javascript(render(:partial => @todo, :locals => {
:parent_container_type => parent_container_type,
:suppress_project => source_view_is(:project),
:suppress_context => source_view_is(:context)
})) : "" %>";
function html_for_recurring_todo() {
<%-
js = @saved && @new_recurring_todo ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : ""
-%>
return "<%= js %>";
}
function html_for_recurring_todo() {
return "<%= @saved ? escape_javascript(render(:partial => @new_recurring_todo, :locals => { :parent_container_type => parent_container_type })) : "" %>";
function html_for_todo() {
<%-
js = ""
if @saved && !source_view_is(:done)
js = escape_javascript(render(
:partial => @todo,
:locals => {
:parent_container_type => parent_container_type,
:suppress_project => source_view_is(:project),
:suppress_context => source_view_is(:context)
}
))
end
-%>
return "<%= js %>";
}

View file

@ -2,7 +2,7 @@
<h2><%= @page_title %></h2>
<%= error_messages_for 'user' %>
<%= get_list_of_error_messages_for @user %>
<p><%= t('users.change_password_prompt') %></p>

View file

@ -51,7 +51,7 @@ Tracksapp::Application.routes.draw do
# root :to => 'welcome#index'
# See how all your routes lay out with "rake routes"
# This is a legacy wild controller route that's not recommended for RESTful applications.
# Note: This route will make all actions in every controller accessible via GET requests.
# match ':controller(/:action(/:id))(.:format)'
@ -64,6 +64,7 @@ Tracksapp::Application.routes.draw do
match 'login_cas' => 'users#login_cas'
match 'logout' => 'users#logout'
match 'calendar' => "todos#calendar"
match 'stats' => 'stats#index'
match 'done' => "stats#done", :as => 'done_overview'
match 'integrations' => "integrations#index"
match 'integrations/rest_api' => "integrations#rest_api", :as => 'rest_api_docs'
@ -113,6 +114,16 @@ Tracksapp::Application.routes.draw do
end
end
match 'todos/tag/:name' => 'todos#tag', :as => :tag
resources :recurring_todos do
member do
put 'toggle_check'
put 'toggle_star'
end
collection do
get 'done'
end
end
resources :users do
member do

View file

@ -1,6 +1,6 @@
Return-Path: <15555555555/TYPE=PLMN@tmomail.net>
Date: Fri, 6 Jun 2008 21:38:26 -0400
From: 15555555555@tmomail.net
From: 5555555555@tmomail.net
To: gtd@tracks.com
Message-ID: <3645873.13759311212802713215.JavaMail.mms@rlyatl28>
Subject: This is the subject

View file

@ -1,30 +1,17 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
require 'feedlist_controller'
# Re-raise errors caught by the controller.
class FeedlistController; def rescue_action(e) raise e end; end
class FeedlistControllerTest < ActionController::TestCase
fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos, :notes
def setup
assert_equal "test", ENV['RAILS_ENV']
assert_equal "change-me", Tracks::Config.salt
@controller = FeedlistController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_get_index_when_not_logged_in
get :index
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_path
end
def test_get_index_by_logged_in_user
login_as :other_user
get :index
assert_response :success
assert_equal "TRACKS::Feeds", assigns['page_title']
assert_equal "TRACKS::Feeds", assigns['page_title']
end
end
end

View file

@ -1,7 +1,6 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
class MessageGatewayTest < ActiveSupport::TestCase
fixtures :users, :contexts, :todos
def setup
@user = users(:sms_user)
@ -14,18 +13,18 @@ class MessageGatewayTest < ActiveSupport::TestCase
def test_sms_with_no_subject
todo_count = Todo.count
load_message('sample_sms.txt')
# assert some stuff about it being created
assert_equal(todo_count+1, Todo.count)
message_todo = Todo.find(:first, :conditions => {:description => "message_content"})
assert_not_nil(message_todo)
assert_equal(@inbox, message_todo.context)
assert_equal(@user, message_todo.user)
end
def test_double_sms
todo_count = Todo.count
load_message('sample_sms.txt')
@ -56,18 +55,18 @@ class MessageGatewayTest < ActiveSupport::TestCase
MessageGateway.receive(badmessage)
assert_equal(todo_count, Todo.count)
end
def test_direct_to_context
message = File.read(File.join(Rails.root, 'test', 'fixtures', 'sample_sms.txt'))
valid_context_msg = message.gsub('message_content', 'this is a task @ anothercontext')
invalid_context_msg = message.gsub('message_content', 'this is also a task @ notacontext')
MessageGateway.receive(valid_context_msg)
valid_context_todo = Todo.find(:first, :conditions => {:description => "this is a task"})
assert_not_nil(valid_context_todo)
assert_equal(contexts(:anothercontext), valid_context_todo.context)
MessageGateway.receive(invalid_context_msg)
invalid_context_todo = Todo.find(:first, :conditions => {:description => 'this is also a task'})
assert_not_nil(invalid_context_todo)

View file

@ -1,9 +1,9 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
class PreferencesControllerTest < ActionController::TestCase
fixtures :users, :preferences
def setup
super
assert_equal "test", Rails.env
assert_equal "change-me", Tracks::Config.salt
end

View file

@ -1,16 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
class RecurringTodosControllerTest < ActionController::TestCase
fixtures :users, :preferences, :projects, :contexts, :todos, :tags, :taggings, :recurring_todos
def setup
@controller = RecurringTodosController.new
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
end
def test_get_index_when_not_logged_in
get :index
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_path
end
def test_destroy_recurring_todo

View file

@ -1,21 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
require 'stats_controller'
# Re-raise errors caught by the controller.
class StatsController; def rescue_action(e) raise e end; end
class StatsControllerTest < ActionController::TestCase
fixtures :users, :preferences, :projects, :contexts, :todos, :recurring_todos, :recurring_todos, :tags, :taggings
def setup
@controller = StatsController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_get_index_when_not_logged_in
get :index
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_url
end
def test_get_index

View file

@ -1,21 +0,0 @@
class TodoContainerControllerTestBase < ActionController::TestCase
def setup_controller_request_and_response
# ## override with empty
# TODO: remove these ugly hacks
end
def perform_setup(container_class, controller_class)
@controller = controller_class.new
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
login_as :other_user
@initial_count = container_class.count
@container_class = container_class
end
def test_truth
assert true
end
end

File diff suppressed because it is too large Load diff

View file

@ -1,23 +1,10 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
require 'users_controller'
# Re-raise errors caught by the controller.
class UsersController; def rescue_action(e) raise e end; end
class UsersControllerTest < ActionController::TestCase
fixtures :preferences, :users
def setup
assert_equal "test", ENV['RAILS_ENV']
assert_equal "change-me", Tracks::Config.salt
@controller = UsersController.new
@request = ActionController::TestRequest.new
@response = ActionController::TestResponse.new
end
def test_get_index_when_not_logged_in
get :index
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_path
end
def test_get_index_by_nonadmin
@ -32,7 +19,7 @@ class UsersControllerTest < ActionController::TestCase
assert_response :success
assert_equal "TRACKS::Manage Users", assigns['page_title']
assert_equal 5, assigns['total_users']
assert_equal "/users", session['return-to']
assert_equal users_url, session['return-to']
end
def test_index_pagination_page_1
@ -59,7 +46,7 @@ class UsersControllerTest < ActionController::TestCase
def test_update_password_successful
get :change_password # should fail because no login
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_path
login_as :admin_user
@user = @request.session['user_id']
get :change_password # should now pass because we're logged in
@ -74,21 +61,19 @@ class UsersControllerTest < ActionController::TestCase
def test_update_password_no_confirmation
post :update_password # should fail because no login
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_path
login_as :admin_user
post :update_password, :user => {:password => 'newpassword', :password_confirmation => 'wrong'}
assert_redirected_to :controller => 'users', :action => 'change_password'
assert users(:admin_user).save, false
assert_redirected_to change_password_user_path(users(:admin_user))
assert_equal 'Validation failed: Password doesn\'t match confirmation', flash[:error]
end
def test_update_password_validation_errors
post :update_password # should fail because no login
assert_redirected_to :controller => 'login', :action => 'login'
assert_redirected_to login_path
login_as :admin_user
post :update_password, :user => {:password => 'ba', :password_confirmation => 'ba'}
assert_redirected_to :controller => 'users', :action => 'change_password'
assert users(:admin_user).save, false
assert_redirected_to change_password_user_path(User.find(users(:admin_user).id))
# For some reason, no errors are being raised now.
#assert_equal 1, users(:admin_user).errors.count
#assert_equal users(:admin_user).errors.on(:password), "is too short (min is 5 characters)"

View file

@ -2,7 +2,8 @@ ENV["RAILS_ENV"] = "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
{ :salt => "change-me", :authentication_schemes => ["database", "open_id"], :prefered_auth => "database"}.each{|k,v| SITE_CONFIG[k]=v}
# set config for tests. Overwrite those read from config/site.yml. Use inject to avoid warning about changing CONSTANT
{"salt" => "change-me", "authentication_schemes" => ["database", "open_id", "ldap"], "prefered_auth" => "database"}.inject( SITE_CONFIG ) { |h, elem| h[elem[0]] = elem[1]; h }
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
@ -10,17 +11,35 @@ class ActiveSupport::TestCase
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# Add more helper methods to be used by all tests here...
def assert_value_changed(object, method = nil)
initial_value = object.send(method)
yield
assert_not_equal initial_value, object.send(method), "#{object}##{method}"
end
# Generates a random string of ascii characters (a-z, "1 0")
# of a given length for testing assignment to fields
# for validation purposes
#
def generate_random_string(length)
string = ""
characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0)
length.times do
pick = characters[rand(26)]
string << pick
end
return string
end
def assert_equal_dmy(date1, date2)
assert_equal date1.strftime("%d-%m-%y"), date2.strftime("%d-%m-%y")
end
end
class ActionController::TestCase
def login_as(user)
@request.session['user_id'] = user ? users(user).id : nil
end
@ -61,26 +80,4 @@ class ActionController::TestCase
eval("#{get_model_class}.count")
end
end
class ActiveSupport::TestCase
# Generates a random string of ascii characters (a-z, "1 0")
# of a given length for testing assignment to fields
# for validation purposes
#
def generate_random_string(length)
string = ""
characters = %w(a b c d e f g h i j k l m n o p q r s t u v w z y z 1\ 0)
length.times do
pick = characters[rand(26)]
string << pick
end
return string
end
def assert_equal_dmy(date1, date2)
assert_equal date1.strftime("%d-%m-%y"), date2.strftime("%d-%m-%y")
end
end

View file

@ -54,12 +54,6 @@ class ContextTest < ActiveSupport::TestCase
assert_equal @agenda.name, @agenda.title
end
def test_feed_options
opts = Context.feed_options(users(:admin_user))
assert_equal 'Tracks Contexts', opts[:title], 'Unexpected value for :title key of feed_options'
assert_equal 'Lists all the contexts for Admin Schmadmin', opts[:description], 'Unexpected value for :description key of feed_options'
end
def test_hidden_attr_reader
assert !@agenda.hidden?
@agenda.hide = true

View file

@ -128,12 +128,6 @@ class ProjectTest < ActiveSupport::TestCase
assert p.nil?
assert_nil p.id
end
def test_feed_options
opts = Project.feed_options(users(:admin_user))
assert_equal 'Tracks Projects', opts[:title], 'Unexpected value for :title key of feed_options'
assert_equal 'Lists all the projects for Admin Schmadmin', opts[:description], 'Unexpected value for :description key of feed_options'
end
def test_name_removes_extra_spaces
newproj = Project.new

View file

@ -1,5 +1,4 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
require 'date'
class TodoTest < ActiveSupport::TestCase
fixtures :todos, :recurring_todos, :users, :contexts, :preferences, :tags, :taggings, :projects

View file

@ -1,13 +1,5 @@
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
module Tracks
class Config
def self.auth_schemes
['database', 'ldap']
end
end
end
class SimpleLdapAuthenticator
cattr_accessor :fake_success
@ -22,7 +14,7 @@ class UserTest < ActiveSupport::TestCase
def setup
assert_equal "test", ENV['RAILS_ENV']
assert_equal "change-me", Tracks::Config.salt
assert_equal ['database', 'ldap'], Tracks::Config.auth_schemes
assert Tracks::Config.auth_schemes.include?('ldap')
@admin_user = User.find(1)
@other_user = User.find(2)
end