TracksApp/tracks

View on GitHub
app/controllers/recurring_todos_controller.rb

Summary

Maintainability
A
0 mins
Test Coverage
class RecurringTodosController < ApplicationController
  helper :todos, :recurring_todos

  append_before_action :init, :only => [:index, :new, :edit, :create]
  append_before_action :get_recurring_todo_from_param, :only => [:destroy, :toggle_check, :toggle_star, :edit, :update]

  def index
    @page_title = t('todos.recurring_actions_title')
    @source_view = params['_source_view'] || 'recurring_todo'
    find_and_inactivate
    @recurring_todos = current_user.recurring_todos.active.includes(:tags, :taggings)
    @completed_recurring_todos = current_user.recurring_todos.completed.limit(10).includes(:tags, :taggings)

    @no_recurring_todos = !@recurring_todos.exists?
    @no_completed_recurring_todos = !@completed_recurring_todos.exists?
    @count = @recurring_todos.count

    @new_recurring_todo = RecurringTodo.new
  end

  def new; end

  def show; end

  def done
    @source_view = params['_source_view'] || 'recurring_todo'
    @page_title = t('todos.completed_recurring_actions_title')

    items_per_page = 20
    page = params[:page] || 1
    @completed_recurring_todos = current_user.recurring_todos.completed.paginate :page => page, :per_page => items_per_page
    @total = @count = current_user.recurring_todos.completed.count

    @range_low = (page.to_i - 1) * items_per_page + 1
    @range_high = @range_low + @completed_recurring_todos.size - 1

    @range_low = 0 if @total == 0
    @range_high = @total if @range_high > @total
  end

  def edit
    @form_helper = RecurringTodos::FormHelper.new(@recurring_todo)

    respond_to do |format|
      format.js
    end
  end

  def update
    updater = RecurringTodos::RecurringTodosBuilder.new(current_user, update_recurring_todo_params)
    @saved = updater.update(@recurring_todo)

    @recurring_todo.reload

    respond_to do |format|
      format.js
    end
  end

  def create
    builder = RecurringTodos::RecurringTodosBuilder.new(current_user, all_recurring_todo_params)
    @saved = builder.save

    if @saved
      @recurring_todo = builder.saved_recurring_todo
      todo_saved = TodoFromRecurringTodo.new(current_user, @recurring_todo).create.nil? == false

      @status_message =
        t('todos.recurring_action_saved') + " / " +
        t("todos.new_related_todo_#{todo_saved ? "" : "not_"}created_short")

      @down_count = current_user.recurring_todos.active.count
      @new_recurring_todo = RecurringTodo.new
    else
      @recurring_todo = builder.recurring_todo
      @status_message = t('todos.error_saving_recurring')
    end

    respond_to do |format|
      format.js
    end
  end

  def destroy
    @number_of_todos = @recurring_todo.todos.count

    # remove all references to this recurring todo
    @recurring_todo.clear_todos_association

    # delete the recurring todo
    @saved = @recurring_todo.destroy

    # count remaining recurring todos
    @active_remaining = current_user.recurring_todos.active.count
    @completed_remaining = current_user.recurring_todos.completed.count

    respond_to do |format|
      format.html do
        if @saved
          notify :notice, t('todos.recurring_deleted_success')
        else
          notify :error,  t('todos.error_deleting_recurring', :description => @recurring_todo.description)
        end
        redirect_to :action => 'index'
      end
      format.js do
        render
      end
    end
  end

  def toggle_check
    @saved = @recurring_todo.toggle_completion!

    @down_count = current_user.recurring_todos.active.count
    @active_remaining = @down_count
    @completed_remaining = 0

    if @recurring_todo.active?
      @completed_remaining = current_user.recurring_todos.completed.count

      # from completed back to active -> check if there is an active todo
      @active_todos = @recurring_todo.todos.active.count
      # create todo if there is no active todo belonging to the activated
      # recurring_todo
      @new_recurring_todo = TodoFromRecurringTodo.new(current_user, @recurring_todo).create if @active_todos == 0
    end

    respond_to do |format|
      format.js
    end
  end

  def toggle_star
    @recurring_todo.toggle_star!
    @saved = @recurring_todo.save!
    respond_to do |format|
      format.js
    end
  end

  private

  def recurring_todo_params
    params.require(:recurring_todo).permit(
      # model attributes
      :context_id, :project_id, :description, :notes, :state, :start_from,
      :ends_on, :end_date, :number_of_occurrences, :occurrences_count, :target,
      :show_from_delta, :recurring_period, :recurrence_selector, :every_other1,
      :every_other2, :every_other3, :every_day, :only_work_days, :every_count,
      :weekday, :show_always, :context_name, :project_name, :tag_list,
      # form attributes
      :recurring_period, :daily_selector, :monthly_selector, :yearly_selector,
      :recurring_target, :daily_every_x_days, :monthly_day_of_week,
      :monthly_every_x_day, :monthly_every_x_month2, :monthly_every_x_month,
      :monthly_every_xth_day, :recurring_show_days_before,
      :recurring_show_always, :weekly_every_x_week, :weekly_return_monday,
      :yearly_day_of_week, :yearly_every_x_day, :yearly_every_xth_day,
      :yearly_month_of_year2, :yearly_month_of_year,
      # derived attributes
      :weekly_return_monday, :weekly_return_tuesday, :weekly_return_wednesday,
      :weekly_return_thursday, :weekly_return_friday, :weekly_return_saturday, :weekly_return_sunday
    )
  end

  def all_recurring_todo_params
    # move context_name, project_name and tag_list into :recurring_todo hash for easier processing
    {
      context_name: :context_name,
      project_name: :project_name,
      tag_list:     :tag_list
    }.each do |target, source|
      move_into_recurring_todo_param(params, target, source)
    end
    recurring_todo_params
  end

  def update_recurring_todo_params
    # we needed to rename the recurring_period selector in the edit form because
    # the form for a new recurring todo and the edit form are on the same page.
    # Same goes for start_from and end_date
    params['recurring_todo']['recurring_period'] = params['recurring_edit_todo']['recurring_period']

    {
      context_name: :context_name,
      project_name: :project_name,
      tag_list:     :edit_recurring_todo_tag_list,
      end_date:     :recurring_todo_edit_end_date,
      start_from:   :recurring_todo_edit_start_from
    }.each do |target, source|
      move_into_recurring_todo_param(params, target, source)
    end

    # make sure that we set weekly_return_xxx to empty (space) when they are
    # not checked (and thus not present in params["recurring_todo"])
    %w{monday tuesday wednesday thursday friday saturday sunday}.each do |day|
      params["recurring_todo"]["weekly_return_#{day}"] = ' ' if params["recurring_todo"]["weekly_return_#{day}"].nil?
    end

    recurring_todo_params
  end

  def move_into_recurring_todo_param(params, target, source)
    params[:recurring_todo][target] = params[source] unless params[source].blank?
  end

  def init
    @days_of_week = (0..6).map { |i| [t('date.day_names')[i], i] }
    @months_of_year = (1..12).map { |i| [t('date.month_names')[i], i] }
    @xth_day = [
      [t('common.first'), 1],
      [t('common.second'), 2],
      [t('common.third'), 3],
      [t('common.fourth'), 4],
      [t('common.last'),5]
    ]
    @projects = current_user.projects.includes(:default_context)
    @contexts = current_user.contexts
  end

  def get_recurring_todo_from_param
    @recurring_todo = current_user.recurring_todos.find(params[:id])
  end

  def find_and_inactivate
    # find active recurring todos without active todos and inactivate them

    current_user.recurring_todos.active
      .select("recurring_todos.id, recurring_todos.state")
      .joins("LEFT JOIN todos fai_todos ON (recurring_todos.id = fai_todos.recurring_todo_id) AND (NOT fai_todos.state='completed')")
      .where("fai_todos.id IS NULL")
      .each { |rt| current_user.recurring_todos.find(rt.id).toggle_completion! }
  end
end