PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/taskr/controllers.rb

http://ruby-taskr.googlecode.com/
Ruby | 344 lines | 258 code | 57 blank | 29 comment | 30 complexity | 47111c7296195caeb7fcc0a182f0d6d3 MD5 | raw file
Possible License(s): GPL-3.0, LGPL-2.1
  1. # This file is part of Taskr.
  2. #
  3. # Taskr is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 3 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # Taskr is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with Taskr. If not, see <http://www.gnu.org/licenses/>.
  15. module Taskr::Controllers
  16. class ActionTypes < REST 'action_types'
  17. def list
  18. @actions = Taskr::Actions.list
  19. render :action_list
  20. end
  21. end
  22. class Default < R '/'
  23. def get
  24. redirect Tasks
  25. end
  26. end
  27. class Actions < REST 'actions'
  28. def parameters_form(id)
  29. @num = input['num'] || 0
  30. @action = Taskr::Actions.list.find {|a| a.to_s =~ Regexp.new("#{id}$")}
  31. if @action
  32. render :action_parameters_form
  33. else
  34. @status = 404
  35. "Action #{id.inspect} not defined"
  36. end
  37. end
  38. def new
  39. @num = input['num'] || 0
  40. @actions = Taskr::Actions.list
  41. render :action_form
  42. end
  43. end
  44. class Tasks < REST 'tasks'
  45. include Taskr::Models
  46. # List of tasks.
  47. def list
  48. @tasks = Task.find(:all, :include => [:task_actions])
  49. render :tasks_list
  50. end
  51. # Input for a new task.
  52. def new
  53. @actions = Taskr::Actions.list
  54. render :new_task
  55. end
  56. # Retrieve details for an existing task.
  57. def read(id)
  58. @task = Task.find(id, :include => [:task_actions])
  59. render :view_task
  60. end
  61. def edit(task_id)
  62. @task = Task.find(task_id, :include => [:task_actions])
  63. @actions = Taskr::Actions.list
  64. render :edit_task
  65. end
  66. def update(task_id)
  67. $LOG.debug "Update Input params: #{@input.inspect}"
  68. @task = Task.find(task_id, :include => [:task_actions])
  69. params = normalize_input(@input)
  70. @task.attributes= {
  71. :name => params[:name],
  72. :schedule_method => params[:schedule_method],
  73. :schedule_when => params[:schedule_when],
  74. :memo => params[:memo]
  75. }
  76. @task.task_actions.each do |action|
  77. $LOG.debug("Updating parameters for #{action.inspect}")
  78. action_params = params[:action].delete("action_id_#{action.id}")
  79. $LOG.debug("Using values #{action_params.inspect}")
  80. next unless action_params
  81. action_params.each do |param_name, value|
  82. $LOG.debug("Looking up \"#{param_name}\". Setting value to \"#{value}\"")
  83. action.parameters.find_by_name(param_name).update_attribute(:value, value)
  84. end
  85. end
  86. # Create new actions/action_parameters for the remaining params
  87. unless params[:action].empty?
  88. params[:action].map do |num, params|
  89. $LOG.debug "Looping remaining action_parameters: #{params.inspect} (num: #{num})"
  90. action_class = get_action_class(params[:action_class_name])
  91. action = TaskAction.new(:order => params[:order] || (@task.task_actions.maximum(:order)+1) || num, :action_class_name => action_class.to_s)
  92. action_class.parameters.each do |p|
  93. value = params[p]
  94. value = nil if value.blank?
  95. action.action_parameters << TaskActionParameter.new(:name => p, :value => value)
  96. end
  97. @task.task_actions << action
  98. end
  99. end
  100. unless @task.valid?
  101. @status = 500
  102. @actions = Taskr::Actions.list
  103. else
  104. @task.save!
  105. @status = 200
  106. end
  107. @task.reload # Ensure any updates to the record goes in
  108. Taskr.scheduler.unschedule(@task.scheduler_job_id)
  109. @task.schedule! Taskr.scheduler
  110. $LOG.info "Task \"#{@task.name}\" (ID: #{@task.id}) updated sucessfully."
  111. redirect R(@task)
  112. end
  113. def normalize_input(hsh)
  114. hsh['task'] || hsh["0"] || hsh
  115. end
  116. def normalize_actions_params(input_params)
  117. $LOG.debug "normalize_actions_params Normalizing: #{input_params.inspect}"
  118. # some gymnastics here to provide compatibility for the way various
  119. # REST client libraries submit data
  120. actions_data = input_params[:actions] || input_params[:action]
  121. raise ArgumentError, "Missing action(s) parameter." if actions_data.blank?
  122. actions = case actions_data
  123. when Array
  124. $LOG.debug "normalize_actions_params Plain Array. Returning as-is."
  125. actions_data
  126. when Hash
  127. $LOG.debug "normalize_actions_params Some weird Hash. Injecting."
  128. actions_data.inject([]) do |acc,(i,a)|
  129. $LOG.debug "normalize_actions_params acc: #{acc.inspect} index: #{i.inspect} array: #{a.inspect}."
  130. acc << a
  131. acc
  132. end
  133. else
  134. $LOG.debug "normalize_actions_params Not a weird hash.\n\tactions_data[:action]: #{actions_data[:action].inspect}\n\tactions_data[:actions]: #{actions_data[:actions].inspect}\n\tactions_data: #{actions_data.inspect}\n\n"
  135. actions_data[:action] || actions_data[:actions] || actions_data
  136. end
  137. actions = [actions] unless actions.kind_of? Array
  138. $LOG.debug "normalize_actions_params DONE. Returning: #{actions.inspect}"
  139. actions
  140. end
  141. def get_action_class(class_name)
  142. action_class_name = "Taskr::Actions::#{class_name}" unless class_name =~ /^Taskr::Actions::/
  143. begin
  144. action_class = action_class_name.constantize
  145. unless action_class.include? Rufus::Schedulable
  146. raise ArgumentError,
  147. "#{a[:action_class_name].inspect} cannot be used as an action because it does not include the Rufus::Schedulable module."
  148. end
  149. rescue NameError
  150. raise ArgumentError,
  151. "#{a[:action_class_name].inspect} is not defined (i.e. there is no such action class)."
  152. end
  153. action_class
  154. end
  155. # Create and schedule a new task.
  156. def create
  157. $LOG.debug @input.inspect
  158. begin
  159. # the "0" is for compatibility with PHP's Zend_Rest_Client
  160. task_data = @input['task'] || @input["0"] || @input
  161. name = task_data[:name]
  162. created_by = @env['REMOTE_HOST']
  163. schedule_method = task_data[:schedule_method]
  164. schedule_when = task_data[:schedule_when]
  165. memo = task_data[:memo]
  166. @task = Task.new(
  167. :name => name,
  168. :created_by => created_by,
  169. :schedule_method => schedule_method,
  170. :schedule_when => schedule_when,
  171. :memo => memo
  172. )
  173. # some gymnastics here to provide compatibility for the way various
  174. # REST client libraries submit data
  175. actions_data = task_data[:actions] || task_data[:action]
  176. raise ArgumentError, "Missing action(s) parameter." if actions_data.blank?
  177. if actions_data.kind_of?(Array)
  178. actions = actions_data
  179. elsif actions_data["0"]
  180. actions = []
  181. actions_data.each do |i,a|
  182. actions << a
  183. end
  184. else
  185. actions = actions_data[:action] || actions_data[:actions] || actions_data
  186. end
  187. actions = [actions] unless actions.kind_of? Array
  188. #puts actions.inspect
  189. i = 0
  190. actions.each do |a|
  191. #puts a.inspect
  192. action_class_name = a[:action_class_name]
  193. action_class_name = "Taskr::Actions::#{action_class_name}" unless action_class_name =~ /^Taskr::Actions::/
  194. begin
  195. action_class = action_class_name.constantize
  196. unless action_class.include? Rufus::Schedulable
  197. raise ArgumentError,
  198. "#{a[:action_class_name].inspect} cannot be used as an action because it does not include the Rufus::Schedulable module."
  199. end
  200. rescue NameError
  201. raise ArgumentError,
  202. "#{a[:action_class_name].inspect} is not defined (i.e. there is no such action class)."
  203. end
  204. action = TaskAction.new(:order => a[:order] || i, :action_class_name => action_class_name)
  205. $LOG.debug "Action should be initialized and ready for creation: #{action.inspect}"
  206. action_class.parameters.each do |p|
  207. value = a[p]
  208. value = nil if value.blank?
  209. action.action_parameters << TaskActionParameter.new(:name => p, :value => value)
  210. end
  211. @task.task_actions << action
  212. i += 1
  213. end
  214. unless @task.valid?
  215. @status = 500
  216. @actions = Taskr::Actions.list
  217. return render(:new_task)
  218. end
  219. @task.schedule! Taskr.scheduler
  220. if @task.save!
  221. location = "/tasks/#{@task.id}?format=#{@format}"
  222. $LOG.debug "#{@task} saved successfuly. Setting Location header to #{location.inspect}."
  223. @headers['Location'] = location
  224. end
  225. return render(:view_task)
  226. rescue => e
  227. puts e.inspect
  228. puts e.backtrace
  229. raise e
  230. end
  231. end
  232. def run(id)
  233. @task = Task.find(id, :include => [:task_actions])
  234. action = @task.prepare_action
  235. LogEntry.info(@task, "Manually executing task #{@task}.")
  236. begin
  237. action.trigger
  238. rescue
  239. # ok to catch exception silently. it should have gotten logged by the action
  240. end
  241. redirect R(@task)
  242. end
  243. # Unschedule and delete an existing task.
  244. def destroy(id)
  245. @task = Task.find(id)
  246. if @task.scheduler_job_id
  247. $LOG.debug "Unscheduling task #{@task}..."
  248. Taskr.scheduler.unschedule(@task.scheduler_job_id)
  249. end
  250. @task.destroy
  251. if @task.frozen?
  252. @status = 200
  253. if @format == :XML
  254. ""
  255. else
  256. return redirect(R(Tasks, :list))
  257. end
  258. else
  259. _error("Task #{id} was not destroyed.", 500)
  260. end
  261. end
  262. # Reload a task
  263. def reload(id)
  264. @task = Task.find(id)
  265. $LOG.debug "Re-scheduling task #{@task}..."
  266. if @task.scheduler_job_id
  267. Taskr.scheduler.unschedule(@task.scheduler_job_id)
  268. $LOG.debug "\t...unscheduled task #{@task}..."
  269. end
  270. @task.schedule! Taskr.scheduler
  271. $LOG.debug "\t...scheduled task #{@task}...\n"
  272. redirect R(@task)
  273. end
  274. end
  275. class LogEntries < REST 'log_entries'
  276. def list
  277. @since = input['since']
  278. @level = ['DEBUG', 'INFO', 'WARN', 'ERROR']
  279. @level.index(input['level']).times {@level.shift} if input['level']
  280. @log_entries = LogEntry.find(:all,
  281. :conditions => ['task_id = ? AND IF(?,timestamp > ?,1) AND level IN (?)',
  282. input['task_id'], !@since.blank?, @since, @level],
  283. :order => 'timestamp DESC, id DESC')
  284. render :log_entries_list
  285. end
  286. end
  287. end