Author: assaf
Date: Fri May 16 01:38:11 2008
New Revision: 656967

URL: http://svn.apache.org/viewvc?rev=656967&view=rev
Log:
Added iCal for tasks and more auto-magic in iCal template.

Added:
    ode/sandbox/singleshot/app/views/tasks/index.atom.builder
    ode/sandbox/singleshot/app/views/tasks/index.ics.ical
Modified:
    ode/sandbox/singleshot/app/controllers/activities_controller.rb
    ode/sandbox/singleshot/app/controllers/application.rb
    ode/sandbox/singleshot/app/controllers/tasks_controller.rb
    ode/sandbox/singleshot/app/models/task.rb
    ode/sandbox/singleshot/lib/extensions/ical_template.rb

Modified: ode/sandbox/singleshot/app/controllers/activities_controller.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/controllers/activities_controller.rb?rev=656967&r1=656966&r2=656967&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/controllers/activities_controller.rb (original)
+++ ode/sandbox/singleshot/app/controllers/activities_controller.rb Fri May 16 
01:38:11 2008
@@ -1,6 +1,6 @@
 class ActivitiesController < ApplicationController
 
-  prepend_before_filter :authenticate_with_access_key, :unless=>lambda { 
|controller| controller.request.format.html? }
+  access_key_authentication :only=>[:show]
 
   def show
     @alternate = { Mime::ATOM=>formatted_activity_url(:format=>:atom, 
:access_key=>authenticated.access_key),

Modified: ode/sandbox/singleshot/app/controllers/application.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/controllers/application.rb?rev=656967&r1=656966&r2=656967&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/controllers/application.rb (original)
+++ ode/sandbox/singleshot/app/controllers/application.rb Fri May 16 01:38:11 
2008
@@ -31,6 +31,12 @@
     end
   end
 
+  def self.access_key_authentication(options = {})
+    formats = options[:formats] || ['atom', 'ics']
+    options[:if] ||= lambda { |controller| 
formats.include?(controller.request.format) }
+    prepend_before_filter :authenticate_with_access_key, options
+  end
+
   # Access key authentication, used for feeds, iCal and other type of requets 
that
   # do not support HTTP authentication or sessions.  Can only be used for GET 
requests.
   #

Modified: ode/sandbox/singleshot/app/controllers/tasks_controller.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/controllers/tasks_controller.rb?rev=656967&r1=656966&r2=656967&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/controllers/tasks_controller.rb (original)
+++ ode/sandbox/singleshot/app/controllers/tasks_controller.rb Fri May 16 
01:38:11 2008
@@ -1,12 +1,12 @@
 class TasksController < ApplicationController
 
+  access_key_authentication :only=>:index
+
   verify :params=>:task, :only=>:update, :render=>{:text=>'Missing task', 
:status=>:bad_request}
   before_filter :authenticate, :except=>[:show, :update, :complete, :destroy]
   instance :task, :only=>[:show, :update, :complete, :destroy], 
:check=>:instance_accessible
   before_filter :forbid_reserved, :except=>[:update, :destroy]
 
-  layout 'application'
-
   def index
     @alternate = { Mime::ATOM=>formatted_tasks_url(:format=>:atom, 
:access_key=>authenticated.access_key), 
                    Mime::ICS=>formatted_tasks_url(:format=>:ics, 
:access_key=>authenticated.access_key) }

Modified: ode/sandbox/singleshot/app/models/task.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/models/task.rb?rev=656967&r1=656966&r2=656967&view=diff
==============================================================================
--- ode/sandbox/singleshot/app/models/task.rb (original)
+++ ode/sandbox/singleshot/app/models/task.rb Fri May 16 01:38:11 2008
@@ -106,6 +106,10 @@
     end
   end
 
+  def status
+    state
+  end
+
 
 
   # -- Common task attributes --
@@ -164,9 +168,9 @@
 
   # --- Priority and ordering ---
   
-  # Task priority: 1 is the lowest (and default) priority.
+  # Task priority: 1 is the highest, 3 the lowest, average is the default.
   PRIORITIES = 1..3
-  before_validation { |task| task.priority ||= PRIORITIES.min }
+  before_validation { |task| task.priority ||= (PRIORITIES.min + 
PRIORITIES.max) >> 1 }
   validates_inclusion_of :priority, :in=>PRIORITIES
 
   def over_due?
@@ -215,6 +219,10 @@
     end
   end
 
+  def completed_on
+    # TODO: should be attribute
+  end
+
   def complete!(data = nil)
     self.status = :completed
     self.data = data if data

Added: ode/sandbox/singleshot/app/views/tasks/index.atom.builder
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/views/tasks/index.atom.builder?rev=656967&view=auto
==============================================================================
--- ode/sandbox/singleshot/app/views/tasks/index.atom.builder (added)
+++ ode/sandbox/singleshot/app/views/tasks/index.atom.builder Fri May 16 
01:38:11 2008
@@ -0,0 +1,14 @@
+atom_feed :root_url=>tasks_url do |feed|
+  feed.title 'Singleshot: Tasks'
+  feed.updated @tasks.map(&:updated_at).max
+
+  for task in @tasks
+    feed.entry task do |entry|
+      entry.title task.title
+      entry.content :type=>'html' do |content|
+        content.text! "<p>#{h(task.description)}</p>"
+        # TODO: task stats and actions
+      end
+    end
+  end
+end

Added: ode/sandbox/singleshot/app/views/tasks/index.ics.ical
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/app/views/tasks/index.ics.ical?rev=656967&view=auto
==============================================================================
--- ode/sandbox/singleshot/app/views/tasks/index.ics.ical (added)
+++ ode/sandbox/singleshot/app/views/tasks/index.ics.ical Fri May 16 01:38:11 
2008
@@ -0,0 +1,14 @@
+calendar.prodid = 'Apache Singleshot'
+for task in @tasks
+  calendar.todo task do |todo|
+    todo.summary task.title
+    todo.description task.description
+    todo.url task_url(task)
+    todo.due task.due_on if task.due_on
+    todo.priority [1,5,9][task.priority - 1]
+    status = { 'ready'=>'NEEDS-ACTION', 'active'=>'IN-PROCESS' }[task.status] 
|| task.status.upcase
+    todo.status status
+    todo.organizer "MAILTO:#{task.creator.email}" if task.creator
+    todo.completed task.completed_on if task.completed_on
+  end
+end

Modified: ode/sandbox/singleshot/lib/extensions/ical_template.rb
URL: 
http://svn.apache.org/viewvc/ode/sandbox/singleshot/lib/extensions/ical_template.rb?rev=656967&r1=656966&r2=656967&view=diff
==============================================================================
--- ode/sandbox/singleshot/lib/extensions/ical_template.rb (original)
+++ ode/sandbox/singleshot/lib/extensions/ical_template.rb Fri May 16 01:38:11 
2008
@@ -1,53 +1,89 @@
 module ActionView
   class ICalBuilder
 
-    class Event
+    class Component
 
-      def initialize
+      def initialize(request, record = nil)
         @properties = {}
+        # TODO: created, last-mod, uid
+        if record
+          uid "#{request.host}:#{record.class}/#{record.id}"
+          dtstamp record.created_at.utc.strftime('%Y%m%dT%H%M%SZ') if 
record.respond_to?(:created_at)
+          last_modified record.updated_at.utc.strftime('%Y%m%dT%H%M%SZ') if 
record.respond_to?(:updated_at)
+          sequence record.send(record.class.locking_column) if 
record.locking_enabled?
+        end
       end
 
       attr_accessor :properties
 
       def to_ical
-        properties = @properties.map { |name, value| 
"#{name.to_s.upcase}:#{stringify(value)}" }
-        "BEGIN:VEVENT\n#{properties.join("\n")}\nEND:VEVENT"
+        properties = @properties.map { |name, value| property(name, value) }
+        "BEGIN:#{self.class.const_get 
:NAME}\n#{properties.join("\n")}\nEND:#{self.class.const_get :NAME}"
       end
 
     private
 
