CSC/ECE 517 Fall 2023 - E2373. Reimplementation of teams controller

From Expertiza_Wiki
Jump to navigation Jump to search

Project Overview

Expertiza Background

Expertiza is an online platform designed to facilitate peer review and submission of various types of academic work, including articles, codes, and websites. The application allows instructors to add assignments, grade them, and assign students to teams based on their topic preferences. The platform also enables students to provide feedback on each other's work through peer reviews, which can be helpful in improving the quality of their projects. Expertiza is backed by the National Science Foundation.

Problem Statement

The teams_controller.rb file contains operations on teams like listing of teams of an assignment/course, updating a team, deleting teams of an assignment/course, copying teams between two assignments or courses among others. The model team.rb contains a lot of functions, with probable violations of single responsibility principle and this needs to be reimplemented with care. The files do not benefit from the complex names the functions are given.

What needs to be done:

Emphasize on Single Responsibility Principle - There are a questionable amount of functions that are directed at copying teams and team members between parents (courses/assignments). There are a lot of class functions in the model, which could be bad design. While reimplementing, make sure that SRP is maintained. See if any code is repetitive, and can be cut down.

Improve naming - Some functions have confusing names. For example, the function “bequeath_copy” can definitely be given a better name if the functionality needs to be reimplemented. The over-populated “copy” related functions in this controller decrease the readability of the code.

Better comments - Bigger files and functions require better comments for readability.

Class Diagram

Functionality

In this project, we aim to:

- Interact with teams assignment database (Basic CRUD) - Interactions with a particular team assignment

Project Design

Model

This model is used to manage teams and their assignments. Here is a brief description of its key features:

Associations: It has various associations with other models, including users, join_team_requests, team_node, signed_up_teams, and bids.

CSV Import and Export: It contains methods for importing team data from a CSV file and exporting team data to a CSV file. The import method creates or finds teams and associates users with them based on the CSV data.

Team Creation and Management: It includes methods to create a new team and add or remove users from teams. It checks for existing team membership before adding a user to a team.

Team Name Generation: There is a method to generate a unique team name, which can be prefixed with a provided string.

Version History: The model uses the has_paper_trail gem, which helps in tracking changes to the model's records over time.

Code snippet can be found here:

class TeamsAssignment < ApplicationRecord

 require 'csv'  # Require the 'csv' library
 
 has_many :users, through: :teams_users
 has_many :join_team_requests, dependent: :destroy
 has_one :team_node, foreign_key: :node_object_id, dependent: :destroy
 has_many :signed_up_teams, dependent: :destroy
 has_many :bids, dependent: :destroy
 has_paper_trail
 # Import teams from a CSV file
 def self.import_teams_from_csv(file)
   CSV.foreach(file.path, headers: true) do |row|
     team = self.find_or_create_by(name: row['name'])
     team.users << User.find_by(name: row['user_name'])
   end
 end
 def self.export_teams_to_csv(file)
   CSV.open(file.path, 'w') do |csv|
   csv << ['name', 'user_name'] # Add relevant column names
     all.each do |team|
       team.users.each do |user|
         csv << [team.name, user.name]
       end
     end
   end
 end
 # Method to create a new team
 def create_team(name)
   team = Team.create(name: name, parent_id: self.id)
   TeamNode.create(parent_id: self.id, node_object_id: team.id)
   team
 end
 # Method to add a user to a team
 def add_user_to_team(team, user)
   # Check if the user is already a member of the team
   return if team.users.include?(user)
   TeamsUser.create(team_id: team.id, user_id: user.id)
   # Optionally, you can add this user to any related associations, like CourseParticipants or AssignmentParticipants
 end
 # Method to remove a user from a team
 def remove_user_from_team(team, user)
   team_user = TeamsUser.find_by(team_id: team.id, user_id: user.id)
   team_user&.destroy
 end
 # Generate the team name
 def self.generate_team_name(team_name_prefix = )
   counter = 1
   loop do
     team_name = "#{team_name_prefix} Team_#{counter}"
     return team_name unless TeamsAssignment.find_by(name: team_name)
     counter += 1
   end
 end
 

end

Schema

create_table "teams_assignments", id: :integer, force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1" do |t|

     t.string "name"
     t.integer "parent_id"
     t.string "type"
     t.text "comments_for_advertisement"
     t.boolean "advertise_for_partner"
     t.text "submitted_hyperlinks"
     t.integer "directory_num"
     t.integer "grade_for_submission"
     t.text "comment_for_submission"
     t.integer "pair_programming_request", limit: 1
   end

Teams controller

Api::V1::TeamsAssignmentController, which is responsible for handling HTTP requests related to a model named TeamAssignment. Here is a brief description of its key features:

Before Actions: The controller specifies before actions using the before_action method. It sets up the @team_assignment instance variable for specific controller actions (show, update, destroy, and copy). It also uses rescue_from to handle exceptions.

