Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E2476 student_team_controller.rb file created #136

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
7bc5fdf
E2476 student_team_controller.rb file created
moreharsh Nov 16, 2024
58b1086
E2476 basic methods of a controller are defined
moreharsh Nov 16, 2024
31f4165
E2476 show method updated to give the json response back
moreharsh Nov 16, 2024
e89b112
Modified existing student_teams_controller
anmolkoul11 Nov 18, 2024
137813a
Merge pull request #3 from moreharsh/akoul_init
moreharsh Nov 19, 2024
108e44e
Changed the studentteamscontroller class name as per the RESTAPI format
moreharsh Nov 19, 2024
1f994ed
Added private functions to access teams and students data
moreharsh Nov 19, 2024
741a5da
Updated he show function to display team details and not student details
moreharsh Nov 19, 2024
8b3b1db
Added the index method to retrieve Student Teams data using query par…
moreharsh Nov 19, 2024
0a37882
Modified the update method so appropriate response is returned back t…
moreharsh Nov 19, 2024
763d871
resolves #14: cleaning up notify_team_creation_success
akarsh16reddy Nov 27, 2024
80d73b6
resolves #15: moving remove_team_user from student teams controller t…
akarsh16reddy Nov 27, 2024
e44c2a1
resolves #16: adding ParameterMissing callback
akarsh16reddy Nov 28, 2024
3792fc3
Rearranged and cleaned the code
moreharsh Nov 30, 2024
c9e0c72
remove participant method updated
moreharsh Nov 30, 2024
d71b378
Implementing assignment_team, team & correcting all REST API endpoints
akarsh16reddy Dec 1, 2024
957a31d
updated & tested create method, adding db seeds
akarsh16reddy Dec 2, 2024
86b8aa5
all API endpoints work, corrected destroy method & cleanup
akarsh16reddy Dec 2, 2024
5c9ae7d
adding member routes
akarsh16reddy Dec 2, 2024
cff5b3e
update student team controller
anmolkoul11 Dec 2, 2024
7d5b8cd
minor controller refactoring and code cleanup
anmolkoul11 Dec 2, 2024
2481aa2
API endpoint optimizations
anmolkoul11 Dec 2, 2024
7704a3d
Merge pull request #18 from moreharsh/akoul_ref
anmolkoul11 Dec 2, 2024
9d99777
added helper class for private methods
anmolkoul11 Dec 2, 2024
e3d5d22
Adding swagger tests for all REST methods
akarsh16reddy Dec 3, 2024
c6b05c8
adding remove participant REST endpoint
akarsh16reddy Dec 3, 2024
7d3a719
Added validation to check for empty strings for update method
moreharsh Dec 3, 2024
6d20fbe
Made code consitent, remove unwanted calls
moreharsh Dec 3, 2024
3619270
updating student team controller spec and auto team generate changes
anmolkoul11 Dec 3, 2024
9a8fdae
Merge pull request #26 from moreharsh/akoul_2
anmolkoul11 Dec 3, 2024
c1d4d21
covering more scenarios in create & update with minor bug fixes
anmolkoul11 Dec 3, 2024
62e05ef
added tests for remove_participant & fixed buggy exceptions
anmolkoul11 Dec 4, 2024
8dae732
adding add_participant & better responses
akarsh16reddy Dec 4, 2024
71e7597
add participant to swagger
akarsh16reddy Dec 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions app/controllers/api/v1/student_teams_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
class Api::V1::StudentTeamsController < ApplicationController
include StudentTeamsHelper

rescue_from ActiveRecord::RecordNotFound, with: :record_not_found
rescue_from ActionController::ParameterMissing, with: :parameter_missing

before_action :set_student, only: %i[view create remove_participant add_participant]

# GET /api/v1/student_teams
# Retrieve all student teams information
def index
fetch_all_teams_and_participants all_teams
end

# GET /student_teams/:id
# Show details of a specific student team
def show
fetch_team_and_participants current_team
rescue ActiveRecord::RecordNotFound => e
render json: { error: e.message }, status: :not_found
end

# POST /student_teams
# Create a new team for the student
def create
team_name = params[:team][:name].presence || generate_team_name
existing_teams = AssignmentTeam.where(name: team_name, assignment_id: @student.assignment_id)

if existing_teams.empty?
parent = Assignment.find_by(id: @student.assignment_id)
team = AssignmentTeam.new(name: team_name, assignment_id: @student.assignment_id)
if parent&.auto_assign_mentor
team = team.upgrade_to_mentored_team
end
if team.save
user = User.find(@student.user_id)
team.add_member(user, team.assignment_id)
fetch_team_and_participants team, :created
else
render json: team.errors, status: :unprocessable_entity
end
else
render json: { error: 'That team name is already in use.' }, status: :unprocessable_entity
end
end

