117 lines
4.3 KiB
Ruby
117 lines
4.3 KiB
Ruby
class AnalyticsService
|
|
def initialize(user_or_org, start_date: "", end_date: "", article_id: nil)
|
|
@user_or_org = user_or_org
|
|
@article_id = article_id
|
|
@start_date = Time.zone.parse(start_date.to_s)&.beginning_of_day
|
|
@end_date = Time.zone.parse(end_date.to_s)&.end_of_day || Time.current.end_of_day
|
|
|
|
load_data
|
|
end
|
|
|
|
def totals
|
|
total_views = article_data.sum(:page_views_count)
|
|
logged_in_page_view_data = page_view_data.where.not(user_id: nil)
|
|
average_read_time_in_seconds = average_read_time(logged_in_page_view_data)
|
|
|
|
{
|
|
comments: {
|
|
total: comment_data.size
|
|
},
|
|
reactions: {
|
|
total: reaction_data.size,
|
|
like: reaction_data.count { |rxn| rxn.category == "like" },
|
|
readinglist: reaction_data.count { |rxn| rxn.category == "readinglist" },
|
|
unicorn: reaction_data.count { |rxn| rxn.category == "unicorn" }
|
|
},
|
|
follows: {
|
|
total: follow_data.size
|
|
},
|
|
page_views: {
|
|
total: total_views,
|
|
average_read_time_in_seconds: average_read_time_in_seconds,
|
|
total_read_time_in_seconds: average_read_time_in_seconds * total_views
|
|
}
|
|
}
|
|
end
|
|
|
|
def stats_grouped_by_day
|
|
result = {}
|
|
|
|
(start_date.to_date..end_date.to_date).each do |date|
|
|
result[date.to_s(:iso)] = cached_data_for_date(date)
|
|
end
|
|
|
|
result
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :user_or_org, :start_date, :end_date, :article_data, :reaction_data, :comment_data, :follow_data, :page_view_data
|
|
|
|
def load_data
|
|
@article_data = Article.published.where("#{user_or_org.class.name.downcase}_id" => user_or_org.id)
|
|
if @article_id
|
|
@article_data = @article_data.where(id: @article_id)
|
|
raise UnauthorizedError if @article_data.blank?
|
|
|
|
article_ids = @article_id
|
|
else
|
|
article_ids = @article_data.pluck(:id)
|
|
end
|
|
|
|
if @start_date && @end_date
|
|
@reaction_data = Reaction.where(reactable_id: article_ids, reactable_type: "Article").
|
|
where(created_at: @start_date..@end_date).
|
|
where("points > 0")
|
|
@comment_data = Comment.where(commentable_id: article_ids, commentable_type: "Article").
|
|
where(created_at: @start_date..@end_date).
|
|
where("score > 0")
|
|
@page_view_data = PageView.where(article_id: article_ids).where(created_at: @start_date..@end_date)
|
|
else
|
|
@reaction_data = Reaction.where(reactable_id: article_ids, reactable_type: "Article").where("points > 0")
|
|
@comment_data = Comment.where(commentable_id: article_ids, commentable_type: "Article").where("score > 0")
|
|
@page_view_data = PageView.where(article_id: article_ids)
|
|
end
|
|
|
|
@follow_data = Follow.where(followable_type: user_or_org.class.name, followable_id: user_or_org.id)
|
|
end
|
|
|
|
def average_read_time(page_view_data)
|
|
page_view_data.size.positive? ? page_view_data.sum(:time_tracked_in_seconds) / page_view_data.size : 0
|
|
end
|
|
|
|
def cached_data_for_date(date)
|
|
expiration_date = if date == Time.current.to_date
|
|
30.minutes
|
|
else
|
|
7.days
|
|
end
|
|
|
|
Rails.cache.fetch("analytics-for-date-#{date}-#{user_or_org.class.name}-#{user_or_org.id}", expires_in: expiration_date) do
|
|
reaction_data_of_date = reaction_data.where("date(created_at) = ?", date)
|
|
logged_in_page_view_data = page_view_data.where("date(created_at) = ?", date).where.not(user_id: nil)
|
|
average_read_time_in_seconds = average_read_time(logged_in_page_view_data)
|
|
total_views = page_view_data.where("date(created_at) = ?", date).sum(:counts_for_number_of_views)
|
|
|
|
{
|
|
comments: {
|
|
total: comment_data.where("date(created_at) = ?", date).size
|
|
},
|
|
reactions: {
|
|
total: reaction_data_of_date.size,
|
|
like: reaction_data_of_date.where("category = ?", "like").size,
|
|
readinglist: reaction_data_of_date.where("category = ?", "readinglist").size,
|
|
unicorn: reaction_data_of_date.where("category = ?", "unicorn").size
|
|
},
|
|
page_views: {
|
|
total: total_views,
|
|
total_read_time_in_seconds: average_read_time_in_seconds * total_views,
|
|
average_read_time_in_seconds: average_read_time_in_seconds
|
|
},
|
|
follows: {
|
|
total: follow_data.where("date(created_at) = ?", date).size
|
|
}
|
|
}
|
|
end
|
|
end
|
|
end
|