Index Action: The index action handles a GET request to list all team assignments. It retrieves all team assignments from the database and renders them as JSON.

Show Action: The show action handles a GET request to retrieve a specific team assignment by its ID. It renders the team assignment as JSON.

Create Action: The create action handles a POST request to create a new team assignment. It creates a new TeamAssignment instance with parameters from the request and saves it. It returns a JSON response with the created team assignment or error messages.

Update Action: The update action handles a PUT or PATCH request to update an existing team assignment. It finds the team assignment, updates it with parameters from the request, and returns a JSON response with the updated team assignment or error messages.

Destroy Action: The destroy action handles a DELETE request to delete a specific team assignment by its ID. It removes the team assignment from the database and returns a JSON response indicating the success of the deletion.

Copy Action: The copy action handles a custom action to create a copy of a team assignment. It calls a method copy_team_assignment on the team assignment and returns a JSON response indicating the success or failure of the copy operation.

Private Methods: There are several private methods used to encapsulate common functionality. set_team_assignment finds and sets the @team_assignment instance variable, team_assignment_params permits trusted parameters for creating or updating team assignments, and team_assignment_not_found and parameter_missing handle specific error cases.

This controller provides a RESTful API for managing team assignments, including listing, creating, updating, and deleting team assignments, as well as a custom copy operation. It also includes error handling for common scenarios.

Code snippet:

class Api::V1::TeamsAssignmentController < ApplicationController

 before_action :set_paper_trail_whodunnit
 before_action :set_team_assignment, only: %i[ show update destroy copy ]
 rescue_from ActiveRecord::RecordNotFound, with: :team_assignment_not_found
 rescue_from ActionController::ParameterMissing, with: :parameter_missing
 # GET /team_assignments
 # List all the team_assignments
 def index
   team_assignment = TeamAssignment.all
   render json: team_assignment, status: :ok
 end
 # GET /team_assignments/1
 # Get a team_assignment
 def show
   render json: @team_assignment, status: :ok
 end
 # POST /team_assignments
 # Create a team_assignment
 def create
   team_assignment = TeamAssignment.new(team_assignment_params)
   if team_assignment.save
     render json: team_assignment, status: :created
   else
     render json: team_assignment.errors, status: :unprocessable_entity
   end
 end
 # PATCH/PUT /team_assignments/1
 # Update a team_assignment
 def update
   if @team_assignment.update(team_assignment_params)
     render json: @team_assignment, status: :ok
   else
     render json: @team_assignment.errors, status: :unprocessable_entity
   end
 end
 # DELETE /team_assignments/1
 # Delete a team_assignment
 def destroy
   @team_assignment.destroy
   render json: { message: "Team assignment with id #{params[:id]}, deleted" }, status: :no_content
 end
 # Creates a copy of the team_assignment
 def copy
   if @team_assignment.copy_team_assignment
     render json: { message: "The team assignment #{@team_assignment.name} has been successfully copied" }, status: :ok
   else
     render json: { message: "The team assignment was not able to be copied" }, status: :unprocessable_entity
   end
 end
 private
 # Use callbacks to share common setup or constraints between actions.
 def set_team_assignment
   @team_assignment = TeamAssignment.find(params[:id])
 end
 # Only allow a list of trusted parameters through.
 def team_assignment_params
   params.require(:team_assignment).permit(
     :users,
     :join_team_requests,
     :team_node,
     :signed_up_teams,
     :bids
   )
 end
 def team_assignment_not_found
   render json: { error: "Team assignment with id #{params[:id]} not found" }, status: :not_found
 end
 def parameter_missing
   render json: { error: "Parameter missing" }, status: :unprocessable_entity
 end

end


Testing Plan

Model tests

Factory used:

 factory :teams_assignment do
   name { "Sample Team Assignment" }
   parent_id { 1 } # You can adjust this value as needed
   type { "Assignment" }
   comments_for_advertisement { "Sample comments for advertisement" }
   advertise_for_partner { true }
   submitted_hyperlinks { "Sample hyperlinks" }
   directory_num { 1 }
   grade_for_submission { 100 }
   comment_for_submission { "Sample comment for submission" }
   pair_programming_request { 1 }
 end

To run model tests:

1. git clone

2. cd reimplementation-back-end/

3. bundle install

4. bundle exec rspec spec/models/teams_assignment_spec.rb

To run controller tests:

1. git clone

2. cd reimplementation-back-end/

3. bundle install

4. 4. bundle exec rspec spec/requests/api/v1/teams_assignment_controller_spec.rb

References

Github repo link[1]

Rspec documentation[2]

Github pull request[3]

Team members

1. Reuben Vandezande

2. Nitin Joseph Madapally Abraham

Mentor

Renji Joseph Sabu