# PATCH/PUT /student_teams
# Update team details: name
def update
team = AssignmentTeam.find(params[:team_id])
team_name = params[:team][:name]
if team_name.blank?
return render json: { error: 'Team name cannot be empty.' }, status: :unprocessable_entity
end

matching_teams = AssignmentTeam.where(name: team_name, assignment_id: team.assignment.id)
success_response = -> { render json: { message: "The team: '#{team.name}' has been updated successfully." }, status: :ok }
if matching_teams.empty?
if team.update(name: team_name)
success_response.call
else
render json: { error: team.errors.full_messages }, status: :unprocessable_entity
end
elsif matching_teams.length == 1 && matching_teams.first.name == team.name
success_response.call
else
render json: { error: 'That team name is already in use.' }, status: :unprocessable_entity
end
rescue ActiveRecord::RecordNotFound
render json: { error: "AssignmentTeam with id #{params[:team_id]} not found." }, status: :not_found
end

# DELETE /student_teams/:id
# Delete a specific team
def destroy
team = AssignmentTeam.find(params[:id])
if team.destroy
head :no_content
else
render json: { error: 'Failed to delete team.' }, status: :unprocessable_entity
end
rescue ActiveRecord::RecordNotFound
render json: { error: "AssignmentTeam with id #{params[:id]} not found." }, status: :not_found
end

# DELETE /student_teams/:id/remove_participant
# Remove a participant from the team
def remove_participant
begin
team = AssignmentTeam.find(params[:id])
destroyed, message = team.remove_team_user(user_id: @student.user_id)
Invitation.where(from_user: @student, assignment: @student.assignment_id).destroy_all
render json: { message: message }, status: destroyed ? :no_content : :not_found

rescue ActiveRecord::RecordNotFound => e
render json: { message: 'Team not found.' }, status: :not_found
end
end

# PATCH /student_teams/:id/add_participant
# Add a participant to the team
def add_participant
team = AssignmentTeam.find_by(id: params[:id])
if team.nil?
render json: { error: "Team with id #{params[:id]} not found" }, status: :not_found
else
user = User.find(@student.user_id)
begin
team.add_member(user, team.assignment_id)
if team.save
fetch_team_and_participants team
else
render json: team.errors, status: :unprocessable_entity
end
rescue => e
render json: { error: e.message }, status: :unprocessable_entity
end
end
end
end
59 changes: 59 additions & 0 deletions app/helpers/student_teams_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module StudentTeamsHelper
private

def set_team
@team = AssignmentTeam.find(params[:team_id])
end

def all_teams
AssignmentTeam.all
end

def current_team
AssignmentTeam.find(params[:id])
end

def set_student
@student = AssignmentParticipant.find(params[:student_id])
end

def generate_team_name
loop do
suffix = rand(1..999)
team_name = "Team_#{suffix}"
break team_name unless AssignmentTeam.exists?(name: team_name)
end
end

def record_not_found(exception)
if exception.model == 'AssignmentTeam'
render json: { error: 'Team id not found.' }, status: :not_found
elsif exception.model == 'AssignmentParticipant'
render json: { error: 'User id not found.' }, status: :not_found
else
render json: { error: 'Record not found.' }, status: :not_found
end
end

def parameter_missing(exception)
render json: { error: "Parameter missing: #{exception.param}" }, status: :unprocessable_entity
end

def fetch_team_and_participants(team, status = :ok)
participants = team.assignment_participants
team_json = team.as_json
team_json[:participants] = participants.map { |participant| { student_id: participant.id } }
render json: team_json, status: status
end

def fetch_all_teams_and_participants(teams, status = :ok)
teams = teams.map do |team|
# Convert the team object to a JSON hash
team_json = team.as_json
# Append the participants to the team JSON hash
team_json[:participants] = team.assignment_participants.map { |participant| { student_id: participant.id } }
team_json
end
render json: { teams: teams }, status: status
end
end
74 changes: 74 additions & 0 deletions app/models/assignment_team.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
class AssignmentTeam < Team

# Get Participants of the team
def assignment_participants
users = self.users
participants = []
users.each do |user|
participant = AssignmentParticipant.find_by(user_id: user.id, assignment_id: self.assignment.id)
participants << participant unless participant.nil?
end
participants
end

def add_participant(assignment_id, user)
return if AssignmentParticipant.find_by(assignment_id: assignment_id, user_id: user.id)

AssignmentParticipant.create(assignment_id: assignment_id, user_id: user.id)
end

