impressionist/app/controllers/impressionist_controller.rb

106 lines
3.7 KiB
Ruby
Raw Normal View History

require 'digest/sha2'
module ImpressionistController
module ClassMethods
def impressionist(opts={})
before_filter { |c| c.impressionist_subapp_filter(opts[:actions], opts[:unique])}
end
end
module InstanceMethods
def self.included(base)
base.before_filter :impressionist_app_filter
end
def impressionist(obj,message=nil)
unless bypass
if obj.respond_to?("impressionable?")
obj.impressions.create(create_statement({:message => message}))
else
raise "#{obj.class.to_s} is not impressionable!"
end
end
end
def impressionist_app_filter
@impressionist_hash = Digest::SHA2.hexdigest(Time.now.to_f.to_s+rand(10000).to_s)
end
def impressionist_subapp_filter(actions=nil, unique_opts=nil)
unless bypass
actions.collect!{|a|a.to_s} unless actions.blank?
if (actions.blank? || actions.include?(action_name)) && (unique_opts.blank? || is_unique(unique_opts))
if (!actions.blank? && !unique_opts.blank?)
logger.info "Restricted to actions #{actions.inspect} and uniqueness for #{unique_opts.inspect}"
end
Impression.create(create_statement(
:impressionable_type => controller_name.singularize.camelize,
:impressionable_id=> params[:id]
))
end
end
end
private
def bypass
Impressionist::Bots::WILD_CARDS.each do |wild_card|
return true if request.user_agent and request.user_agent.downcase.include? wild_card
end
Impressionist::Bots::LIST.include? request.user_agent
end
def is_unique(unique_opts)
# FIXME think about uniqueness in relation to impressionable_id, impressionable_type and controller_name
# is controller name redundant? does the controller name always have to match?
default_statement = create_statement(
:impressionable_type => controller_name.singularize.camelize,
:impressionable_id=> params[:id]
)
statement = unique_opts.reduce({}) do |query, param|
query[param] = default_statement[param]
query
end
#logger.debug "Statement params: #{statement.inspect}."
# always use impressionable type?
statement[:impressionable_type] = controller_name.singularize.camelize
#statement[:impressionable_id] = params[:id]
return Impression.where(statement).size == 0
end
# creates a statment hash that contains default values for creating an impression (without
# :impressionable_type and impressionable_id as they are not needed for creating via association).
def create_statement(query_params={})
query_params.reverse_merge!(
:controller_name => controller_name,
:action_name => action_name,
:user_id => user_id,
:request_hash => @impressionist_hash,
:session_hash => session_hash,
:ip_address => remote_ip,
:referrer => request.referer
)
end
def session_hash
# # careful: request.session_options[:id] encoding in rspec test was ASCII-8BIT
# # that broke the database query for uniqueness. not sure how to solve this issue
# # seems to depend on app setup/config
# str = request.session_options[:id]
# # probably this isn't a fix: request.session_options[:id].encode("ISO-8859-1")
# logger.debug "Encoding: #{str.encoding.inspect}"
request.session_options[:id]
end
def remote_ip
request.remote_ip
end
#use both @current_user and current_user helper
def user_id
user_id = @current_user ? @current_user.id : nil rescue nil
user_id = current_user ? current_user.id : nil rescue nil if user_id.blank?
user_id
end
end
end