CSC/ECE 517 Fall 2023 - E2360. View for Results of Bidding
Expertiza
Expertiza is an open source project based on Ruby on Rails framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including URLs and wiki pages.
Background
When topics are opened up for bidding, students can see how “hot” each topic is by the color it has on their topic list. However, instructors have no way to view the bidding process except by impersonating students. Furthermore, when the bidding assignment algorithm is run, there is no way to verify that it did in fact assign teams to topics they had chosen.
Previous Work
CSC/ECE_517_Spring_2022_-_E2245:_View_for_results_of_bidding
Accomplishments
This project added a "View Bidding Details" when the instructor enables the "bidding for topics" feature. By clicking it, it redirects us to a new page, where shows the following details of bidding:
- Topic Name
- Bidding Teams
- Bidding Order
- The number of bidding a topic gets
Also, for each topic, the team that wins the bidding will be highlighted with a yellow background color so that the instructor can easily find out which team each topic is assigned to.
The button leads to a page that contains bidding information for the assignment. It displays the number of #1, #2, and #3 bids on a specific topic, the teams that bid and priority of their bid, and the name of the team that got assigned the topic is highlighted.
Files Involved:
The files to be worked upon are:
- ./app/controllers/lottering_controller.rb
- ./app/views/lottery/bidding_details.ntml.erb
- ./app/assignments/edit/_topics.html.erb
- ./spec/controllers/lottery_controller.rb
Team Members
- Richard Li rli14@ncsu.edu
- Shreshth Malik smalik4@ncsu.edu
- Shuai Chen schen76@ncsu.edu
Implemented Code
1. Lottery Controller
File: ./app/controllers/lottery_controller.rb
Method: "bidding_details"
Functionality:
(1) Assignment Retrieval:
- Retrieves the assignment based on the provided id from the params.
(2) Topic Fetching:
- Gathers all the sign-up topics associated with the retrieved assignment.
(3) Initialization of Data Structures:
- Initializes two hash data structures:
- @bids_by_topic: To store bids by topic.
- @assigned_teams_by_topic: To store teams assigned to each topic.
(4) Data Aggregation:
Iterates through each topic and performs the following actions:
(i) Bids Gathering:
- Fetches all bids for each topic.
- Bids are stored in @bids_by_topic, mapped by the topic.id. Each bid includes the team and its priority.
(ii) Assigned Teams Gathering:
- Retrieves teams that are assigned to a topic and are not waitlisted.
- The results are stored in @assigned_teams_by_topic, indexed by topic.id.
(5) Priority Counts:
- For each topic, the method calculates the number of bids at each priority level (1 to 3).
- It dynamically initializes and updates three instance variables: @count1, @count2, and @count3.
- Each of these variables is a hash that maps topic IDs to the count of bids at the respective priority.
def bidding_details @assignment = Assignment.find(params[:id]) # Fetch all topics for the assignment @topics = @assignment.sign_up_topics # Fetch all bids for these topics @bids_by_topic = {} @assigned_teams_by_topic = {} # This will store the assigned teams for each topic @topics.each do |topic| # Assuming bids are stored with a topic_id, and each bid has a team associated with it @bids_by_topic[topic.id] = Bid.where(topic_id: topic.id).map { |bid| { team: bid.team, priority: bid.priority } } # Fetch teams that are not waitlisted for this topic @assigned_teams_by_topic[topic.id] = SignedUpTeam.where(topic_id: topic.id, is_waitlisted: false).map(&:team) # Dynamically initializing and updating @count1, @count2, and @count3 (1..3).each do |priority| instance_variable_set("@count#{priority}", Hash.new(0)) unless instance_variable_defined?("@count#{priority}") instance_variable_get("@count#{priority}")[topic.id] = @bids_by_topic[topic.id].count { |bid| bid[:priority] == priority } end end end
2. Bidding Details View
File: ./app/views/lottery/bidding_details.html.erb
Added a button and corresponding JavaScript which toggles its visibility based on “Enable bidding for topics?” checkbox.
Components:
1. Custom CSS Style:
- A style block is defined to style elements with the assigned-team class. Teams assigned to a topic will have a yellow background and black text.
2. Bidding Details Table:
- A table is created with classes table, table-bordered, and table-hover for styling.
- The header (<thead>) section of the table defines five columns: "Topic Name", "Bidding Teams", and three columns for bid counts ("#1 bids", "#2 bids", "#3 bids").
3. Dynamic Table Rows:
- The <tbody> section uses ERB to iterate over each topic in the @topics array.
- Each topic creates a table row () with the following data:
- Topic Name: Displayed using <%= topic.topic_name %>.
- Bidding Teams: A list of teams bidding on the topic. For each bid associated with the topic:
- The team's name and priority number are displayed.
- If the team is assigned to the topic, it is styled with the assigned-team class.
- Bid Counts: Three columns display the number of #1, #2, and #3 bids for each topic. If there are no bids, it displays "No bids yet".
4. Navigation Link:
<a href="javascript:history.back()">Back</a>
: Provides a link to go back to the previous page in the browser history.
<h3>Bidding Details for <%= @assignment.name %></h3> <style> .assigned-team { background-color: yellow; color: black; } </style> <table class="table table-bordered table-hover"> <thead> <tr> <th>Topic Name</th> <th>Bidding Teams</th> <th>#1 bids</th> <th>#2 bids</th> <th>#3 bids</th> </tr> </thead> <tbody> <% @topics.each do |topic| %> <tr> <td><%= topic.topic_name %></td> <td> <% @bids_by_topic[topic.id].each do |bid_info| %> <% team = bid_info[:team] %> <% assigned_team = @assigned_teams_by_topic[topic.id].include?(team) %> <span class="<%= assigned_team ? 'assigned-team' : '' %>"> <%= team.name %> (#<%= bid_info[:priority] %>) </span> <% end %> </td> <td> <% if @count1[topic.id] != 0%> <%= @count1[topic.id] %> <%else%> No bids yet <%end%> </td> <td> <% if @count2[topic.id] != 0%> <%= @count2[topic.id] %> <%else%> No bids yet <%end%> </td> <td> <% if @count3[topic.id] != 0%> <%= @count3[topic.id] %> <%else%> No bids yet <%end%> </td> </tr> <% end %> </tbody> </table> <a href="javascript:history.back()">Back</a>
3. The button of View Bidding Details
File: ./app/assignments/edit/_topics.html.erb
<%= button_to 'View Bidding Details', {:controller => 'lottery', :action => 'bidding_details', :id => @assignment_form.assignment.id}, :method => :get, class: 'custom-button', id: 'bidding-button' %>
4. RSpec Testing on "bidding_details" Method
File: ./spec/controllers/lottery_controller_spec.rb
Structure:
1. Setup (before :each block):
- Initializes a testing environment before each test case.
- Sets up parameters (like assignment.id) to mimic a real request context.
2. Test Case 1: Populating Bids and Assigned Teams
- Objective: To test if the #bidding_details method correctly populates bids and assigned teams for each topic, including handling topics with no teams.
- Execution: Calls the #bidding_details method.
- Expectations:
- @bids_by_topic should correctly map topics to their respective bids.
- @assigned_teams_by_topic should correctly map topics to their assigned teams, handling cases where no teams are assigned.
- Counts of bids for each priority level (@count1, @count2, @count3) are checked against expected values.
3. Test Case 2: Fetching All Topics
- Objective: To verify if the method fetches all topics related to the assignment.
- Execution: Invokes #bidding_details.
- Expectation: The @topics instance variable should contain an array of all topics (e.g., [topic1, topic2, topic3, topic4]).
describe '#bidding_details' do before :each do # Set the assignment id in the params params = ActionController::Parameters.new(id: assignment.id) allow(controller).to receive(:params).and_return(params) end it 'populates bids and assigned teams for each topic, handling topics with no teams' do controller.bidding_details # Check if @bids_by_topic is populated correctly expect(controller.instance_variable_get(:@bids_by_topic)[topic1.id].length).to eq(1) expect(controller.instance_variable_get(:@bids_by_topic)[topic2.id].length).to eq(1) # Check if @assigned_teams_by_topic is populated correctly, allowing for no teams assigned_teams_topic1 = controller.instance_variable_get(:@assigned_teams_by_topic)[topic1.id] if assigned_teams_topic1 expect(assigned_teams_topic1.length).to(satisfy { |value| (value == 0) || (value == 1) }) else expect(assigned_teams_topic1).to be_nil end # Check the counts of bids for each priority level # Ensure to adjust these based on what is set up in your test data expect(controller.instance_variable_get(:@count1)[topic1.id]).to eq(1) # assuming there is one bid with priority 1 for topic1 expect(controller.instance_variable_get(:@count2)[topic1.id]).to eq(0) # assuming there are no bids with priority 2 for topic1 expect(controller.instance_variable_get(:@count3)[topic1.id]).to eq(0) # assuming there are no bids with priority 3 for topic1 end it 'fetches all topics for the assignment' do controller.bidding_details expect(controller.instance_variable_get(:@topics)).to match_array([topic1, topic2, topic3, topic4]) end end
Relevant Links
Github Repository: https://github.com/Shreshth-Malik/expertiza
Testing Credentials
username: instructor6
password: password
Team
Mentor
Edward F. Gehringer (efg@ncsu.edu)
Members
Richard Li (rli14@ncsu.edu)
Shreshth Malik (smalik4@ncsu.edu)
Shuai Chen (schen76@ncsu.edu)