queue_dispatcher 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +55 -0
  5. data/Rakefile +2 -0
  6. data/app/assets/images/icon_acquire_lock.png +0 -0
  7. data/app/assets/images/icon_error.png +0 -0
  8. data/app/assets/images/icon_init_queue.gif +0 -0
  9. data/app/assets/images/icon_pending.gif +0 -0
  10. data/app/assets/images/icon_running.gif +0 -0
  11. data/app/assets/images/icon_successful.png +0 -0
  12. data/app/assets/images/icon_warning.gif +0 -0
  13. data/app/assets/images/lock.png +0 -0
  14. data/app/assets/javascript/tasks.js.coffee +8 -0
  15. data/app/helpers/tasks_helper.rb +28 -0
  16. data/app/models/task_dependency.rb +2 -0
  17. data/app/views/queue_dispatcher_views/_search_results_events.html.haml +4 -0
  18. data/app/views/queue_dispatcher_views/_search_results_my_events.html.haml +4 -0
  19. data/app/views/queue_dispatcher_views/_task_event.html.haml +24 -0
  20. data/app/views/queue_dispatcher_views/_task_footer.html.erb +1 -0
  21. data/app/views/queue_dispatcher_views/_task_header.html.erb +12 -0
  22. data/app/views/queue_dispatcher_views/_task_my_event.html.haml +24 -0
  23. data/app/views/queue_dispatcher_views/expand_event.js.rjs +1 -0
  24. data/app/views/queue_dispatcher_views/my_events.html.haml +7 -0
  25. data/app/views/queue_dispatcher_views/my_events.js.erb +6 -0
  26. data/app/views/queue_dispatcher_views/update_events.js.erb +15 -0
  27. data/lib/generators/queue_dispatcher/migration/migration_generator.rb +51 -0
  28. data/lib/generators/queue_dispatcher/migration/templates/task_dependencies.rb +16 -0
  29. data/lib/generators/queue_dispatcher/migration/templates/task_queues.rb +18 -0
  30. data/lib/generators/queue_dispatcher/migration/templates/tasks.rb +25 -0
  31. data/lib/queue_dispatcher/acts_as_task.rb +194 -0
  32. data/lib/queue_dispatcher/acts_as_task_controller.rb +95 -0
  33. data/lib/queue_dispatcher/acts_as_task_queue.rb +447 -0
  34. data/lib/queue_dispatcher/deserialization_error.rb +4 -0
  35. data/lib/queue_dispatcher/message_sending.rb +31 -0
  36. data/lib/queue_dispatcher/psych_ext.rb +127 -0
  37. data/lib/queue_dispatcher/qd_logger.rb +15 -0
  38. data/lib/queue_dispatcher/rc_and_msg.rb +60 -0
  39. data/lib/queue_dispatcher/serialization/active_record.rb +20 -0
  40. data/lib/queue_dispatcher/syck_ext.rb +34 -0
  41. data/lib/queue_dispatcher/version.rb +3 -0
  42. data/lib/queue_dispatcher/yaml_ext.rb +10 -0
  43. data/lib/queue_dispatcher.rb +20 -0
  44. data/lib/tasks/queue_dispatcher.rake +7 -0
  45. data/queue_dispatcher.gemspec +26 -0
  46. data/script/queue_worker_dispatcher +259 -0
  47. metadata +187 -0
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in queue_dispatcher.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011-2012 Philip Kurmann
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,55 @@
1
+ = QueueDispatcher for Rails3
2
+
3
+ This Rails3 Gem implements a method to perform long running methods in the background.
4
+ Background tasks will be executed by persistent workers.
5
+
6
+ == Install
7
+
8
+ Inside your Gemfile:
9
+
10
+ gem "queue_dispatcher"
11
+
12
+ and then run:
13
+
14
+ * bundle install
15
+ * rake queue_dispatcher:sync
16
+
17
+ === Gem Dependencies
18
+
19
+ Please check if all those requirements are satisfied on your environment.
20
+
21
+ * rails >= 3.0.0
22
+ * sys-proctable >= 0.9.1
23
+
24
+
25
+ == Inside your application
26
+
27
+ To enqueue a long running task, simple call a method through enque:
28
+ E.g.:
29
+ Assume, you have a long running job:
30
+ LongRunningMailJob.send_mail
31
+
32
+ Now we'd like to execute it in the background by simply calling:
33
+ task = LongRunningMailJob.enqueue.send_mail
34
+
35
+ If you like to put the job in a queue, you can do this by execute it the following way:
36
+ task = LongRunningMailJob.enqueue(queue: 'queue_name').send_mail
37
+
38
+ Jobs inside a queue are executed serialized, not in parallel. You can define dependencies. A task is then executed only after all dependent tasks are finished. Code to add Task dependencies:
39
+ task.dependent_tasks = another_task
40
+
41
+ == Generators
42
+
43
+ * rails generate queue_dispatcher:migration
44
+
45
+ === Database Setup
46
+
47
+ Use
48
+
49
+ rails g queue_dispatcher:migration
50
+
51
+ This will create a database migration for the models Task and TaskQueues.
52
+
53
+ == Copyright
54
+
55
+ Copyright (c) 2011 - 2012 Philip Kurmann. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,8 @@
1
+ jQuery ->
2
+ if jQuery('.pagination').length
3
+ jQuery(window).scroll ->
4
+ url = jQuery('.pagination .next_page').attr('href')
5
+ if url && jQuery(window).scrollTop() > jQuery(document).height() - jQuery(window).height() - 50
6
+ jQuery('.pagination').text('Fetching more events...')
7
+ jQuery.getScript(url)
8
+ jQuery(window).scroll
@@ -0,0 +1,28 @@
1
+ module TasksHelper
2
+ def icon_for_task task
3
+ icon = 'icon_warning.gif'
4
+ alt = 'Unknwon'
5
+
6
+ if task.pending?
7
+ icon = 'icon_pending.gif'
8
+ alt = 'Pending'
9
+ elsif task.init_queue?
10
+ icon = 'icon_init_queue.gif'
11
+ alt = 'Initialize Queue'
12
+ elsif task.acquire_lock?
13
+ icon = 'icon_acquire_lock.png'
14
+ alt = 'Acquire Lock'
15
+ elsif task.running?
16
+ icon = 'icon_running.gif'
17
+ alt = 'Running'
18
+ elsif task.successful?
19
+ icon = 'icon_successful.png'
20
+ alt = 'Successful'
21
+ elsif task.error?
22
+ icon = 'icon_error.png'
23
+ alt = 'Error!'
24
+ end
25
+
26
+ image_tag(icon, :alt => alt)
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ class TaskDependency < ActiveRecord::Base
2
+ end
@@ -0,0 +1,4 @@
1
+ #events
2
+ %table#events_table.table.table-striped
3
+ - @tasks.each do |task|
4
+ = render :partial => 'queue_dispatcher_views/task_event', :locals => { :task => task }
@@ -0,0 +1,4 @@
1
+ #events
2
+ %table#events_table.table.table-striped
3
+ - @tasks.each do |task|
4
+ = render :partial => 'queue_dispatcher_views/task_my_event', :locals => { :task => task }
@@ -0,0 +1,24 @@
1
+ - if task.error_msg.blank?
2
+ - event_class = "event"
3
+ - event_onclick = ""
4
+ - else
5
+ - event_class = "event pointer"
6
+ - event_onclick = onclick_to_remote :url => {:controller => 'tasks', :action => 'expand_event'}, :with => "'id=#{task.id}'"
7
+
8
+ - if @expanded_events.include? task.id
9
+ - event_style = ""
10
+ - else
11
+ - event_style = "display:none"
12
+
13
+ %tr{:id => "task_#{task.id}", :class => event_class, :onclick => event_onclick }
14
+ %td.qd_icon
15
+ = icon_for_task task
16
+ = "#{task.perc_finished}%" if task.running?
17
+ %td.qd_date= task.updated_at.to_s :history
18
+ %td.qd_prosa
19
+ = task.prosa
20
+ - unless task.error_msg.blank?
21
+ = image_tag 'icon_expand.gif'
22
+ %div{:id => "task_#{task.id}_details", :class => 'qd_error_msg', :style => event_style}
23
+ = task.error_msg
24
+ %br
@@ -0,0 +1,12 @@
1
+ <table>
2
+ <tr>
3
+ <th>ID</th>
4
+ <th>Action</th>
5
+ <th>Target Object</th>
6
+ <th>Remark</th>
7
+ <th>Task List</th>
8
+ <th>Priority</th>
9
+ <th>State</th>
10
+ <th>Message</th>
11
+ <th>Error Message</th>
12
+ </tr>
@@ -0,0 +1,24 @@
1
+ - if task.error_msg.blank?
2
+ - event_class = "event"
3
+ - event_onclick = ""
4
+ - else
5
+ - event_class = "event pointer"
6
+ - event_onclick = onclick_to_remote :url => {:action => 'expand_event'}, :with => "'id=#{task.id}'"
7
+
8
+ - if @expanded_events.include? task.id
9
+ - event_style = ""
10
+ - else
11
+ - event_style = "display:none"
12
+
13
+ %tr{:id => "task_#{task.id}", :class => event_class, :onclick => event_onclick }
14
+ %td.qd_icon
15
+ = icon_for_task task
16
+ = task.perc_finished if task.running?
17
+ %td.qd_date= task.updated_at.to_s :history
18
+ %td.qd_prosa
19
+ = task.prosa
20
+ - unless task.error_msg.blank?
21
+ = image_tag 'icon_expand.gif'
22
+ %div{:id => "task_#{task.id}_details", :class => 'qd_error_msg', :style => event_style}
23
+ = task.error_msg
24
+ %br
@@ -0,0 +1 @@
1
+ page.visual_effect :toggle_blind, "task_#{@task.id}_details", :duration => 0.1
@@ -0,0 +1,7 @@
1
+ - title "Tasks and Events"
2
+ = periodically_call_remote :url => {:action => 'my_events'},
3
+ :frequency => 5,
4
+ :condition => 'running_task_queues'
5
+ = render :partial => 'queue_dispatcher_views/search_results_my_events'
6
+ %br/
7
+ = will_paginate @tasks
@@ -0,0 +1,6 @@
1
+ jQuery('#events').append('<%= j render(partial: "queue_dispatcher_views/search_results_my_events") %>');
2
+ <% if @tasks.next_page %>
3
+ jQuery('.pagination').replaceWith('<%= j will_paginate(@tasks) %>');
4
+ <% else %>
5
+ jQuery('.pagination').remove();
6
+ <% end %>
@@ -0,0 +1,15 @@
1
+ <% @new_tasks.each do |task| %>
2
+ jQuery('#events_table').prepend('<%=j render(partial: 'queue_dispatcher_views/task_event', locals: {task: task}) %>');
3
+ jQuery('#task_<%= task.id %>').effect('highlight');
4
+ <% end %>
5
+
6
+ <% @updated_tasks.each do |task| %>
7
+ jQuery('#task_<%= task.id %>').replaceWith('<%=j render(partial: 'queue_dispatcher_views/task_event', locals: {task: task}) %>');
8
+ jQuery('#task_<%= task.id %>').effect('highlight');
9
+ <% end %>
10
+
11
+ <% @deleted_task_ids.each do |id| %>
12
+ jQuery('#task_<%= id %>).fadeOut();
13
+ <% end %>
14
+
15
+ <%= update_flash %>
@@ -0,0 +1,51 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/migration'
3
+
4
+ module QueueDispatcher
5
+ class MigrationGenerator < Rails::Generators::Base
6
+ desc "The queue_dispatcher migration generator creates a database migration for the task_queue model."
7
+ include Rails::Generators::Migration
8
+ source_root File.join(File.dirname(__FILE__), 'templates')
9
+
10
+ class_option :task_queues_table_name,
11
+ :type => :string,
12
+ :desc => "Name for the TaskQueue Table",
13
+ :required => false,
14
+ :default => "task_queues"
15
+
16
+ class_option :tasks_table_name,
17
+ :type => :string,
18
+ :desc => "Name for the Task Table",
19
+ :required => false,
20
+ :default => "tasks"
21
+
22
+ class_option :task_dependencies_table_name,
23
+ :type => :string,
24
+ :desc => "Name for the Task Dependency Table",
25
+ :required => false,
26
+ :default => "task_dependencies"
27
+
28
+ def initialize(args = [], options = {}, config = {})
29
+ super
30
+ end
31
+
32
+ #attr_reader :lock_table_name
33
+
34
+ # Implement the required interface for Rails::Generators::Migration.
35
+ # taken from http://github.com/rails/rails/blob/master/activerecord/lib/generators/active_record.rb
36
+ def self.next_migration_number(dirname)
37
+ if ActiveRecord::Base.timestamped_migrations
38
+ [Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % (current_migration_number(dirname) + 1)].max
39
+ else
40
+ "%.3d" % (current_migration_number(dirname) + 1)
41
+ end
42
+ end
43
+
44
+ def create_migration_file
45
+ migration_template 'task_queues.rb', 'db/migrate/create_task_queues.rb'
46
+ migration_template 'tasks.rb', 'db/migrate/create_tasks.rb'
47
+ migration_template 'task_dependencies.rb', 'db/migrate/create_task_dependencies.rb'
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ class CreateTaskDependencies < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "<%= options[:task_dependencies_table_name] %>" do |t|
4
+ t.integer :task_id
5
+ t.integer :dependent_task_id
6
+
7
+ t.timestamps
8
+ end
9
+ add_index "<%= options[:task_dependencies_table_name] %>", :task_id
10
+ add_index "<%= options[:task_dependencies_table_name] %>", :dependent_task_id
11
+ end
12
+
13
+ def self.down
14
+ drop_table "<%= options[:task_dependencies_table_name] %>"
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ class CreateTaskQueues < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "<%= options[:task_queues_table_name] %>" do |t|
4
+ t.string :name
5
+ t.string :state
6
+ t.integer :pid
7
+ t.boolean :terminate_immediately
8
+
9
+ t.timestamps
10
+ end
11
+
12
+ add_index "<%= options[:task_queues_table_name] %>", :name
13
+ end
14
+
15
+ def self.down
16
+ drop_table "<%= options[:task_queues_table_name] %>"
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ class CreateTasks < ActiveRecord::Migration
2
+ def self.up
3
+ create_table "<%= options[:tasks_table_name] %>" do |t|
4
+ t.text :target
5
+ t.string :method_name
6
+ t.text :args
7
+ t.string :state
8
+ t.integer :priority
9
+ t.string :message
10
+ t.integer :perc_finished
11
+ t.string :remark
12
+ t.text :output
13
+ t.text :error_msg
14
+ t.integer :task_queue_id
15
+
16
+ t.timestamps
17
+ end
18
+
19
+ add_index "<%= options[:tasks_table_name] %>", :task_queue_id
20
+ end
21
+
22
+ def self.down
23
+ drop_table "<%= options[:tasks_table_name] %>"
24
+ end
25
+ end
@@ -0,0 +1,194 @@
1
+ module QueueDispatcher
2
+ module ActsAsTask
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+
8
+ class Config
9
+ attr_reader :task_queue_class_name
10
+
11
+ def initialize(task_queue_class_name)
12
+ @task_queue_class_name = task_queue_class_name.to_s.underscore
13
+ end
14
+ end
15
+
16
+
17
+ module ClassMethods
18
+ def acts_as_task args = {}
19
+ # Include number-helper for number_to_human_size method
20
+ include ActionView::Helpers::NumberHelper
21
+
22
+ include QueueDispatcher::ActsAsTask::InstanceMethods
23
+ extend QueueDispatcher::ActsAsTask::SingletonMethods
24
+
25
+ @acts_as_task_config = QueueDispatcher::ActsAsTask::Config.new(args[:task_queue_model] || :task_queue)
26
+
27
+ belongs_to acts_as_task_config.task_queue_class_name
28
+ has_many :task_dependencies, :dependent => :destroy, :foreign_key => :task_id
29
+ has_many :dependent_tasks, :through => :task_dependencies
30
+ has_many :inverse_task_dependencies, :class_name => 'TaskDependency', :foreign_key => 'dependent_task_id', :dependent => :destroy
31
+ has_many :inverse_dependent_tasks, :through => :inverse_task_dependencies, :source => :task
32
+ validates_presence_of :target, :method_name, :state
33
+ serialize :target
34
+ serialize :args
35
+
36
+ # Add dynamic associations to task_dependency and task_property according to the class name
37
+ TaskDependency.instance_eval %Q{
38
+ belongs_to :task, :class_name => '#{self.name}'
39
+ belongs_to :dependent_task, :class_name => '#{self.name}'
40
+ }
41
+ end
42
+ end
43
+
44
+
45
+ module SingletonMethods
46
+ def acts_as_task_config
47
+ @acts_as_task_config
48
+ end
49
+ end
50
+
51
+
52
+ module InstanceMethods
53
+ def acts_as_task_task_queue
54
+ self.send(self.class.acts_as_task_config.task_queue_class_name)
55
+ end
56
+
57
+
58
+ # Add task_id to the args
59
+ def args
60
+ a = super
61
+ a[-1] = a.last.merge(task_id: self.id) if a && a.instance_of?(Array) && a.last.instance_of?(Hash)
62
+ a
63
+ end
64
+
65
+
66
+ # This method updates the task state according to the return code of their corresponding command
67
+ def update_state(rc_and_msg)
68
+ rc = output = error_msg = nil
69
+
70
+ if rc_and_msg.kind_of?(QueueDispatcher::RcAndMsg)
71
+ rc = rc_and_msg.rc
72
+ output = rc_and_msg.output
73
+ error_msg = rc_and_msg.error_msg
74
+ elsif rc_and_msg.kind_of?(Hash)
75
+ rc = rc_and_msg[:rc]
76
+ output = rc_and_msg[:output]
77
+ error_msg = rc_and_msg[:error_msg]
78
+ end
79
+
80
+ if rc.nil? || rc == 0
81
+ self.update_attributes :state => "successful",
82
+ :perc_finished => 100,
83
+ :message => output
84
+ else
85
+ self.update_attributes :state => "error",
86
+ :error_msg => error_msg,
87
+ :message => output
88
+ end
89
+ end
90
+
91
+
92
+ # Update the attributes perc_finished and message according to the args
93
+ def update_message args = {}
94
+ msg = args[:msg]
95
+ perc_finished = args[:perc_finished]
96
+
97
+ self.update_attribute :message, msg if msg
98
+ self.update_attribute :perc_finished, perc_finished if perc_finished
99
+ end
100
+
101
+
102
+ # Is this task new?
103
+ def new?
104
+ state == 'new' || state == 'new_popped'
105
+ end
106
+
107
+
108
+ # Is this task pending?
109
+ def pending?
110
+ acts_as_task_task_queue && state == 'new'
111
+ end
112
+
113
+
114
+ # Is this task pending?
115
+ def acquire_lock?
116
+ acts_as_task_task_queue && acts_as_task_task_queue.running? && state == 'acquire_lock'
117
+ end
118
+
119
+
120
+ # Is this task running?
121
+ def running?
122
+ acts_as_task_task_queue && acts_as_task_task_queue.running? && state == 'running'
123
+ end
124
+
125
+
126
+ # Was this task finsihed successful?
127
+ def successful?
128
+ state == 'successful' || state == 'finished'
129
+ end
130
+
131
+
132
+ # Had this task error(s)?
133
+ def error?
134
+ state == 'error' || state.blank?
135
+ end
136
+
137
+
138
+ # Was this task aborted?
139
+ def aborted?
140
+ state == 'aborted'
141
+ end
142
+
143
+
144
+ # Is this task waiting until the queue is initialized?
145
+ def init_queue?
146
+ state == 'init_queue'
147
+ end
148
+
149
+
150
+ # Was this task already executed?
151
+ def executed?
152
+ successful? || error? || aborted?
153
+ end
154
+
155
+
156
+ # Are all dependent_tasks executed?
157
+ def dependent_tasks_executed?
158
+ state = true
159
+ dependent_tasks.each{ |dt| state = false unless dt.executed? }
160
+ state
161
+ end
162
+
163
+
164
+ # Check recursive, if one or more of the tasks, which this task is dependent on had errors
165
+ def dependent_tasks_had_errors
166
+ error = false
167
+ dependent_tasks.each do |t|
168
+ error = true if t.state == 'error' || t.dependent_tasks_had_errors
169
+ end
170
+ error
171
+ end
172
+
173
+
174
+ # Placeholder. Please override it in your model.
175
+ def prosa
176
+ end
177
+
178
+
179
+ # Calculate md5-Checksum
180
+ def md5
181
+ attr_str = ""
182
+ Task.attribute_names.each{ |a| attr_str += self.send(a).to_s }
183
+ Digest('MD5').digest(attr_str)
184
+ end
185
+
186
+
187
+ # Execute task
188
+ def execute!
189
+ target.send(method_name, *args)
190
+ end
191
+
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,95 @@
1
+ module QueueDispatcher
2
+ module ActsAsTaskController
3
+ def self.included(base)
4
+ base.extend(ClassMethods)
5
+ end
6
+
7
+
8
+ class Config
9
+ attr_reader :task_class_name
10
+
11
+ def initialize(task_class_name)
12
+ @task_class_name = task_class_name.to_s.underscore
13
+ end
14
+ end
15
+
16
+
17
+ module ClassMethods
18
+ def acts_as_task_controller args = {}
19
+ include QueueDispatcher::ActsAsTaskController::InstanceMethods
20
+ extend QueueDispatcher::ActsAsTaskController::SingletonMethods
21
+ @acts_as_task_controller_config = QueueDispatcher::ActsAsTaskController::Config.new(args[:task_model] || :task)
22
+ end
23
+ end
24
+
25
+
26
+ module SingletonMethods
27
+ def acts_as_task_controller_config
28
+ @acts_as_task_controller_config
29
+ end
30
+ end
31
+
32
+
33
+ module InstanceMethods
34
+ def my_events
35
+ # Remember the selected page, if the AJAX-Request wants to update the current page
36
+ page = session[:my_events_page] = params[:page] if params[:page] || ! request.xhr?
37
+ page = session[:my_events_page] if page.nil? && request.xhr?
38
+ @tasks = current_user.send(self.class.acts_as_task_controller_config.task_class_name.pluralize).order('id DESC').page(page)
39
+
40
+ # Check for updated tasks
41
+ session[:task_updates] ||= {}
42
+ task_updates = {}
43
+ @new_tasks = []
44
+ @updated_tasks = []
45
+ @deleted_task_ids = []
46
+
47
+ if @tasks
48
+ @tasks.page(1).each do |task|
49
+ task_updates[task.id] = task.updated_at
50
+ @new_tasks << task unless session[:task_updates][task.id]
51
+ @updated_tasks << task if session[:task_updates][task.id] && session[:task_updates][task.id] != task.updated_at
52
+ end
53
+ session[:task_updates].each{ |id, updated_at| @deleted_task_ids << id unless eval(self.class.acts_as_task_controller_config.task_class_name.camelize).find_by_id(id) }
54
+ session[:task_updates] = task_updates
55
+ end
56
+
57
+ if request.xhr?
58
+ # Load expanded_events from session if this is a AJAX-request
59
+ @expanded_events = session[:acts_as_task_controller_expanded_events] || []
60
+ else
61
+ # Reset expanded_events if this is a regular request
62
+ @expanded_events = session[:acts_as_task_controller_expanded_events] = []
63
+ end
64
+
65
+ respond_to do |format|
66
+ format.html { render 'queue_dispatcher_views/my_events' }
67
+ format.js do
68
+ if params[:page]
69
+ render
70
+ else
71
+ render 'queue_dispatcher_views/update_events'
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+
78
+ def expand_event
79
+ @task = eval(self.class.acts_as_task_controller_config.task_class_name.camelize).find(params[:id])
80
+ @expanded_events = session[:acts_as_task_controller_expanded_events] || []
81
+ if @expanded_events.include? @task.id
82
+ @expanded_events -= [@task.id]
83
+ else
84
+ @expanded_events |= [@task.id]
85
+ end
86
+ session[:acts_as_task_controller_expanded_events] = @expanded_events
87
+
88
+ respond_to do |format|
89
+ format.js { render 'queue_dispatcher_views/expand_event' }
90
+ end
91
+ end
92
+ end
93
+
94
+ end
95
+ end