Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
98 changes: 98 additions & 0 deletions app/controllers/review_reports_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
class ReviewReportsController < ApplicationController
# GET /review_reports/:assignment_id
def index
assignment = Assignment.find(params[:assignment_id])
# Fetch all review response maps for this assignment
review_maps = ReviewResponseMap.where(reviewed_object_id: assignment.id)

report_data = review_maps.map do |map|
reviewer = map.reviewer.user
reviewee = map.reviewee # Team

# Get all responses
responses = Response.where(map_id: map.id).order(created_at: :asc)

rounds = responses.map do |response|
questionnaire = response.questionnaire_by_answer(response.scores.first)
assignment_questionnaire = AssignmentQuestionnaire.find_by(assignment_id: assignment.id, questionnaire_id: questionnaire.id)
round_num = assignment_questionnaire&.used_in_round || 1 # Default to 1 if not specified

{
round: round_num,
calculatedScore: response.aggregate_questionnaire_score,
maxScore: response.maximum_score,
reviewVolume: response.volume,
reviewCommentCount: response.comment_count
}
end

# Use the latest response for general status, but keep rounds data
latest_response = responses.last

# Calculate reviews done/selected
reviews_selected = 1
reviews_completed = latest_response&.is_submitted ? 1 : 0

# Calculate score (latest)
score = latest_response&.aggregate_questionnaire_score
max_score = latest_response&.maximum_score

# Calculate volume (latest)
vol = latest_response&.volume || 0

# Determine status color
status = if !latest_response
"purple" # No review
elsif !latest_response.is_submitted
"red" # Not completed
elsif latest_response.is_submitted && map.reviewer_grade.nil?
"blue" # Completed, no grade
elsif map.reviewer_grade
"brown" # Grade assigned
else
"green" # Fallback or specific case (No submitted work?)
end

{
id: map.id,
reviewerName: reviewer.full_name,
reviewerUsername: reviewer.name,
reviewerId: reviewer.id,
reviewsCompleted: reviews_completed,
reviewsSelected: reviews_selected,
teamReviewedName: reviewee.name,
hasConsent: map.reviewer.permission_granted,
teamReviewedStatus: status,
calculatedScore: score, # Latest score
maxScore: max_score, # Latest max score
rounds: rounds, # All rounds data
reviewComment: latest_response&.additional_comment,
reviewVolume: vol,
reviewCommentCount: latest_response&.comment_count || 0,
assignedGrade: map.reviewer_grade,
instructorComment: map.reviewer_comment
}
end

# Calculate average volume for the assignment
total_volume = report_data.sum { |d| d[:reviewVolume] }
count_volume = report_data.count { |d| d[:reviewVolume] > 0 }
avg_volume = count_volume > 0 ? total_volume.to_f / count_volume : 0

render json: {
reportData: report_data,
averageVolume: avg_volume
}
end

# PATCH /review_reports/:id/update_grade
# Updates the grade and comment for a specific review report
def update_grade
map = ReviewResponseMap.find(params[:id])
if map.update(reviewer_grade: params[:assignedGrade], reviewer_comment: params[:instructorComment])
render json: { message: "Grade updated successfully" }, status: :ok
else
render json: { error: "Failed to update grade" }, status: :unprocessable_entity
end
end
end
7 changes: 7 additions & 0 deletions app/models/Item.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# frozen_string_literal: true

class Item < ApplicationRecord
self.inheritance_column = 'question_type'

before_create :set_seq
belongs_to :questionnaire # each item belongs to a specific questionnaire
has_many :answers, dependent: :destroy, foreign_key: 'item_id'
Expand Down Expand Up @@ -73,4 +75,9 @@ def self.for(record)
# Cast the existing record to the desired subclass
klass.new(record.attributes)
end

def self.find_with_order(ids)
return [] if ids.empty?
where(id: ids).index_by(&:id).slice(*ids).values
end
end
2 changes: 1 addition & 1 deletion app/models/answer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

class Answer < ApplicationRecord
belongs_to :response
belongs_to :item
belongs_to :item, foreign_key: 'question_id'
end
3 changes: 2 additions & 1 deletion app/models/assignment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ class Assignment < ApplicationRecord
attr_accessor :title, :description, :has_badge, :enable_pair_programming, :is_calibrated, :staggered_deadline

def review_questionnaire_id
Questionnaire.find_by_assignment_id id
aq = AssignmentQuestionnaire.find_by(assignment_id: id)
aq ? aq.questionnaire_id : nil
end

def teams?
Expand Down
18 changes: 17 additions & 1 deletion app/models/response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,20 @@ def maximum_score
# puts "total: #{total_weight * questionnaire.max_question_score} "
total_weight * questionnaire.max_question_score
end
end

def volume
text = (additional_comment || "")
scores.each do |s|
text += " " + (s.comments || "")
end
text.downcase.scan(/\b\w+\b/).uniq.count
end

def comment_count
count = 0
scores.each do |s|
count += 1 if s.comments.present?
end
count
end
end
10 changes: 9 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,4 +149,12 @@
get '/:participant_id/instructor_review', to: 'grades#instructor_review'
end
end
end
resources :review_reports, only: [] do
collection do
get ':assignment_id', action: :index
end
member do
patch 'update_grade', action: :update_grade
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class AddGradeAndCommentToResponseMaps < ActiveRecord::Migration[8.0]
def change
add_column :response_maps, :reviewer_grade, :integer
add_column :response_maps, :reviewer_comment, :text
end
end
4 changes: 3 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading