diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 5d2d0584..7396d500 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -21,6 +21,7 @@ def calendar } end + @daily_buddy = Buddy.of_the_day(current_user) @next_puzzle_time = Aoc.next_puzzle_time @now = Aoc.event_timezone.now end diff --git a/app/jobs/buddies/generate_daily_pairs_job.rb b/app/jobs/buddies/generate_daily_pairs_job.rb new file mode 100644 index 00000000..e3148064 --- /dev/null +++ b/app/jobs/buddies/generate_daily_pairs_job.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +module Buddies + class GenerateDailyPairsJob < ApplicationJob + queue_as :default + + def perform(day) + @day = day + + if Buddy.exists?(day:) + Rails.logger.info "Daily pairs already exist for day #{day}" + return + end + + retrieve_confirmed_users + handle_odd_number_of_users + generate_possible_pairs_of_buddies + + @possible_pairs.shuffle! + + pick_valid_pairs_of_buddies + handle_unpaired_users + + insert_generated_buddies + end + + private + + def retrieve_confirmed_users + @user_ids = User.confirmed.order(:id).pluck(:id) + end + + def handle_odd_number_of_users + @user_ids.pop if @user_ids.size.odd? + end + + def generate_possible_pairs_of_buddies + all_pairs = @user_ids.combination(2).to_set + past_buddies = Buddy.pluck(:id_1, :id_2).to_set + + @possible_pairs = (all_pairs - past_buddies).to_a + end + + def pick_valid_pairs_of_buddies + @users_to_match = Set.new(@user_ids) + @buddies = [] + + # Iterate once over possible pairs to find matches + @possible_pairs.each do |pair| + # If a pair contains two available IDs, it's a match! + if pair.all? { |id| @users_to_match.include?(id) } + @buddies << pair + pair.each { |id| @users_to_match.delete(id) } + end + end + end + + def handle_unpaired_users + @buddies += @users_to_match.to_a.shuffle.each_slice(2).to_a + end + + def insert_generated_buddies + Buddy.insert_all!(@buddies.map { |a, b| { day: @day, id_1: a, id_2: b } }) + Rails.logger.info "Buddies successfully generated for day #{@day}" + end + end +end diff --git a/app/models/buddy.rb b/app/models/buddy.rb new file mode 100644 index 00000000..000541aa --- /dev/null +++ b/app/models/buddy.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Buddy < ApplicationRecord + scope :of_today, -> { where(day: Aoc.latest_day) } + scope :of_user, ->(user_id) { where("id_1 = ? OR id_2 = ?", user_id, user_id) } + + def self.of_the_day(user) + buddy_pair = of_today.of_user(user.id).first + daily_buddy_id = user.id == buddy_pair.id_1 ? buddy_pair.id_2 : buddy_pair.id_1 if buddy_pair + + User.find_by(id: daily_buddy_id) + end +end diff --git a/app/views/pages/calendar.html.erb b/app/views/pages/calendar.html.erb index e96d397d..b5c58327 100644 --- a/app/views/pages/calendar.html.erb +++ b/app/views/pages/calendar.html.erb @@ -2,6 +2,20 @@ Welcome, <%= link_to current_user.username, profile_path(current_user.uid), class: "strong hover:text-gold" %>
+<% if @daily_buddy.present? %> + ++ Your daily buddy is + + <% if @daily_buddy.slack_id.present? %> + <%= link_to "@#{@daily_buddy.slack_username}", @daily_buddy.slack_link, target: :_blank, rel: :noopener, class: "link-explicit link-slack" %> + <% else %> + <%= link_to @daily_buddy.username, profile_path(@daily_buddy.uid), class: "link-explicit" %> + <% end %> +
+ +<% end %> +