113 lines
2.9 KiB
Ruby
Raw Normal View History

2024-12-07 18:40:23 +01:00
# frozen_string_literal: true
module DiscourseRewind
# Service responsible to fetch a rewind for a username/year.
#
# @example
# ::DiscourseRewind::Rewind::Fetch.call(
2024-12-13 17:00:17 +01:00
# guardian: guardian
2024-12-07 18:40:23 +01:00
# )
#
2025-01-20 16:50:51 +01:00
class FetchReports
2024-12-07 18:40:23 +01:00
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
2025-11-26 15:12:59 -03:00
# @option params [Integer] :count number of reports to fetch (optional, defaults to 3)
2024-12-07 18:40:23 +01:00
# @return [Service::Base::Context]
2025-01-20 16:50:51 +01:00
CACHE_DURATION = Rails.env.development? ? 10.seconds : 5.minutes
2025-11-26 15:12:59 -03:00
INITIAL_REPORT_COUNT = 3
2025-01-20 16:50:51 +01:00
# order matters
REPORTS = [
Action::TopWords,
Action::ReadingTime,
Action::Reactions,
Action::Fbff,
Action::MostViewedTags,
Action::MostViewedCategories,
2025-01-20 16:50:51 +01:00
Action::BestTopics,
Action::BestPosts,
Action::ActivityCalendar,
FEATURE: Add seven new metrics to Discourse Rewind reports (#26) ## Summary Adds seven new metrics to the Discourse Rewind plugin, significantly expanding the types of insights users can get about their annual activity. These new reports cover temporal patterns, community engagement, plugin integrations, and content analysis. ## New Reports ### 1. Time of Day Activity (`time-of-day-activity`) - Analyzes user activity by hour in their timezone - Determines personality type: "early bird" (6-9am), "night owl" (10pm-2am), or "balanced" - Aggregates posts, chat messages, and page views ### 2. New User Interactions (`new-user-interactions`) - Tracks veteran mentorship and community building behavior - Measures likes, replies, and mentions to users who joined this year - Shows unique new users interacted with and total engagement ### 3. Chat Usage (`chat-usage`) - Total messages and average message length - Top 5 favorite channels with message counts - DM statistics (message count, unique conversations) - Reactions received on messages ### 4. AI Usage (`ai-usage`) - Integrates with `discourse-ai` plugin - Total requests, tokens consumed (request/response breakdown) - Top 5 most used features and AI models - Success rate calculation ### 5. Favorite GIFs (`favorite-gifs`) - Extracts GIFs from posts and chat messages - Ranks by engagement score (usage × 10 + likes + reactions) - Supports Giphy, Tenor, and direct GIF URLs - Shows top 5 GIFs with usage statistics ### 6. Assignments (`assignments`) - Integrates with `discourse-assign` plugin - Tracks assignments received and given - Shows completion rate and pending assignments ### 7. Invites (`invites`) - Total invites sent and redemption rate - Impact metrics: invitee posts, topics, and likes created - Most active invitee identification - Average trust level of invitees ## Technical Details - All reports extend `BaseReport` class - Include proper enablement checks for plugin dependencies - Use efficient database queries with proper joins and aggregations - Return `nil` when no relevant data exists Co-authored-by: Martin Brennan <mjrbrennan@gmail.com>
2025-10-30 11:18:35 -03:00
Action::TimeOfDayActivity,
Action::NewUserInteractions,
Action::ChatUsage,
Action::AiUsage,
Action::FavoriteGifs,
Action::Assignments,
Action::Invites,
2025-01-20 16:50:51 +01:00
]
2024-12-07 18:40:23 +01:00
2025-01-13 17:00:32 +01:00
model :year
2024-12-11 22:38:58 +01:00
model :date
2025-11-26 15:12:59 -03:00
model :enabled_reports
2024-12-07 18:40:23 +01:00
model :reports
2025-11-26 15:12:59 -03:00
model :total_available
2024-12-07 18:40:23 +01:00
private
2025-01-13 17:00:32 +01:00
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
2025-01-13 17:00:32 +01:00
end
end
def fetch_date(params:, year:)
Date.new(year).all_year
2024-12-11 22:38:58 +01:00
end
2025-11-26 15:12:59 -03:00
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)
2024-12-07 18:40:23 +01:00
2025-11-26 15:12:59 -03:00
return MultiJson.load(cached_list, symbolize_keys: true) if cached_list
2024-12-07 18:40:23 +01:00
2025-11-26 15:12:59 -03:00
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))
2024-12-07 18:40:23 +01:00
reports
end
2025-11-26 15:12:59 -03:00
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
2024-12-07 18:40:23 +01:00
end
end