diff --git a/app/controllers/calendar_controller.rb b/app/controllers/calendar_controller.rb
new file mode 100644
index 00000000..9a39dfac
--- /dev/null
+++ b/app/controllers/calendar_controller.rb
@@ -0,0 +1,21 @@
+class CalendarController < ApplicationController
+ def show
+ @source_view = 'calendar'
+ @page_title = t('todos.calendar_page_title')
+
+ @calendar = Todos::Calendar.new(current_user)
+ @projects = @calendar.projects
+ @count = current_user.todos.not_completed.are_due.count
+ @due_all = current_user.todos.not_completed.are_due.reorder("due")
+
+ respond_to do |format|
+ format.html
+ format.ics {
+ render :action => 'calendar', :layout => false, :content_type => Mime::ICS
+ }
+ format.xml {
+ render :xml => @due_all.to_xml( *to_xml_params )
+ }
+ end
+ end
+end
diff --git a/app/views/calendar/show.html.erb b/app/views/calendar/show.html.erb
new file mode 100644
index 00000000..59096af9
--- /dev/null
+++ b/app/views/calendar/show.html.erb
@@ -0,0 +1,13 @@
+
+
+ <%= todos_calendar_container(:due_today, @calendar.due_today ) %>
+ <%= todos_calendar_container(:due_this_week, @calendar.due_this_week ) %>
+ <%= todos_calendar_container(:due_next_week, @calendar.due_next_week ) %>
+ <%= todos_calendar_container(:due_this_month, @calendar.due_this_month ) %>
+ <%= todos_calendar_container(:due_after_this_month, @calendar.due_after_this_month) %>
+
+
+
diff --git a/app/views/calendar/show.ics.erb b/app/views/calendar/show.ics.erb
new file mode 100644
index 00000000..221216ea
--- /dev/null
+++ b/app/views/calendar/show.ics.erb
@@ -0,0 +1,32 @@
+BEGIN:VCALENDAR
+PRODID:-//TRACKS//<%= TRACKS_VERSION %>//EN
+VERSION:2.0
+CALSCALE:GREGORIAN
+METHOD:PUBLISH
+X-WR-CALNAME:Tracks
+<% for todo in @due_all
+ due_date = todo.due
+ overdue_text = ""
+ if due_date.at_midnight < Time.zone.now.at_midnight
+ due_date = Time.zone.now
+ overdue_text = t('todos.overdue') +": "
+ end
+ modified = todo.updated_at || todo.created_at
+%>BEGIN:VEVENT
+DTSTART;VALUE=DATE:<%= due_date.strftime("%Y%m%d") %>
+DTEND;VALUE=DATE:<%= (due_date+1.day).strftime("%Y%m%d") %>
+DTSTAMP:<%= due_date.strftime("%Y%m%dT%H%M%SZ") %>
+UID:<%= todo_url(todo) %>
+CLASS:PUBLIC
+CATEGORIES:Tracks
+CREATED:<%= todo.created_at.strftime("%Y%m%dT%H%M%SZ") %>
+DESCRIPTION:<%= format_ical_notes(todo.notes) %>
+LAST-MODIFIED:<%= modified.strftime("%Y%m%dT%H%M%SZ") %>
+LOCATION:
+SEQUENCE:0
+STATUS:CONFIRMED
+SUMMARY:<%= overdue_text + todo.description %>
+TRANSP:TRANSPARENT
+END:VEVENT
+<% end
+%>END:VCALENDAR
diff --git a/config/routes.rb b/config/routes.rb
index 0e1de86b..746c66cf 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -10,7 +10,7 @@ Tracksapp::Application.routes.draw do
match "tickler" => "todos#list_deferred"
match 'review' => "projects#review"
- match 'calendar' => "todos#calendar"
+ match 'calendar' => "calendar#show"
match 'done' => "stats#done", :as => 'done_overview'
match 'search' => 'search#index'
diff --git a/test/functional/calendar_controller_test.rb b/test/functional/calendar_controller_test.rb
new file mode 100644
index 00000000..43f54385
--- /dev/null
+++ b/test/functional/calendar_controller_test.rb
@@ -0,0 +1,30 @@
+require_relative '../test_helper'
+
+class CalendarControllerTest < ActionController::TestCase
+ def test_show
+ login_as(:admin_user)
+
+ get :show
+
+ projects = [projects(:timemachine),
+ projects(:moremoney),
+ projects(:gardenclean)]
+ due_today = [todos(:phone_grandfather),
+ todos(:call_bill_gates_every_day),
+ todos(:due_today)]
+ due_next_week = [todos(:buy_shares),
+ todos(:buy_stego_bait),
+ todos(:new_action_in_context)]
+ due_this_month = [todos(:call_bill),
+ todos(:call_dino_ext)]
+
+ assert_equal "calendar", assigns['source_view']
+ assert_equal projects, assigns['projects']
+ assert_equal due_today, assigns['calendar'].due_today
+ assert_equal [], assigns['calendar'].due_this_week
+ assert_equal due_next_week, assigns['calendar'].due_next_week
+ assert_equal due_this_month, assigns['calendar'].due_this_month
+ assert_equal [], assigns['calendar'].due_after_this_month
+ assert_equal 8, assigns['count']
+ end
+end
diff --git a/test/functional/todos_controller_test.rb b/test/functional/todos_controller_test.rb
index 6d207ade..cc890baf 100644
--- a/test/functional/todos_controller_test.rb
+++ b/test/functional/todos_controller_test.rb
@@ -898,29 +898,4 @@ class TodosControllerTest < ActionController::TestCase
assert t4.pending?, "t4 should remain pending"
assert t4.predecessors.map(&:id).include?(t3.id)
end
-
-
- def test_calendar
- login_as(:admin_user)
-
- get :calendar
-
- projects = [projects(:timemachine),
- projects(:moremoney),
- projects(:gardenclean)]
- due_today = [todos(:phone_grandfather),
- todos(:call_bill_gates_every_day),
- todos(:due_today)]
- due_next_week = [todos(:buy_shares),
- todos(:buy_stego_bait),
- todos(:new_action_in_context)]
-
- assert_equal "calendar", assigns['source_view']
- assert_equal projects, assigns['projects']
- assert_equal due_today, assigns['calendar'].due_today
- assert_equal [], assigns['calendar'].due_this_week
- assert_equal due_next_week, assigns['calendar'].due_next_week
- assert_equal [], assigns['calendar'].due_this_month
- assert_equal 8, assigns['count']
- end
end