From 92a7f87eaa07853678c0c922ce147a5e71c20661 Mon Sep 17 00:00:00 2001 From: SaiSanthoshG <52049230+saisanthoshG@users.noreply.github.com> Date: Mon, 22 Apr 2024 00:41:06 -0400 Subject: [PATCH] Added a method to LotteryController for detailed bidding data analysis and informed team assignment decisions. --- app/controllers/lottery_controller.rb | 87 +++++++++++++++++++++------ 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/app/controllers/lottery_controller.rb b/app/controllers/lottery_controller.rb index 0deeceffbde..77ffec1b024 100755 --- a/app/controllers/lottery_controller.rb +++ b/app/controllers/lottery_controller.rb @@ -1,14 +1,12 @@ class LotteryController < ApplicationController + include LotteryHelper include AuthorizationHelper - require 'json' require 'rest_client' - # Give permission to run the bid to appropriate roles def action_allowed? current_user_has_ta_privileges? end - # This method sends a request to a web service that uses k-means and students' bidding data # to build teams automatically. # The webservice tries to create teams with sizes close to the max team size @@ -16,14 +14,13 @@ def action_allowed? # that have similar bidding info/priorities associated with the assignment's sign-up topics. # # rubocop:disable Metrics/AbcSize + def run_intelligent_assignment assignment = Assignment.find(params[:id]) teams = assignment.teams - users_bidding_info = construct_users_bidding_info(assignment.sign_up_topics, teams) bidding_data = { users: users_bidding_info, max_team_size: assignment.max_team_size } ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, "Bidding data for assignment #{assignment.name}: #{bidding_data}", request) - begin url = WEBSERVICE_CONFIG['topic_bidding_webservice_url'] response = RestClient.post url, bidding_data.to_json, content_type: :json, accept: :json @@ -36,12 +33,73 @@ def run_intelligent_assignment rescue StandardError => e flash[:error] = e.message end - redirect_to controller: 'tree_display', action: 'list' end + # Prepares data for displaying the bidding details for each topic within an assignment. + # It calculates the number of bids for each priority (1, 2, 3) per topic and also computes + # the overall percentages of teams that received their first, second, and third choice. + # This method is responsible for calculating the bidding table data for an assignment. + def calculate_bidding_summary_based_on_priority + # Find the assignment by its ID passed in parameters. + @assignment = Assignment.find(params[:id]) + # Retrieve all sign up topics associated with the assignment and include the bids for each topic. + @topics = @assignment.sign_up_topics.includes(:bids) + # Map over each topic to create a structured hash of data needed for the view. + @topic_data = @topics.map do |topic| + # Count the total number of bids for the topic. + total_bids = topic.bids.count + # Count the number of first, second, and third priority bids. + first_bids = topic.bids.where(priority: 1).count + second_bids = topic.bids.where(priority: 2).count + third_bids = topic.bids.where(priority: 3).count + # Extract the team names for the bids. + bidding_teams = topic.bids.includes(:team).map { |bid| bid.team.name } + + # Calculate the percentage of first priority bids. + percentage_first = if total_bids > 0 + # If there are any bids, calculate the percentage. + (first_bids.to_f / total_bids * 100).round(2) + else + # If there are no bids, the percentage is 0. + 0 + end + # Return a hash containing all the calculated and retrieved data for the topic. + { + id: topic.id, + name: topic.topic_name, + first_bids: first_bids, + second_bids: second_bids, + third_bids: third_bids, + total_bids: total_bids, + percentage_first: percentage_first, + bidding_teams: bidding_teams + } + end + end + private + # Computes the count of assigned teams for each priority level (1, 2, 3) across all topics. + # It checks each team associated with a topic and determines if the team's bid matches + # one of the priority levels, incrementing the respective count if so. + def compute_priority_counts(assigned_teams_by_topic, bids_by_topic) + priority_counts = { 1 => 0, 2 => 0, 3 => 0 } + assigned_teams_by_topic.each do |topic_id, teams| + teams.each do |team| + bid_info = bids_by_topic[topic_id].find { |bid| bid[:team] == team } + priority_counts[bid_info[:priority]] += 1 if bid_info + end + end + priority_counts + end + + # Calculates the percentages of teams that received their first, second, and third choice + # based on the counts of teams at each priority level. + def compute_percentages(priority_counts, total_teams) + priority_counts.transform_values { |count| (count.to_f / total_teams * 100).round(2) } + end + # Generate user bidding information hash based on students who haven't signed up yet # This associates a list of bids corresponding to sign_up_topics to a user # Structure of users_bidding_info variable: [{user_id1, bids_1}, {user_id2, bids_2}] @@ -84,11 +142,7 @@ def construct_teams_bidding_info(unassigned_teams, sign_up_topics) # teams def create_new_teams_for_bidding_response(teams, assignment, users_bidding_info) teams.each do |user_ids| - if assignment.auto_assign_mentor - new_team = MentoredTeam.create_team_with_users(assignment.id, user_ids) - else - new_team = AssignmentTeam.create_team_with_users(assignment.id, user_ids) - end + new_team = AssignmentTeam.create_team_with_users(assignment.id, user_ids) # Select data from `users_bidding_info` variable that only related to team members in current team current_team_members_info = users_bidding_info.select { |info| user_ids.include? info[:pid] }.map { |info| info[:ranks] } Bid.merge_bids_from_different_users(new_team.id, assignment.sign_up_topics, current_team_members_info) @@ -102,12 +156,8 @@ def assign_available_slots(teams_bidding_info) teams_bidding_info.each do |tb| tb[:bids].each do |bid| topic_id = bid[:topic_id] - num_of_signed_up_teams = SignedUpTeam.where(topic_id: topic_id).count - max_choosers = SignUpTopic.find(bid[:topic_id]).try(:max_choosers) - if num_of_signed_up_teams < max_choosers - SignedUpTeam.create(team_id: tb[:team_id], topic_id: bid[:topic_id]) - break - end + max_choosers = SignUpTopic.find(topic_id).try(:max_choosers) + SignedUpTeam.create(team_id: tb[:team_id], topic_id: topic_id) if SignedUpTeam.where(topic_id: topic_id).count < max_choosers end end end @@ -124,7 +174,6 @@ def match_new_teams_to_topics(assignment) unassigned_teams = assignment.teams.reload.select do |t| SignedUpTeam.where(team_id: t.id, is_waitlisted: 0).blank? && Bid.where(team_id: t.id).any? end - # Sorting unassigned_teams by team size desc, number of bids in current team asc # again, we need to find a way to to merge bids that came from different previous teams # then sorting unassigned_teams by number of bids in current team (less is better) @@ -134,10 +183,8 @@ def match_new_teams_to_topics(assignment) [TeamsUser.where(team_id: t2.id).size, Bid.where(team_id: t1.id).size] <=> [TeamsUser.where(team_id: t1.id).size, Bid.where(team_id: t2.id).size] end - teams_bidding_info = construct_teams_bidding_info(unassigned_teams, sign_up_topics) assign_available_slots(teams_bidding_info) - # Remove is_intelligent property from assignment so that it can revert to the default sign-up state assignment.update_attributes(is_intelligent: false) flash[:success] = 'The intelligent assignment was successfully completed for ' + assignment.name + '.'