PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/app/controllers/todos_controller.rb

https://github.com/jasonrwagner/tracks
Ruby | 1452 lines | 1196 code | 192 blank | 64 comment | 194 complexity | 8ae07d0be833834a59d8e114b9479276 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. class TodosController < ApplicationController
  2. skip_before_filter :login_required, :only => [:index, :calendar, :tag]
  3. prepend_before_filter :login_or_feed_token_required, :only => [:index, :calendar, :tag]
  4. append_before_filter :find_and_activate_ready, :only => [:index, :list_deferred]
  5. # # TODO: replace :except with :only
  6. # append_before_filter :init, :except => [ :tag, :tags, :destroy, :done,
  7. # :check_deferred, :toggle_check, :toggle_star, :edit, :update, :defer, :create,
  8. # :calendar, :auto_complete_for_predecessor, :remove_predecessor, :add_predecessor]
  9. protect_from_forgery :except => :check_deferred
  10. def index
  11. @source_view = params['_source_view'] || 'todo'
  12. init_data_for_sidebar unless mobile?
  13. @todos = current_user.todos.includes(Todo::DEFAULT_INCLUDES)
  14. # TODO: refactor text feed for done todos to todos/done.text, not /todos.text?done=true
  15. if params[:done]
  16. @not_done_todos = current_user.todos.completed.completed_after(Time.zone.now - params[:done].to_i.days)
  17. else
  18. @not_done_todos = current_user.todos.active.not_hidden
  19. end
  20. @not_done_todos = @not_done_todos.
  21. reorder("todos.due IS NULL, todos.due ASC, todos.created_at ASC").
  22. includes(Todo::DEFAULT_INCLUDES)
  23. if params[:limit]
  24. @not_done_todos = @not_done_todos.limit(sanitize(params[:limit]))
  25. @todos = @todos.limit(sanitize(params[:limit]))
  26. end
  27. if params[:due]
  28. due_within_when = Time.zone.now + params['due'].to_i.days
  29. @not_done_todos = @not_done_todos.where('todos.due <= ?', due_within_when)
  30. end
  31. if params[:tag]
  32. tag = Tag.find_by_name(params['tag'])
  33. @not_done_todos = @not_done_todos.where('taggings.tag_id = ?', tag.id)
  34. end
  35. if params[:context_id]
  36. context = current_user.contexts.find(params[:context_id])
  37. @not_done_todos = @not_done_todos.where('context_id' => context.id)
  38. end
  39. if params[:project_id]
  40. project = current_user.projects.find(params[:project_id])
  41. @not_done_todos = @not_done_todos.where('project_id' => project)
  42. end
  43. @projects = current_user.projects.includes(:default_context)
  44. @contexts = current_user.contexts
  45. @contexts_to_show = current_user.contexts.active
  46. # If you've set no_completed to zero, the completed items box isn't shown
  47. # on the home page
  48. max_completed = current_user.prefs.show_number_completed
  49. @done = current_user.todos.completed.limit(max_completed).includes(Todo::DEFAULT_INCLUDES) unless max_completed == 0
  50. respond_to do |format|
  51. format.html do
  52. @page_title = t('todos.task_list_title')
  53. # Set count badge to number of not-done, not hidden context items
  54. @count = current_user.todos.active.not_hidden.count(:all)
  55. end
  56. format.m do
  57. @page_title = t('todos.mobile_todos_page_title')
  58. @home = true
  59. cookies[:mobile_url]= { :value => request.fullpath, :secure => SITE_CONFIG['secure_cookies']}
  60. determine_down_count
  61. render :action => 'index'
  62. end
  63. format.text do
  64. # somehow passing Mime::TEXT using content_type to render does not work
  65. headers['Content-Type']=Mime::TEXT.to_s
  66. render :content_type => Mime::TEXT
  67. end
  68. format.xml { render :xml => @todos.to_xml( *to_xml_params ) }
  69. format.rss { @feed_title, @feed_description = 'Tracks Actions', "Actions for #{current_user.display_name}" }
  70. format.atom { @feed_title, @feed_description = 'Tracks Actions', "Actions for #{current_user.display_name}" }
  71. format.ics
  72. end
  73. end
  74. def new
  75. @projects = current_user.projects.active
  76. @contexts = current_user.contexts
  77. respond_to do |format|
  78. format.m {
  79. @new_mobile = true
  80. @return_path=cookies[:mobile_url] ? cookies[:mobile_url] : mobile_path
  81. @mobile_from_context = current_user.contexts.find_by_id(params[:from_context]) if params[:from_context]
  82. @mobile_from_project = current_user.projects.find_by_id(params[:from_project]) if params[:from_project]
  83. if params[:from_project] && !params[:from_context]
  84. # we have a project but not a context -> use the default context
  85. @mobile_from_context = @mobile_from_project.default_context
  86. end
  87. }
  88. end
  89. end
  90. def create
  91. @source_view = params['_source_view'] || 'todo'
  92. @default_context = current_user.contexts.find_by_name(params['default_context_name'])
  93. @default_project = current_user.projects.find_by_name(params['default_project_name']) unless params['default_project_name'].blank?
  94. @tag_name = params['_tag_name']
  95. is_multiple = params[:todo] && params[:todo][:multiple_todos] && !params[:todo][:multiple_todos].nil?
  96. if is_multiple
  97. create_multiple
  98. else
  99. p = TodoCreateParamsHelper.new(params, prefs)
  100. p.parse_dates() unless mobile?
  101. tag_list = p.tag_list
  102. predecessor_list = p.predecessor_list
  103. @todo = current_user.todos.build(p.attributes)
  104. if p.project_specified_by_name?
  105. project = current_user.projects.find_or_create_by_name(p.project_name)
  106. @new_project_created = project.new_record_before_save?
  107. @todo.project_id = project.id
  108. elsif !(p.project_id.nil? || p.project_id.blank?)
  109. project = current_user.projects.find_by_id(p.project_id)
  110. @todo.errors[:project] << "unknown" if project.nil?
  111. end
  112. if p.context_specified_by_name?
  113. context = current_user.contexts.find_or_create_by_name(p.context_name)
  114. @new_context_created = context.new_record_before_save?
  115. @not_done_todos = [@todo] if @new_context_created
  116. @todo.context_id = context.id
  117. elsif !(p.context_id.nil? || p.context_id.blank?)
  118. context = current_user.contexts.find_by_id(p.context_id)
  119. @todo.errors[:context] << "unknown" if context.nil?
  120. end
  121. if @todo.errors.empty?
  122. @todo.starred= (params[:new_todo_starred]||"").include? "true" if params[:new_todo_starred]
  123. @todo.add_predecessor_list(predecessor_list)
  124. @saved = @todo.save
  125. @todo.update_state_from_project if @saved
  126. else
  127. @saved = false
  128. end
  129. unless ( !@saved ) || tag_list.blank?
  130. @todo.tag_with(tag_list)
  131. @todo.tags.reload
  132. end
  133. if @saved
  134. @todo.block! unless @todo.uncompleted_predecessors.empty? || @todo.state == 'project_hidden'
  135. @saved = @todo.save
  136. end
  137. @todo.reload if @saved
  138. @todo_was_created_deferred = @todo.deferred?
  139. @todo_was_created_blocked = @todo.pending?
  140. respond_to do |format|
  141. format.html { redirect_to :action => "index" }
  142. format.m do
  143. @return_path=cookies[:mobile_url] ? cookies[:mobile_url] : mobile_path
  144. if @saved
  145. redirect_to @return_path
  146. else
  147. @projects = current_user.projects
  148. @contexts = current_user.contexts
  149. render :action => "new"
  150. end
  151. end
  152. format.js do
  153. if @saved
  154. determine_down_count
  155. @contexts = current_user.contexts if @new_context_created
  156. @projects = current_user.projects if @new_project_created
  157. @initial_context_name = params['default_context_name']
  158. @initial_project_name = params['default_project_name']
  159. @initial_tags = params['initial_tag_list']
  160. @status_message = t('todos.added_new_next_action')
  161. @status_message += ' ' + t('todos.to_tickler') if @todo.deferred?
  162. @status_message += ' ' + t('todos.in_pending_state') if @todo.pending?
  163. @status_message += ' ' + t('todos.in_hidden_state') if @todo.hidden?
  164. @status_message = t('todos.added_new_project') + ' / ' + @status_message if @new_project_created
  165. @status_message = t('todos.added_new_context') + ' / ' + @status_message if @new_context_created
  166. end
  167. render :action => 'create'
  168. end
  169. format.xml do
  170. if @saved
  171. head :created, :location => todo_url(@todo)
  172. else
  173. render_failure @todo.errors.to_xml.html_safe, 409
  174. end
  175. end
  176. end
  177. end
  178. end
  179. def create_multiple
  180. if project_specified_by_name(params[:project_name])
  181. project = current_user.projects.find_or_create_by_name(params[:project_name])
  182. @new_project_created = project.new_record_before_save?
  183. @project_id = project.id
  184. end
  185. if context_specified_by_name(params[:context_name])
  186. context = current_user.contexts.find_or_create_by_name(params[:context_name])
  187. @new_context_created = context.new_record_before_save?
  188. @not_done_todos = [] if @new_context_created
  189. @context_id = context.id
  190. end
  191. tag_list = params[:tag_list]
  192. @sequential = !params[:todos_sequential].blank? && params[:todos_sequential]=='true'
  193. @todos_init = []
  194. @predecessor = nil
  195. validates = true
  196. errors = []
  197. # first build all todos and check if they would validate on save
  198. params[:todo][:multiple_todos].split("\n").map do |line|
  199. unless line.blank?
  200. @todo = current_user.todos.build(
  201. :description => line)
  202. @todo.project_id = @project_id
  203. @todo.context_id = @context_id
  204. validates = false if @todo.invalid?
  205. @todos_init << @todo
  206. end
  207. end
  208. # if all todos validate, then save them and add predecessors and tags
  209. @todos = []
  210. if validates
  211. @todos_init.each do |todo|
  212. @saved = todo.save
  213. validates = validates && @saved
  214. if @predecessor && @saved && @sequential
  215. todo.add_predecessor(@predecessor)
  216. todo.block!
  217. end
  218. unless (@saved == false) || tag_list.blank?
  219. todo.tag_with(tag_list)
  220. todo.tags.reload
  221. end
  222. @todos << todo
  223. @not_done_todos << todo if @new_context_created
  224. @predecessor = todo
  225. end
  226. else
  227. @todos = @todos_init
  228. @saved = false
  229. end
  230. respond_to do |format|
  231. format.html { redirect_to :action => "index" }
  232. format.js do
  233. determine_down_count if @saved
  234. @contexts = current_user.contexts if @new_context_created
  235. @projects = current_user.projects if @new_project_created
  236. @initial_context_name = params['default_context_name']
  237. @initial_project_name = params['default_project_name']
  238. @initial_tags = params['initial_tag_list']
  239. if @saved && @todos.size > 0
  240. @default_tags = @todos[0].project.default_tags unless @todos[0].project.nil?
  241. else
  242. @multiple_error = @todos.size > 0 ? "" : t('todos.next_action_needed')
  243. @saved = false
  244. @default_tags = current_user.projects.find_by_name(@initial_project_name).default_tags unless @initial_project_name.blank?
  245. end
  246. @status_message = @todos.size > 1 ? t('todos.added_new_next_action_plural') : t('todos.added_new_next_action_singular')
  247. @status_message = t('todos.added_new_project') + ' / ' + @status_message if @new_project_created
  248. @status_message = t('todos.added_new_context') + ' / ' + @status_message if @new_context_created
  249. render :action => 'create_multiple'
  250. end
  251. format.xml do
  252. if @saved
  253. head :created, :location => context_url(@todos[0].context)
  254. else
  255. render :xml => @todos[0].errors.to_xml, :status => 422
  256. end
  257. end
  258. end
  259. end
  260. def edit
  261. @todo = current_user.todos.find(params['id'])
  262. @source_view = params['_source_view'] || 'todo'
  263. @tag_name = params['_tag_name']
  264. respond_to do |format|
  265. format.js
  266. format.m {
  267. @projects = current_user.projects.active
  268. @contexts = current_user.contexts
  269. @edit_mobile = true
  270. @return_path=cookies[:mobile_url] ? cookies[:mobile_url] : mobile_path
  271. }
  272. end
  273. end
  274. def show
  275. @todo = current_user.todos.find_by_id(params['id'])
  276. respond_to do |format|
  277. format.m { render :action => 'show' }
  278. format.xml { render :xml => @todo.to_xml( *to_xml_params ) }
  279. end
  280. end
  281. def add_predecessor
  282. @source_view = params['_source_view'] || 'todo'
  283. @predecessor = current_user.todos.find_by_id(params['predecessor'])
  284. @predecessors = @predecessor.predecessors
  285. @todo = current_user.todos.includes(Todo::DEFAULT_INCLUDES).find_by_id(params['successor'])
  286. @original_state = @todo.state
  287. unless @predecessor.completed?
  288. @todo.add_predecessor(@predecessor)
  289. @todo.block! unless @todo.pending?
  290. @saved = @todo.save
  291. @status_message = t('todos.added_dependency', :dependency => @predecessor.description)
  292. @status_message += t('todos.set_to_pending', :task => @todo.description) unless @original_state == 'pending'
  293. else
  294. @saved = false
  295. end
  296. respond_to do |format|
  297. format.js
  298. end
  299. end
  300. def remove_predecessor
  301. @source_view = params['_source_view'] || 'todo'
  302. @todo = current_user.todos.includes(Todo::DEFAULT_INCLUDES).find_by_id(params['id'])
  303. @predecessor = current_user.todos.find_by_id(params['predecessor'])
  304. @predecessors = @predecessor.predecessors
  305. @successor = @todo
  306. @removed = @successor.remove_predecessor(@predecessor)
  307. determine_remaining_in_context_count
  308. respond_to do |format|
  309. format.js
  310. end
  311. end
  312. # Toggles the 'done' status of the action
  313. #
  314. def toggle_check
  315. @todo = current_user.todos.find(params['id'])
  316. @source_view = params['_source_view'] || 'todo'
  317. @original_item_due = @todo.due
  318. @original_item_was_deferred = @todo.deferred?
  319. @original_item_was_pending = @todo.pending?
  320. @original_item_was_hidden = @todo.hidden?
  321. @original_item_context_id = @todo.context_id
  322. @original_item_project_id = @todo.project_id
  323. @todo_was_completed_from_deferred_or_blocked_state = @original_item_was_deferred || @original_item_was_pending
  324. @saved = @todo.toggle_completion!
  325. @todo_was_blocked_from_completed_state = @todo.pending? # since we toggled_completion the previous state was completed
  326. # check if this todo has a related recurring_todo. If so, create next todo
  327. @new_recurring_todo = check_for_next_todo(@todo) if @saved
  328. @predecessors = @todo.uncompleted_predecessors
  329. if @saved
  330. if @todo.completed?
  331. @pending_to_activate = @todo.activate_pending_todos
  332. else
  333. @active_to_block = @todo.block_successors
  334. end
  335. end
  336. respond_to do |format|
  337. format.js do
  338. if @saved
  339. determine_remaining_in_context_count(@todo.context_id)
  340. determine_down_count
  341. determine_completed_count
  342. determine_deferred_tag_count(params['_tag_name']) if source_view_is(:tag)
  343. @wants_redirect_after_complete = @todo.completed? && !@todo.project_id.nil? && current_user.prefs.show_project_on_todo_done && !source_view_is(:project)
  344. if source_view_is :calendar
  345. @original_item_due_id = get_due_id_for_calendar(@original_item_due)
  346. @old_due_empty = is_old_due_empty(@original_item_due_id)
  347. end
  348. end
  349. render
  350. end
  351. format.xml { render :xml => @todo.to_xml( *to_xml_params ) }
  352. format.html do
  353. if @saved
  354. # TODO: I think this will work, but can't figure out how to test it
  355. notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete'))
  356. redirect_to :action => "index"
  357. else
  358. notify(:notice, t("todos.action_marked_complete_error", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete'), "index")
  359. redirect_to :action => "index"
  360. end
  361. end
  362. format.m {
  363. if @saved
  364. if cookies[:mobile_url]
  365. old_path = cookies[:mobile_url]
  366. cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']}
  367. notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete'))
  368. redirect_to old_path
  369. else
  370. notify(:notice, t("todos.action_marked_complete", :description => @todo.description, :completed => @todo.completed? ? 'complete' : 'incomplete'))
  371. redirect_to todos_path(:format => 'm')
  372. end
  373. else
  374. render :action => "edit", :format => :m
  375. end
  376. }
  377. end
  378. end
  379. def toggle_star
  380. @todo = current_user.todos.find_by_id(params['id'])
  381. @todo.toggle_star!
  382. @saved = true # cannot determine error
  383. respond_to do |format|
  384. format.js
  385. format.xml { render :xml => @todo.to_xml( *to_xml_params ) }
  386. format.html { redirect_to request.referrer}
  387. format.m {
  388. if cookies[:mobile_url]
  389. old_path = cookies[:mobile_url]
  390. cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']}
  391. notify(:notice, "Star toggled")
  392. redirect_to old_path
  393. else
  394. notify(:notice, "Star toggled")
  395. redirect_to todos_path(:format => 'm')
  396. end
  397. }
  398. end
  399. end
  400. def change_context
  401. # change context if you drag a todo to another context
  402. @todo = current_user.todos.find_by_id(params[:id])
  403. @original_item_context_id = @todo.context_id
  404. @context = current_user.contexts.find_by_id(params[:todo][:context_id])
  405. @todo.context = @context
  406. @saved = @todo.save
  407. @context_changed = true
  408. @status_message = t('todos.context_changed', :name => @context.name)
  409. determine_down_count
  410. determine_remaining_in_context_count(@original_item_context_id)
  411. respond_to do |format|
  412. format.js { render :action => :update }
  413. format.xml { render :xml => @todo.to_xml( *to_xml_params ) }
  414. end
  415. end
  416. def update
  417. @todo = current_user.todos.find_by_id(params['id'])
  418. @source_view = params['_source_view'] || 'todo'
  419. init_data_for_sidebar unless mobile?
  420. cache_attributes_from_before_update
  421. update_tags
  422. update_project
  423. update_context
  424. update_due_and_show_from_dates
  425. update_completed_state
  426. update_dependencies
  427. update_attributes_of_todo
  428. @saved = @todo.save
  429. # this is set after save and cleared after reload, so save it here
  430. @removed_predecessors = @todo.removed_predecessors
  431. @todo.reload # refresh context and project object too (not only their id's)
  432. update_dependency_state
  433. update_todo_state_if_project_changed
  434. determine_changes_by_this_update
  435. determine_remaining_in_context_count(@context_changed ? @original_item_context_id : @todo.context_id)
  436. determine_down_count
  437. determine_deferred_tag_count(params['_tag_name']) if source_view_is(:tag)
  438. respond_to do |format|
  439. format.js {
  440. @status_message = @todo.deferred? ? t('todos.action_saved_to_tickler') : t('todos.action_saved')
  441. @status_message = t('todos.added_new_project') + ' / ' + @status_message if @new_project_created
  442. @status_message = t('todos.added_new_context') + ' / ' + @status_message if @new_context_created
  443. }
  444. format.xml { render :xml => @todo.to_xml( *to_xml_params ) }
  445. format.m do
  446. if @saved
  447. do_mobile_todo_redirection
  448. else
  449. render :action => "edit", :format => :m
  450. end
  451. end
  452. end
  453. end
  454. def destroy
  455. @source_view = params['_source_view'] || 'todo'
  456. @todo = current_user.todos.find_by_id(params['id'])
  457. @original_item_due = @todo.due
  458. @context_id = @todo.context_id
  459. @project_id = @todo.project_id
  460. @todo_was_destroyed_from_deferred_state = @todo.deferred?
  461. @todo_was_destroyed_from_pending_state = @todo.pending?
  462. @todo_was_destroyed_from_deferred_or_pending_state = @todo_was_destroyed_from_deferred_state || @todo_was_destroyed_from_pending_state
  463. @uncompleted_predecessors = []
  464. @todo.uncompleted_predecessors.each do |predecessor|
  465. @uncompleted_predecessors << predecessor
  466. end
  467. # activate successors if they only depend on this todo
  468. activated_successor_count = 0
  469. @pending_to_activate = []
  470. @todo.pending_successors.each do |successor|
  471. successor.uncompleted_predecessors.delete(@todo)
  472. if successor.uncompleted_predecessors.empty?
  473. successor.activate!
  474. @pending_to_activate << successor
  475. activated_successor_count += 1
  476. end
  477. end
  478. @saved = @todo.destroy
  479. # check if this todo has a related recurring_todo. If so, create next todo
  480. @new_recurring_todo = check_for_next_todo(@todo) if @saved
  481. respond_to do |format|
  482. format.html do
  483. if @saved
  484. message = t('todos.action_deleted_success')
  485. if activated_successor_count > 0
  486. message += " activated #{pluralize(activated_successor_count, 'pending action')}"
  487. end
  488. notify :notice, message, 2.0
  489. redirect_to :action => 'index'
  490. else
  491. notify :error, t('todos.action_deleted_error'), 2.0
  492. redirect_to :action => 'index'
  493. end
  494. end
  495. format.js do
  496. if @saved
  497. determine_down_count
  498. if source_view_is_one_of(:todo, :deferred, :project, :context)
  499. determine_remaining_in_context_count(@context_id)
  500. elsif source_view_is :calendar
  501. @original_item_due_id = get_due_id_for_calendar(@original_item_due)
  502. @old_due_empty = is_old_due_empty(@original_item_due_id)
  503. end
  504. end
  505. render
  506. end
  507. format.xml { render :text => '200 OK. Action deleted.', :status => 200 }
  508. end
  509. end
  510. def done
  511. @source_view = 'done'
  512. @page_title = t('todos.completed_tasks_title')
  513. @done_today, @done_this_week, @done_this_month = DoneTodos.done_todos_for_container(current_user)
  514. @count = @done_today.size + @done_this_week.size + @done_this_month.size
  515. respond_to do |format|
  516. format.html
  517. format.xml do
  518. completed_todos = current_user.todos.completed
  519. render :xml => completed_todos.to_xml( *to_xml_params )
  520. end
  521. end
  522. end
  523. def all_done
  524. @source_view = 'done'
  525. @page_title = t('todos.completed_tasks_title')
  526. @done = current_user.todos.completed.includes(Todo::DEFAULT_INCLUDES).reorder('completed_at DESC').paginate :page => params[:page], :per_page => 20
  527. @count = @done.size
  528. end
  529. def list_deferred
  530. @source_view = 'deferred'
  531. @page_title = t('todos.deferred_tasks_title')
  532. @contexts_to_show = @contexts = current_user.contexts
  533. includes = params[:format]=='xml' ? [:context, :project] : Todo::DEFAULT_INCLUDES
  534. @not_done_todos = current_user.todos.deferred.includes(includes) + current_user.todos.pending.includes(includes)
  535. @down_count = @count = @not_done_todos.size
  536. respond_to do |format|
  537. format.html do
  538. init_not_done_counts
  539. init_project_hidden_todo_counts
  540. @active_projects = current_user.projects.active
  541. @active_contexts = current_user.contexts.active
  542. @hidden_projects = current_user.projects.hidden
  543. @hidden_contexts = current_user.contexts.hidden
  544. @completed_projects = current_user.projects.completed
  545. end
  546. format.m
  547. format.xml { render :xml => @not_done_todos.to_xml( *to_xml_params ) }
  548. end
  549. end
  550. # Check for any due tickler items, activate them
  551. # Called by periodically_call_remote
  552. def check_deferred
  553. @due_tickles = current_user.deferred_todos.find_and_activate_ready
  554. respond_to do |format|
  555. format.html { redirect_to home_path }
  556. format.js
  557. end
  558. end
  559. def filter_to_context
  560. context = current_user.contexts.find_by_id(params['context']['id'])
  561. redirect_to context_todos_path(context, :format => 'm')
  562. end
  563. def filter_to_project
  564. project = current_user.projects.find_by_id(params['project']['id'])
  565. redirect_to project_todos_path(project, :format => 'm')
  566. end
  567. # /todos/tag/[tag_name] shows all the actions tagged with tag_name
  568. def tag
  569. get_params_for_tag_view
  570. @page_title = t('todos.tagged_page_title', :tag_name => @tag_title)
  571. @source_view = params['_source_view'] || 'tag'
  572. if mobile?
  573. # mobile tags are routed with :name ending on .m. So we need to chomp it
  574. @tag_name = @tag_name.chomp('.m')
  575. else
  576. init_data_for_sidebar
  577. end
  578. todos_with_tag_ids = find_todos_with_tag_expr(@tag_expr)
  579. @not_done_todos = todos_with_tag_ids.
  580. active.not_hidden.
  581. reorder('todos.due IS NULL, todos.due ASC, todos.created_at ASC').
  582. includes(Todo::DEFAULT_INCLUDES)
  583. @hidden_todos = todos_with_tag_ids.
  584. hidden.
  585. reorder('todos.completed_at DESC, todos.created_at DESC').
  586. includes(Todo::DEFAULT_INCLUDES)
  587. @deferred = todos_with_tag_ids.
  588. deferred.
  589. reorder('todos.show_from ASC, todos.created_at DESC').
  590. includes(Todo::DEFAULT_INCLUDES)
  591. @pending = todos_with_tag_ids.
  592. blocked.
  593. reorder('todos.show_from ASC, todos.created_at DESC').
  594. includes(Todo::DEFAULT_INCLUDES)
  595. # If you've set no_completed to zero, the completed items box isn't shown on
  596. # the tag page
  597. @done = todos_with_tag_ids.completed.
  598. limit(current_user.prefs.show_number_completed).
  599. reorder('todos.completed_at DESC').
  600. includes(Todo::DEFAULT_INCLUDES)
  601. @projects = current_user.projects
  602. @contexts = current_user.contexts
  603. @contexts_to_show = @contexts.reject {|x| x.hide? }
  604. # Set defaults for new_action
  605. @initial_tags = @tag_name
  606. unless @not_done_todos.empty?
  607. @context = current_user.contexts.find(@not_done_todos.first.context_id)
  608. end
  609. # Set count badge to number of items with this tag
  610. @not_done_todos.empty? ? @count = 0 : @count = @not_done_todos.size
  611. @down_count = @count
  612. respond_to do |format|
  613. format.html
  614. format.m {
  615. cookies[:mobile_url]= {:value => request.fullpath, :secure => SITE_CONFIG['secure_cookies']}
  616. }
  617. format.text {
  618. render :action => 'index', :layout => false, :content_type => Mime::TEXT
  619. }
  620. end
  621. end
  622. def done_tag
  623. @source_view = params['_source_view'] || 'tag'
  624. @tag_name = sanitize(params[:name]) # sanitize to prevent XSS vunerability!
  625. @page_title = t('todos.completed_tagged_page_title', :tag_name => @tag_name)
  626. @tag = Tag.find_by_name(@tag_name)
  627. @tag = Tag.new(:name => @tag_name) if @tag.nil?
  628. completed_todos = current_user.todos.completed.with_tag(@tag.id)
  629. @done_today = get_done_today(completed_todos)
  630. @done_this_week = get_done_this_week(completed_todos)
  631. @done_this_month = get_done_this_month(completed_todos)
  632. @count = @done_today.size + @done_this_week.size + @done_this_month.size
  633. render :template => 'todos/done'
  634. end
  635. def all_done_tag
  636. @source_view = params['_source_view'] || 'tag'
  637. @tag_name = sanitize(params[:name]) # sanitize to prevent XSS vunerability!
  638. @page_title = t('todos.all_completed_tagged_page_title', :tag_name => @tag_name)
  639. @tag = Tag.find_by_name(@tag_name)
  640. @tag = Tag.new(:name => @tag_name) if @tag.nil?
  641. @done = current_user.todos.completed.with_tag(@tag.id).reorder('completed_at DESC').includes(Todo::DEFAULT_INCLUDES).paginate :page => params[:page], :per_page => 20
  642. @count = @done.size
  643. render :template => 'todos/all_done'
  644. end
  645. def tags
  646. # TODO: limit to current_user
  647. tags_beginning = Tag.where('name like ?', params[:term]+'%')
  648. tags_all = Tag.where('name like ?', '%'+params[:term]+'%')
  649. tags_all= tags_all - tags_beginning
  650. respond_to do |format|
  651. format.autocomplete { render :text => for_autocomplete(tags_beginning+tags_all, params[:term]) }
  652. end
  653. end
  654. def defer
  655. @source_view = params['_source_view'] || 'todo'
  656. numdays = params['days'].to_i
  657. @todo = current_user.todos.find_by_id(params[:id])
  658. @original_item_context_id = @todo.context_id
  659. @todo_deferred_state_changed = true
  660. @new_context_created = false
  661. @due_date_changed = false
  662. @tag_was_removed = false
  663. @todo_hidden_state_changed = false
  664. @todo_was_deferred_from_active_state = @todo.show_from.nil?
  665. @todo.show_from = (@todo.show_from || @todo.user.date) + numdays.days
  666. @saved = @todo.save
  667. @status_message = t('todos.action_saved_to_tickler')
  668. determine_down_count
  669. determine_remaining_in_context_count(@todo.context_id)
  670. source_view do |page|
  671. page.project {
  672. @remaining_undone_in_project = current_user.projects.find_by_id(@todo.project_id).todos.not_completed.count
  673. @original_item_project_id = @todo.project_id
  674. }
  675. page.tag {
  676. determine_deferred_tag_count(params['_tag_name'])
  677. }
  678. end
  679. respond_to do |format|
  680. format.html { redirect_to :back }
  681. format.js {render :action => 'update'}
  682. format.m {
  683. notify(:notice, t("todos.action_deferred", :description => @todo.description))
  684. do_mobile_todo_redirection
  685. }
  686. end
  687. end
  688. def calendar
  689. @source_view = params['_source_view'] || 'calendar'
  690. @page_title = t('todos.calendar_page_title')
  691. @projects = current_user.projects
  692. due_today_date = Time.zone.now
  693. due_this_week_date = due_today_date.end_of_week
  694. due_next_week_date = due_this_week_date + 7.days
  695. due_this_month_date = due_today_date.end_of_month
  696. included_tables = Todo::DEFAULT_INCLUDES
  697. @due_today = current_user.todos.not_completed.
  698. where('todos.due <= ?', due_today_date).
  699. includes(included_tables).
  700. reorder("due")
  701. @due_this_week = current_user.todos.not_completed.
  702. where('todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date).
  703. includes(included_tables).
  704. reorder("due")
  705. @due_next_week = current_user.todos.not_completed.
  706. where('todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date).
  707. includes(included_tables).
  708. reorder("due")
  709. @due_this_month = current_user.todos.not_completed.
  710. where('todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date).
  711. includes(included_tables).
  712. reorder("due")
  713. @due_after_this_month = current_user.todos.not_completed.
  714. where('todos.due > ?', due_this_month_date).
  715. includes(included_tables).
  716. reorder("due")
  717. @count = current_user.todos.not_completed.are_due.count
  718. respond_to do |format|
  719. format.html
  720. format.ics {
  721. @due_all = current_user.todos.not_completed.are_due.reorder("due")
  722. render :action => 'calendar', :layout => false, :content_type => Mime::ICS
  723. }
  724. format.xml {
  725. @due_all = current_user.todos.not_completed.are_due.reorder("due")
  726. render :xml => @due_all.to_xml( *to_xml_params )
  727. }
  728. end
  729. end
  730. def list_hidden
  731. @hidden = current_user.todos.hidden
  732. respond_to do |format|
  733. format.xml {
  734. render :xml => @hidden.to_xml( *to_xml_params )
  735. }
  736. end
  737. end
  738. def auto_complete_for_predecessor
  739. unless params['id'].nil?
  740. get_todo_from_params
  741. # Begin matching todos in current project, excluding @todo itself
  742. @items = @todo.project.todos.not_completed.
  743. where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
  744. includes(:context, :project).
  745. reorder('description ASC').
  746. limit(10) unless @todo.project.nil?
  747. # Then look in the current context, excluding @todo itself
  748. @items = @todo.context.todos.not_completed
  749. where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
  750. includes(:context, :project).
  751. reorder('description ASC').
  752. limit(10) unless !@items.empty? || @todo.context.nil?
  753. # Match todos in other projects, excluding @todo itself
  754. @items = current_user.todos.not_completed.
  755. where('(LOWER(todos.description) LIKE ?) AND NOT(todos.id=?)', "%#{params[:term].downcase}%", @todo.id).
  756. includes(:context, :project).
  757. reorder('description ASC').
  758. limit(10) unless !@items.empty?
  759. else
  760. # New todo - TODO: Filter on current project in project view
  761. @items = current_user.todos.not_completed.
  762. where('(LOWER(todos.description) LIKE ?)', "%#{params[:term].downcase}%").
  763. includes(:context, :project).
  764. reorder('description ASC').
  765. limit(10)
  766. end
  767. render :inline => format_dependencies_as_json_for_auto_complete(@items)
  768. end
  769. def convert_to_project
  770. todo = current_user.todos.find_by_id(params[:id])
  771. @project = Project.create_from_todo(todo)
  772. if @project.valid?
  773. redirect_to project_url(@project)
  774. else
  775. flash[:error] = "Could not create project from todo: #{@project.errors.full_messages[0]}"
  776. redirect_to request.env["HTTP_REFERER"] || root_url
  777. end
  778. end
  779. def show_notes
  780. @todo = current_user.todos.find_by_id(params['id'])
  781. @return_path=cookies[:mobile_url] ? cookies[:mobile_url] : mobile_path
  782. respond_to do |format|
  783. format.html {
  784. redirect_to home_path, "Viewing note of todo is not implemented"
  785. }
  786. format.m {
  787. render :action => "show_notes"
  788. }
  789. end
  790. end
  791. private
  792. def do_mobile_todo_redirection
  793. if cookies[:mobile_url]
  794. old_path = cookies[:mobile_url]
  795. cookies[:mobile_url] = {:value => nil, :secure => SITE_CONFIG['secure_cookies']}
  796. redirect_to old_path
  797. else
  798. redirect_to todos_path(:format => 'm')
  799. end
  800. end
  801. def to_xml_params
  802. if params[:limit_fields] == 'index'
  803. return [:only => [:id, :created_at, :updated_at, :completed_at] ]
  804. else
  805. return [:except => :user_id, :include => [:tags] ]
  806. end
  807. end
  808. def get_todo_from_params
  809. # TODO: this was a :append_before but was removed to tune performance per
  810. # method. Reconsider re-enabling it
  811. @todo = current_user.todos.find_by_id(params['id'])
  812. end
  813. def find_and_activate_ready
  814. current_user.deferred_todos.find_and_activate_ready
  815. end
  816. def tag_title(tag_expr)
  817. and_list = tag_expr.inject([]) { |s,tag_list| s << tag_list.join(',') }
  818. return and_list.join(' AND ')
  819. end
  820. def get_params_for_tag_view
  821. # use sanitize to prevent XSS attacks
  822. @tag_expr = []
  823. @tag_expr << sanitize(params[:name]).split(',')
  824. @tag_expr << sanitize(params[:and]).split(',') if params[:and]
  825. i = 1
  826. while params['and'+i.to_s]
  827. @tag_expr << sanitize(params['and'+i.to_s]).split(',')
  828. i=i+1
  829. end
  830. @single_tag = @tag_expr.size == 1 && @tag_expr[0].size == 1
  831. @tag_name = @tag_expr[0][0]
  832. @tag_title = @single_tag ? @tag_name : tag_title(@tag_expr)
  833. end
  834. def get_ids_from_tag_expr(tag_expr)
  835. ids = []
  836. tag_expr.each do |tag_list|
  837. id_list = []
  838. tag_list.each do |tag|
  839. tag = Tag.find_by_name(tag)
  840. id_list << tag.id if tag
  841. end
  842. ids << id_list
  843. end
  844. return ids
  845. end
  846. def find_todos_with_tag_expr(tag_expr)
  847. # optimize for the common case: selecting only one tag
  848. if @single_tag
  849. tag = Tag.find_by_name(@tag_name)
  850. tag_id = tag.nil? ? -1 : tag.id
  851. return current_user.todos.with_tag(tag_id)
  852. end
  853. tag_ids = get_ids_from_tag_expr(tag_expr)
  854. todos = current_user.todos
  855. tag_ids.each do |ids|
  856. todos = todos.with_tags(ids) unless ids.nil? || ids.empty?
  857. end
  858. return todos
  859. end
  860. def determine_down_count
  861. source_view do |from|
  862. from.todo do
  863. @down_count = current_user.todos.active.not_hidden.count
  864. end
  865. from.context do
  866. context_id = @original_item_context_id || @todo.context_id
  867. todos = current_user.contexts.find_by_id(context_id).todos.not_completed
  868. if @todo.context.hide?
  869. # include hidden todos
  870. @down_count = todos.count
  871. else
  872. # exclude hidden_todos
  873. @down_count = todos.not_hidden.count
  874. end
  875. end
  876. from.project do
  877. unless @todo.project_id == nil
  878. @down_count = current_user.projects.find_by_id(@todo.project_id).todos.active_or_hidden.count
  879. end
  880. end
  881. from.deferred do
  882. @down_count = current_user.todos.deferred_or_blocked.count
  883. end
  884. from.tag do
  885. @tag_name = params['_tag_name']
  886. @tag = Tag.find_by_name(@tag_name)
  887. if @tag.nil?
  888. @tag = Tag.new(:name => @tag_name)
  889. end
  890. @down_count = current_user.todos.with_tag(@tag.id).active.not_hidden.count
  891. end
  892. end
  893. end
  894. def determine_remaining_in_context_count(context_id = @todo.context_id)
  895. source_view do |from|
  896. from.deferred {
  897. # force reload to todos to get correct count and not a cached one
  898. @remaining_in_context = current_user.contexts.find_by_id(context_id).todos.deferred_or_blocked.count
  899. @target_context_count = current_user.contexts.find_by_id(@todo.context_id).todos.deferred_or_blocked.count
  900. }
  901. from.tag {
  902. tag = Tag.find_by_name(params['_tag_name'])
  903. if tag.nil?
  904. tag = Tag.new(:name => params['tag'])
  905. end
  906. @remaining_deferred_or_pending_count = current_user.todos.with_tag(tag.id).deferred_or_blocked.count
  907. @remaining_in_context = current_user.contexts.find_by_id(context_id).todos.active.not_hidden.with_tag(tag.id).count
  908. @target_context_count = current_user.contexts.find_by_id(@todo.context_id).todos.active.not_hidden.with_tag(tag.id).count
  909. @remaining_hidden_count = current_user.todos.hidden.with_tag(tag.id).count
  910. }
  911. from.project {
  912. project_id = @project_changed ? @original_item_project_id : @todo.project_id
  913. @remaining_deferred_or_pending_count = current_user.projects.find_by_id(project_id).todos.deferred_or_blocked.count
  914. if @todo_was_completed_from_deferred_or_blocked_state
  915. @remaining_in_context = @remaining_deferred_or_pending_count
  916. else
  917. @remaining_in_context = current_user.projects.find_by_id(project_id).todos.active_or_hidden.count
  918. end
  919. @target_context_count = current_user.projects.find_by_id(project_id).todos.active.count
  920. }
  921. from.calendar {
  922. @target_context_count = @new_due_id.blank? ? 0 : count_old_due_empty(@new_due_id)
  923. }
  924. from.context {
  925. context = current_user.contexts.find_by_id(context_id)
  926. @remaining_deferred_or_pending_count = context.todos.deferred_or_blocked.count
  927. remaining_actions_in_context = context.todos(true).active
  928. remaining_actions_in_context = remaining_actions_in_context.not_hidden if !context.hide?
  929. @remaining_in_context = remaining_actions_in_context.count
  930. if @todo_was_deferred_or_blocked
  931. actions_in_target = current_user.contexts.find_by_id(@todo.context_id).todos(true).active
  932. actions_in_target = actions_in_target.not_hidden if !context.hide?
  933. else
  934. actions_in_target = @todo.context.todos.deferred_or_blocked
  935. end
  936. @target_context_count = actions_in_target.count
  937. }
  938. end
  939. @remaining_in_context = current_user.contexts.find_by_id(context_id).todos(true).active.not_hidden.count if !@remaining_in_context
  940. @target_context_count = current_user.contexts.find_by_id(@todo.context_id).todos(true).active.not_hidden.count if !@target_context_count
  941. end
  942. def determine_completed_count
  943. source_view do |from|
  944. from.todo do
  945. @completed_count = current_user.todos.not_hidden.completed.count
  946. end
  947. from.context do
  948. todos = current_user.contexts.find_by_id(@todo.context_id).todos.completed
  949. todos = todos.not_hidden if !@todo.context.hidden?
  950. @completed_count = todos.count
  951. end
  952. from.project do
  953. unless @todo.project_id == nil
  954. todos = current_user.projects.find_by_id(@todo.project_id).todos.completed
  955. todos = todos.not_hidden if !@todo.project.hidden?
  956. @completed_count = todos.count
  957. end
  958. end
  959. from.tag do
  960. @completed_count = current_user.todos.with_tag(@tag.id).completed.count
  961. end
  962. end
  963. end
  964. def determine_deferred_tag_count(tag_name)
  965. tag = Tag.find_by_name(tag_name)
  966. # tag.nil? should normally not happen, but is a workaround for #929
  967. @remaining_deferred_or_pending_count = tag.nil? ? 0 : current_user.todos.deferred.with_tag(tag.id).count
  968. end
  969. def check_for_next_todo(todo)
  970. # check if this todo has a related recurring_todo. If so, create next todo
  971. new_recurring_todo = nil
  972. recurring_todo = nil
  973. if todo.from_recurring_todo?
  974. recurring_todo = todo.recurring_todo
  975. # check if there are active todos belonging to this recurring todo. only
  976. # add new one if all active todos are completed
  977. if recurring_todo.todos.active.count == 0
  978. # check for next todo either from the due date or the show_from date
  979. date_to_check = todo.due.nil? ? todo.show_from : todo.due
  980. # if both due and show_from are nil, check for a next todo from now
  981. date_to_check = Time.zone.now if date_to_check.nil?
  982. if recurring_todo.active? && recurring_todo.has_next_todo(date_to_check)
  983. # shift the reference date to yesterday if date_to_check is furher in
  984. # the past. This is to make sure we do not get older todos for overdue
  985. # todos. I.e. checking a daily todo that is overdue with 5 days will
  986. # create a new todo which is overdue by 4 days if we don't shift the
  987. # date. Discard the time part in the compare. We pick yesterday so
  988. # that new todos due for today will be created instead of new todos
  989. # for tomorrow.
  990. date = date_to_check.at_midnight >= Time.zone.now.at_midnight ? date_to_check : Time.zone.now-1.day
  991. new_recurring_todo = create_todo_from_recurring_todo(recurring_todo, date.at_midnight)
  992. end
  993. end
  994. end
  995. return new_recurring_todo
  996. end
  997. def get_due_id_for_calendar(due)
  998. return "" if due.nil?
  999. due_today_date = Time.zone.now
  1000. due_this_week_date = Time.zone.now.end_of_week
  1001. due_next_week_date = due_this_week_date + 7.days
  1002. due_this_month_date = Time.zone.now.end_of_month
  1003. if due <= due_today_date
  1004. new_due_id = "due_today"
  1005. elsif due <= due_this_week_date
  1006. new_due_id = "due_this_week"
  1007. elsif due <= due_next_week_date
  1008. new_due_id = "due_next_week"
  1009. elsif due <= due_this_month_date
  1010. new_due_id = "due_this_month"
  1011. else
  1012. new_due_id = "due_after_this_month"
  1013. end
  1014. return new_due_id
  1015. end
  1016. def is_old_due_empty(id)
  1017. return 0 == count_old_due_empty(id)
  1018. end
  1019. def count_old_due_empty(id)
  1020. due_today_date = Time.zone.now
  1021. due_this_week_date = Time.zone.now.end_of_week
  1022. due_next_week_date = due_this_week_date + 7.days
  1023. due_this_month_date = Time.zone.now.end_of_month
  1024. case id
  1025. when "due_today"
  1026. return current_user.todos.not_completed.where('todos.due <= ?', due_today_date).count
  1027. when "due_this_week"
  1028. return current_user.todos.not_completed.where('todos.due > ? AND todos.due <= ?', due_today_date, due_this_week_date).count
  1029. when "due_next_week"
  1030. return current_user.todos.not_completed.where('todos.due > ? AND todos.due <= ?', due_this_week_date, due_next_week_date).count
  1031. when "due_this_month"
  1032. return current_user.todos.not_completed.where('todos.due > ? AND todos.due <= ?', due_next_week_date, due_this_month_date).count
  1033. when "due_after_this_month"
  1034. return current_user.todos.not_completed.where('todos.due > ?', due_this_month_date).count
  1035. else
  1036. raise Exception.new, "unknown due id for calendar: '#{id}'"
  1037. end
  1038. end
  1039. def cache_attributes_from_before_update
  1040. @original_item_context_id = @todo.context_id
  1041. @original_item_project_id = @todo.project_id
  1042. @original_item_was_deferred = @todo.deferred?
  1043. @original_item_was_hidden = @todo.hidden?
  1044. @original_item_was_pending = @todo.pending?
  1045. @original_item_due = @todo.due
  1046. @original_item_due_id = get_due_id_for_calendar(@todo.due)
  1047. @original_item_predecessor_list = @todo.predecessors.map{|t| t.specification}.join(', ')
  1048. @todo_was_deferred_or_blocked = @todo.deferred? || @todo.pending?
  1049. end
  1050. def update_project
  1051. @project_changed = false;
  1052. if params['todo']['project_id'].blank? && !params['project_name'].nil?
  1053. if params['project_name'] == 'None'
  1054. project = Project.null_object
  1055. else
  1056. project = current_user.projects.find_by_name(params['project_name'].strip)
  1057. unless project
  1058. project = current_user.projects.build
  1059. project.name = params['project_name'].strip
  1060. project.save
  1061. @new_project_created = true
  1062. end
  1063. end
  1064. params["todo"]["project_id"] = project.id
  1065. @project_changed = @original_item_project_id != params["todo"]["project_id"] = project.id
  1066. end
  1067. end
  1068. def update_todo_state_if_project_changed
  1069. if @project_changed
  1070. @todo.update_state_from_project
  1071. @remaining_undone_in_project = current_user.projects.find_by_id(@original_item_project_id).todos.active.count if source_view_is :project
  1072. end
  1073. end
  1074. def update_context
  1075. @context_changed = false
  1076. if params['todo']['context_id'].blank? && !params['context_name'].blank?
  1077. context = current_user.contexts.find_by_name(params['context_name'].strip)
  1078. unless context
  1079. @new_context = current_user.contexts.build
  1080. @new_context.name = params['context_name'].strip
  1081. @new_context.save
  1082. @new_context_created = true
  1083. @not_done_todos = [@todo]
  1084. context = @new_context
  1085. end
  1086. params["todo"]["context_id"] = context.id
  1087. @context_changed = @original_item_context_id != params["todo"]["context_id"] = context.id
  1088. end
  1089. end
  1090. def update_tags
  1091. if params[:tag_list]
  1092. @todo.tag_with(params[:tag_list])
  1093. @todo.tags(true) #force a reload for proper rendering
  1094. end
  1095. end
  1096. def update_due_and_show_from_dates
  1097. if params["todo"].has_key?("due")
  1098. begin
  1099. params["todo"]["due"] = parse_date_per_user_prefs(params["todo"]["due"])
  1100. rescue
  1101. @todo.errors[:base] << "Invalid due date"
  1102. end
  1103. else
  1104. params["todo"]["due"] = ""
  1105. end
  1106. if params['todo']['show_from']
  1107. begin
  1108. params['todo']['show_from'] = parse_date_per_user_prefs(params['todo']['show_from'])
  1109. rescue
  1110. @todo.errors[:base] << "Invalid show from date"
  1111. end
  1112. end
  1113. end
  1114. def update_completed_state
  1115. if params['done'] == '1' && !@todo.completed?
  1116. @todo.complete!
  1117. @todo.activate_pending_todos
  1118. end
  1119. # strange. if checkbox is not checked, there is no 'done' in params.
  1120. # Therefore I've used the negation
  1121. if !(params['done'] == '1') && @todo.completed?
  1122. @todo.activate!
  1123. @todo.block_successors
  1124. end
  1125. end
  1126. def update_dependencies
  1127. @todo.add_predecessor_list(params[:predecessor_list])
  1128. end
  1129. def update_dependency_state
  1130. # assumes @todo.save was called so that the predecessor_list is persistent
  1131. if @original_item_predecessor_list != params[:predecessor_list]
  1132. # Possible state change with new dependencies
  1133. if @todo.uncompleted_predecessors.empty?
  1134. @todo.activate! if @todo.state == 'pending' # Activate pending if no uncompleted predecessors
  1135. else
  1136. @todo.block! if @todo.state == 'active' # Block active if we got uncompleted predecessors
  1137. end
  1138. end
  1139. end
  1140. def update_attributes_of_todo
  1141. @todo.attributes = params["todo"]
  1142. end
  1143. def determine_changes_by_this_update
  1144. @todo_was_activated_from_deferred_state = @todo.active? && @original_item_was_deferred
  1145. @todo_was_activated_from_pending_state = @todo.active? && @original_item_was_pending
  1146. @todo_was_deferred_from_active_state = @todo.deferred? && !@original_item_was_deferred
  1147. @todo_was_blocked_from_active_state = @todo.pending? && !@original_item_was_pending
  1148. @todo_deferred_state_changed = @original_item_was_deferred != @todo.deferred?
  1149. @todo_pending_state_changed = @original_item_was_pending != @todo.pending?
  1150. @todo_hidden_state_changed = @original_item_was_hidden != @todo.hidden?
  1151. @due_date_changed = @original_item_due != @todo.due
  1152. source_view do |page|
  1153. page.calendar do
  1154. @old_due_empty = is_old_due_empty(@original_item_due_id)
  1155. @new_due_id = get_due_id_for_calendar(@todo.due)
  1156. end
  1157. page.tag do
  1158. @tag_name = params['_tag_name']
  1159. @tag_was_removed = !@todo.has_tag?(@tag_name)
  1160. end
  1161. page.context do
  1162. @todo_should_be_hidden = @todo_hidden_state_changed && @todo.hidden?
  1163. end
  1164. end
  1165. end
  1166. def project_specified_by_name(project_name)
  1167. return false unless params['project_id'].blank?
  1168. return false if project_name.blank?
  1169. return false if project_name == 'None'
  1170. true
  1171. end
  1172. def context_specified_by_name(context_name)
  1173. return false unless params['context_id'].blank?
  1174. return false if context_name.blank?
  1175. true
  1176. end
  1177. def determine_non_uniq_todo
  1178. # for calendar view. TODO: unused
  1179. all_list_uniq_ids = (@due_today.map(&:id) + @due_this_week.map(&:id) +
  1180. @due_next_week.map(&:id) + @due_this_month.map(&:id) + @due_after_this_month.map(&:id)).uniq
  1181. all_list_count = @due_today.count + @due_this_week.count +
  1182. @due_next_week.count + @due_this_month.count + @due_after_this_month.count
  1183. return !( all_list_uniq_ids.length == all_list_count )
  1184. end
  1185. # all completed todos [today@00:00, today@now]
  1186. def get_done_today(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
  1187. start_of_this_day = Time.zone.now.beginning_of_day
  1188. completed_todos.completed_after(start_of_this_day).all(includes)
  1189. end
  1190. # all completed todos [begin_of_week, start_of_today]
  1191. def get_done_this_week(completed_todos, includes = {:include => Todo::DEFAULT_INCLUDES})
  1192. start_of_this_week = Time.zone.now.beginning_of_week
  1193. start_of_this_day = Time.zone.now.beginning_of_day
  1194. completed_todos.co

Large files files are truncated, but you can click here to view the full file