def received_any_peer_review?
ResponseMap.where(reviewee_id: id, reviewed_object_id: self.assignment.id).any?
end

# Prototyping AssignmenTeam to MentoredTeam
# TODO :: Assign mentor once MentorManagement is implemented
def upgrade_to_mentored_team
# Duplicate AssignmentTeam
mentored_team = self.dup

# Dynamically hook into add_member logic to invoke MentorManagement if can add member
mentored_team.define_singleton_method(:add_member) do |user, assignment_id|
# Call the original implementation with the arguments
can_add_member = super(user, assignment_id)
# Mentor Management is not yet implemented, so having to comment this line
# MentorManagement.assign_mentor(_assignment_id, id) if can_add_member
can_add_member
end

# Return overridden team
mentored_team
end

private

def dup
ActiveRecord::Base.transaction do
# Duplicate the team itself
duplicated_team = self.dup
duplicated_team.save!

# Duplicate associated signed_up_teams
self.signed_up_teams.each do |signed_up_team|
duplicated_team.signed_up_teams.create!(signed_up_team.attributes.except("id", "team_id", "created_at", "updated_at"))
end

# Duplicate associated teams_users and retain user associations
self.teams_users.each do |teams_user|
duplicated_team_user = duplicated_team.teams_users.create!(teams_user.attributes.except("id", "team_id", "created_at", "updated_at"))
duplicated_team_user.user = teams_user.user # Reassociate the existing user
duplicated_team_user.save!
end

# Duplicate participants
self.participants.each do |participant|
duplicated_team.participants.create!(participant.attributes.except("id", "team_id", "created_at", "updated_at"))
end

duplicated_team
end
rescue => e
Rails.logger.error("Failed to duplicate team: #{e.message}")
raise ActiveRecord::Rollback
end
end
55 changes: 55 additions & 0 deletions app/models/team.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,59 @@ def full?
false
end
end

def self.size(team_id)
#TeamsUser.where(team_id: team_id).count
count = 0
members = TeamsUser.where(team_id: team_id)
members.each do |member|
member_name = member.name
unless member_name.include?(' (Mentor)')
count = count + 1
end
end
count
end

# Add member to the team, changed to hash by E1776
def add_member(user, _assignment_id)
raise "The user #{user.name} is already a member of the team #{name}" if user?(user)

can_add_member = false
unless full?
can_add_member = true
t_user = TeamsUser.create(user_id: user.id, team_id: self.id)
add_participant(_assignment_id, user)
end
can_add_member
end

def user?(user)
users.include? user
end

# TODO :: Remove the team from waitlist, once Waitlist is implemented
def remove_team_user(user_id:)
if TeamsUser.exists?(team_id: self.id, user_id: user_id)
TeamsUser.where(team_id: self.id, user_id: user_id).destroy_all
else
return [false, "Student does not belong to team #{self.id}"]
end

# if this user is the last member of the team then the team does not
# have any members, delete the entry for the team
# puts TeamsUser.where(team_id: self.id).inspect
if TeamsUser.where(team_id: self.id).empty?
old_team = AssignmentTeam.find self.id
if (old_team && Team.size(old_team.id) == 0 && !old_team.received_any_peer_review?)
old_team.destroy
return [true, "Team #{self.id} is destroyed as the last user is removed"]
# if assignment has signup sheet then the topic selected by the team has to go back to the pool
# or to the first team in the waitlist
# Waitlist.remove_from_waitlists(team_id)
end
end
return [true, "Participant Removed Successfully"]
end

end
14 changes: 14 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,20 @@
end
end

resources :student_teams do
member do
get :show
delete :destroy
end
collection do
get :index
post :create
patch :update
delete ':id/remove_participant',action: :remove_participant
patch ':id/add_participant', action: :add_participant
end
end

resources :courses do
collection do
get ':id/add_ta/:ta_id', action: :add_ta
Expand Down
8 changes: 8 additions & 0 deletions db/migrate/20241201203840_create_assignment_teams.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
class CreateAssignmentTeams < ActiveRecord::Migration[7.0]
def change
create_table :assignment_teams do |t|

t.timestamps
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddAutoAssignMentorToAssignments < ActiveRecord::Migration[7.0]
def change
add_column :assignments, :auto_assign_mentor, :boolean
end
end
5 changes: 5 additions & 0 deletions db/migrate/20241201221122_add_type_to_teams.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddTypeToTeams < ActiveRecord::Migration[7.0]
def change
add_column :teams, :type, :string
end
end
5 changes: 5 additions & 0 deletions db/migrate/20241202002102_add_name_to_teams.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddNameToTeams < ActiveRecord::Migration[7.0]
def change
add_column :teams, :name, :string
end
end
Loading