Skip to content

Commit

Permalink
Added a method to LotteryController for detailed bidding data analysi…
Browse files Browse the repository at this point in the history
…s and informed team assignment decisions.
  • Loading branch information
saisanthoshG committed Apr 22, 2024
1 parent ef449f6 commit 92a7f87
Showing 1 changed file with 67 additions and 20 deletions.
87 changes: 67 additions & 20 deletions app/controllers/lottery_controller.rb
@@ -1,29 +1,26 @@
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
# allowed by the assignment by potentially combining existing smaller teams
# 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
Expand All @@ -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}]
Expand Down Expand Up @@ -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)
Expand All @@ -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
Expand All @@ -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)
Expand All @@ -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 + '.'
Expand Down

0 comments on commit 92a7f87

Please sign in to comment.