app/controllers/todos/todo_create_params_helper.rb
module Todos
class TodoCreateParamsHelper
attr_reader :new_project_created, :new_context_created, :attributes
def initialize(params, user)
set_params(params)
filter_attributes(params)
filter_tags
filter_starred
@user = user
@errors = []
@new_project_created = find_or_create_group(:project, user.projects, project_name)
@new_context_created = find_or_create_group(:context, user.contexts, context_name)
end
def set_params(params)
@params = params['request'] || params
end
def filter_attributes(params)
if params[:request]
@attributes = todo_params(params[:request])
elsif params[:todo]
@attributes = todo_params(params)
end
# Make sure there is at least an empty hash
@attributes = {} if @attributes.nil?
end
def filter_tags
if @attributes[:tags]
# for single tags, @attributed[:tags] returns a hash. For multiple tags,
# it with return an array of hashes. Make sure it is always an array of hashes
@attributes[:tags][:tag] = [@attributes[:tags][:tag]] unless @attributes[:tags][:tag].class == Array
# the REST api may use <tags> which will collide with tags association, so rename tags to add_tags
@attributes[:add_tags] = @attributes[:tags]
@attributes.delete :tags
end
end
def filter_starred
if @params[:new_todo_starred]
@attributes["starred"] = (@params[:new_todo_starred] || "").include? "true"
end
end
def show_from
@attributes['show_from']
end
def due
@attributes['due']
end
def project_name
@params['project_name'].strip unless @params['project_name'].nil?
end
def project_id
@attributes['project_id']
end
def context_name
@params['context_name'].strip unless @params['context_name'].nil?
end
def context_id
@attributes['context_id']
end
def tag_list
@params['tag_list']
end
def predecessor_list
@params['predecessor_list']
end
def parse_dates
@attributes['show_from'] = @user.prefs.parse_date(show_from)
@attributes['due'] = @user.prefs.parse_date(due)
@attributes['due'] ||= ''
end
def sequential?
return @params[:todos_sequential].present? && @params[:todos_sequential] == 'true'
end
def specified_by_name?(group_type)
return send("#{group_type}_specified_by_name?")
end
def specified_by_id?(group_type)
group_id = send("#{group_type}_id")
group_id.present?
end
def project_specified_by_name?
return false if @attributes['project_id'].present?
return false if project_name.blank?
true
end
def context_specified_by_name?
return false if @attributes['context_id'].present?
return false if context_name.blank?
true
end
def add_errors(model)
@errors.each { |e| model.errors.add(e[:attribute], e[:message]) }
end
private
def todo_params(params)
# keep :predecessor_dependencies from being filterd (for XML API).
# The permit cannot handle multiple precessors
if params[:todo][:predecessor_dependencies]
deps = params[:todo][:predecessor_dependencies][:predecessor]
end
# accept empty :todo hash
if params[:todo].empty?
params[:todo] = { :ignore => true }
end
filtered = params.require(:todo).permit(
:context_id, :project_id, :description, :notes,
:due, :show_from, :state,
# XML API
:tags => [:tag => [:name]],
:context => [:name],
:project => [:name])
# add back :predecessor_dependencies
filtered[:predecessor_dependencies] = { :predecessor => deps } unless deps.nil?
filtered
end
def find_or_create_group(group_type, set, name)
return set_id_by_name(group_type, set, name) if specified_by_name?(group_type)
return set_id_by_id_string(group_type, set, @attributes["#{group_type}_id"]) if specified_by_id?(group_type)
end
def set_id_by_name(group_type, set, name)
group = set.where(:name => name).first_or_initialize
group_is_new = group.new_record?
group.save if group_is_new
@attributes["#{group_type}_id"] = group.id
group_is_new
end
def set_id_by_id_string(group_type, set, id)
# be aware, this will replace the project_id/context_id (string) in @attributes with the new found id (int)
@attributes["#{group_type}_id"] = set.find(id).id
return false
rescue
@errors << { :attribute => group_type, :message => "unknown" }
end
end
end