+      def property(name, value)
+        value = { :value=>value } unless Hash === value
+        name.to_s.underscore.upcase +
+          value.except(:value).map { |name, value| 
";#{name.to_s.underscore}=#{stringify(value)}" }.join +
+          ":#{stringify(value[:value])}"
+      end
+
       def stringify(value)
         case value
         when String then value
         when Date then value.strftime('%Y%m%d')
-        when Time then value.strftime('%Y%m%dT%H%M%S')
+        when Time then value.strftime(value.utc? ? '%Y%m%dT%H%M%SZ' : 
'%Y%m%dT%H%M%S')
         else value.to_s
         end
       end
 
-      def method_missing(name, arg)
-        @properties[name] = arg
+      def method_missing(name, *args)
+        options = args.extract_options!
+        options[:value] = args.first
+        @properties[name] = options
       end
 
     end
 
-    def initialize(prodid = nil)
-      @prodid = prodid
-      @events = []
+    class Event < Component
+
+      NAME = 'VEVENT'
+
+    end
+
+
+    class Todo < Component
+
+      NAME = 'VTODO'
+
+    end
+
+    def initialize(request)
+      @request =request
+      @components = []
     end
 
     attr_accessor :prodid
-    attr_reader :events
+    attr_reader :components
 
-    def event
-      returning Event.new do |event|
+    def event(record = nil)
+      returning Event.new(@request, record) do |event|
         yield event if block_given?
-        @events << event
+        @components << event
+      end
+    end
+
+    def todo(record = nil)
+      returning Todo.new(@request, record) do |todo|
+        yield todo if block_given?
+        @components << todo
       end
     end
 
     def to_ical
-      
"BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:#{prodid}\n#{events.map(&:to_ical).join("\n")}\nEND:VCALENDAR\n"
+      "BEGIN:VCALENDAR\nVERSION:2.0\nPRODID:[EMAIL 
PROTECTED](&:to_ical).join("\n")}\nEND:VCALENDAR\n"
     end
   end
 
@@ -63,7 +99,7 @@
       def compile(template)
         content_type_handler = 
(@view.send!(:controller).respond_to?(:response) ? "controller.response" : 
"controller")
         "#{content_type_handler}.content_type ||= Mime::ICS\n" +
-        "calendar = ::ActionView::ICalBuilder.new\n" +
+        "calendar = ::ActionView::ICalBuilder.new(request)\n" +
         template.source +
         "\ncalendar.to_ical\n"
       end


Reply via email to