queue_dispatcher 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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