dawarich/app/services/create_stats.rb

81 lines
2.1 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2024-03-23 15:29:55 -04:00
class CreateStats
attr_reader :years, :months, :users
2024-03-23 15:29:55 -04:00
def initialize(user_ids)
@users = User.where(id: user_ids)
2024-03-23 15:29:55 -04:00
@years = (1970..Time.current.year).to_a
@months = (1..12).to_a
end
def call
users.each do |user|
years.each do |year|
months.each { |month| update_month_stats(user, year, month) }
2024-03-23 15:29:55 -04:00
end
2024-07-04 16:20:12 -04:00
create_stats_updated_notification(user)
2024-07-04 16:20:12 -04:00
rescue StandardError => e
create_stats_update_failed_notification(user, e)
end
2024-03-23 15:29:55 -04:00
end
private
2024-05-25 07:36:15 -04:00
def points(user, beginning_of_month_timestamp, end_of_month_timestamp)
user
.tracked_points
2024-05-23 14:12:23 -04:00
.without_raw_data
2024-03-23 15:29:55 -04:00
.where(timestamp: beginning_of_month_timestamp..end_of_month_timestamp)
.order(:timestamp)
.select(:latitude, :longitude, :timestamp, :city, :country)
end
def update_month_stats(user, year, month)
beginning_of_month_timestamp = DateTime.new(year, month).beginning_of_month.to_i
end_of_month_timestamp = DateTime.new(year, month).end_of_month.to_i
points = points(user, beginning_of_month_timestamp, end_of_month_timestamp)
return if points.empty?
stat = Stat.find_or_initialize_by(year:, month:, user:)
stat.distance = distance(points)
stat.toponyms = toponyms(points)
stat.daily_distance = stat.distance_by_day
stat.save
end
2024-03-23 15:29:55 -04:00
def distance(points)
2024-08-28 17:54:00 -04:00
distance = 0
2024-03-23 15:29:55 -04:00
points.each_cons(2) do
2024-08-28 17:54:00 -04:00
distance += Geocoder::Calculations.distance_between(
[_1.latitude, _1.longitude], [_2.latitude, _2.longitude], units: DISTANCE_UNIT.to_sym
2024-03-23 15:29:55 -04:00
)
end
2024-08-28 17:54:00 -04:00
distance
2024-03-23 15:29:55 -04:00
end
def toponyms(points)
CountriesAndCities.new(points).call
end
def create_stats_updated_notification(user)
Notifications::Create.new(
user:, kind: :info, title: 'Stats updated', content: 'Stats updated'
).call
end
def create_stats_update_failed_notification(user, error)
Notifications::Create.new(
user:,
kind: :error,
title: 'Stats update failed',
content: "#{error.message}, stacktrace: #{error.backtrace.join("\n")}"
).call
end
2024-03-23 15:29:55 -04:00
end