# frozen_string_literal: true module DiscourseRewind # Service responsible to fetch a rewind for a username/year. # # @example # ::DiscourseRewind::Rewind::Fetch.call( # guardian: guardian # ) # class FetchReports include Service::Base # @!method self.call(guardian:, params:) # @param [Guardian] guardian # @param [Hash] params # @option params [Integer] :year of the rewind # @option params [Integer] :username of the rewind # @option params [Integer] :count number of reports to fetch (optional, defaults to 3) # @return [Service::Base::Context] CACHE_DURATION = Rails.env.development? ? 10.seconds : 5.minutes INITIAL_REPORT_COUNT = 3 # order matters REPORTS = [ Action::TopWords, Action::ReadingTime, Action::Reactions, Action::Fbff, Action::MostViewedTags, Action::MostViewedCategories, Action::BestTopics, Action::BestPosts, Action::ActivityCalendar, Action::TimeOfDayActivity, Action::NewUserInteractions, Action::ChatUsage, Action::AiUsage, Action::FavoriteGifs, Action::Assignments, Action::Invites, ] model :year model :date model :enabled_reports model :reports model :total_available private def fetch_year current_date = Time.zone.now current_month = current_date.month current_year = current_date.year case current_month when 1 current_year - 1 when 12 current_year else # Otherwise it's impossible to test in browser unless you're # in December or January if Rails.env.development? current_year else false end end end def fetch_date(params:, year:) Date.new(year).all_year end def fetch_enabled_reports(date:, guardian:, year:) # Generate all reports and filter out nils (disabled/empty reports) # Cache the full list to maintain consistent indices across requests key = "rewind:#{guardian.user.username}:#{year}:all_reports" cached_list = Discourse.redis.get(key) return MultiJson.load(cached_list, symbolize_keys: true) if cached_list reports = REPORTS.filter_map do |report_class| begin report_class.call(date:, user: guardian.user, guardian:) rescue => e Rails.logger.error("Failed to generate report #{report_class.name}: #{e.message}") nil end end # Cache the complete enabled reports list Discourse.redis.setex(key, CACHE_DURATION, MultiJson.dump(reports)) reports end def fetch_total_available(enabled_reports:) enabled_reports.length end def fetch_reports(enabled_reports:, params:) count = params[:count]&.to_i || INITIAL_REPORT_COUNT count = [[count, 1].max, enabled_reports.length].min enabled_reports.first(count) end end end