app/models/review_response_map.rb
class ReviewResponseMap < ResponseMap
belongs_to :reviewee, class_name: 'Team', foreign_key: 'reviewee_id', inverse_of: false
belongs_to :contributor, class_name: 'Team', foreign_key: 'reviewee_id', inverse_of: false
belongs_to :assignment, class_name: 'Assignment', foreign_key: 'reviewed_object_id', inverse_of: false
# Added for E1973:
# http://wiki.expertiza.ncsu.edu/index.php/CSC/ECE_517_Fall_2019_-_Project_E1973._Team_Based_Reviewing
# ReviewResponseMap was created in so many places, I thought it best to add this here as a catch-all
def after_initialize
# If an assignment supports team reviews, it is marked in each mapping
assignment.team_reviewing_enabled
end
# Find a review questionnaire associated with this review response map's assignment
def questionnaire(round_number = nil, topic_id = nil)
Questionnaire.find(assignment.review_questionnaire_id(round_number, topic_id))
end
def get_title
'Review'
end
def delete(_force = nil)
fmaps = FeedbackResponseMap.where(reviewed_object_id: response.response_id)
fmaps.each(&:destroy)
maps = MetareviewResponseMap.where(reviewed_object_id: id)
maps.each(&:destroy)
destroy
end
def self.export_fields(_options)
['contributor', 'reviewed by']
end
def self.export(csv, parent_id, _options)
mappings = where(reviewed_object_id: parent_id).to_a
mappings.sort! { |a, b| a.reviewee.name <=> b.reviewee.name }
mappings.each do |map|
csv << [
map.reviewee.name,
map.reviewer.name
]
end
end
def self.import(row_hash, _session, assignment_id)
reviewee_user_name = row_hash[:reviewee].to_s
reviewee_user = User.find_by(name: reviewee_user_name)
raise ArgumentError, 'Cannot find reviewee user.' unless reviewee_user
reviewee_participant = AssignmentParticipant.find_by(user_id: reviewee_user.id, parent_id: assignment_id)
raise ArgumentError, 'Reviewee user is not a participant in this assignment.' unless reviewee_participant
reviewee_team = AssignmentTeam.team(reviewee_participant)
if reviewee_team.nil? # lazy team creation: if the reviewee does not have team, create one.
reviewee_team = AssignmentTeam.create(name: 'Team' + '_' + rand(1000).to_s,
parent_id: assignment_id, type: 'AssignmentTeam')
t_user = TeamsUser.create(team_id: reviewee_team.id, user_id: reviewee_user.id)
team_node = TeamNode.create(parent_id: assignment_id, node_object_id: reviewee_team.id)
TeamUserNode.create(parent_id: team_node.id, node_object_id: t_user.id)
end
row_hash[:reviewers].each do |reviewer|
reviewer_user_name = reviewer.to_s
reviewer_user = User.find_by(name: reviewer_user_name)
raise ArgumentError, 'Cannot find reviewer user.' unless reviewer_user
next if reviewer_user_name.empty?
reviewer_participant = AssignmentParticipant.find_by(user_id: reviewer_user.id, parent_id: assignment_id)
raise ArgumentError, 'Reviewer user is not a participant in this assignment.' unless reviewer_participant
ReviewResponseMap.find_or_create_by(reviewed_object_id: assignment_id,
reviewer_id: reviewer_participant.get_reviewer.id,
reviewee_id: reviewee_team.id,
calibrate_to: false)
end
end
def show_feedback(response)
return unless self.response.any? && response
map = FeedbackResponseMap.find_by(reviewed_object_id: response.id)
map.response.last.display_as_html if map && map.response.any?
end
def metareview_response_maps
responses = Response.where(map_id: id)
metareview_list = []
responses.each do |response|
metareview_response_maps = MetareviewResponseMap.where(reviewed_object_id: response.id)
metareview_response_maps.each { |metareview_response_map| metareview_list << metareview_response_map }
end
metareview_list
end
# return the responses for specified round, for varying rubric feature -Yang
def self.get_responses_for_team_round(team, round)
responses = []
if team.id
maps = ResponseMap.where(reviewee_id: team.id, type: 'ReviewResponseMap')
maps.each do |map|
if map.response.any? && map.response.reject { |r| (r.round != round || !r.is_submitted) }.any?
responses << map.response.reject { |r| (r.round != round || !r.is_submitted) }.last
end
end
responses.sort! { |a, b| a.map.reviewer.fullname <=> b.map.reviewer.fullname }
end
responses
end
# E-1973 - returns the reviewer of the response, either a participant or a team
def get_reviewer
ReviewResponseMap.get_reviewer_with_id(assignment.id, reviewer_id)
end
# E-1973 - gets the reviewer of the response, given the assignment and the reviewer id
# the assignment is used to determine if the reviewer is a participant or a team
def self.get_reviewer_with_id(assignment_id, reviewer_id)
assignment = Assignment.find(assignment_id)
if assignment.team_reviewing_enabled
return AssignmentTeam.find(reviewer_id)
else
return AssignmentParticipant.find(reviewer_id)
end
end
# wrap latest version of responses in each response map, together with the questionnaire_id
# will be used to display the reviewer summary
def self.final_versions_from_reviewer(assignment_id, reviewer_id)
reviewer = ReviewResponseMap.get_reviewer_with_id(assignment_id, reviewer_id)
maps = ReviewResponseMap.where(reviewer_id: reviewer_id)
assignment = Assignment.find(reviewer.parent_id)
prepare_final_review_versions(assignment, maps)
end
def self.review_response_report(id, assignment, type, review_user)
if review_user.nil?
# This is not a search, so find all reviewers for this assignment
response_maps_with_distinct_participant_id =
ResponseMap.select('DISTINCT reviewer_id').where('reviewed_object_id = ? and type = ? and calibrate_to = ?', id, type, 0)
@reviewers = []
response_maps_with_distinct_participant_id.each do |reviewer_id_from_response_map|
@reviewers << ReviewResponseMap.get_reviewer_with_id(assignment.id, reviewer_id_from_response_map.reviewer_id)
end
# we sort the reviewer by name here, using whichever class it is an instance of
@reviewers = if assignment.team_reviewing_enabled
Team.sort_by_name(@reviewers)
else
Participant.sort_by_name(@reviewers)
end
else
# This is a search, so find reviewers by user's full name
user_ids = User.select('DISTINCT id').where('fullname LIKE ?', '%' + review_user[:fullname] + '%')
# E1973 - we use a separate query depending on if the reviewer is a team or participant
if assignment.team_reviewing_enabled
reviewer_participants = AssignmentTeam.where('id IN (?) and parent_id = ?', team_ids, assignment.id)
@reviewers = []
reviewer_participants.each do |participant|
unless @reviewers.include? participant.team
@reviewers << participant.team
end
end
else
@reviewers = AssignmentParticipant.where('user_id IN (?) and parent_id = ?', user_ids, assignment.id)
end
end
# @review_scores[reviewer_id][reviewee_id] = score for assignments not using vary_rubric_by_rounds feature
# @review_scores[reviewer_id][round][reviewee_id] = score for assignments using vary_rubric_by_rounds feature
end
def email(defn, _participant, assignment)
defn[:body][:type] = 'Peer Review'
AssignmentTeam.find(reviewee_id).users.each do |user|
defn[:body][:obj_name] = assignment.name
defn[:body][:first_name] = User.find(user.id).fullname
defn[:to] = User.find(user.id).email
Mailer.sync_message(defn).deliver_now
end
end
def self.prepare_final_review_versions(assignment, maps)
review_final_versions = {}
rounds_num = assignment.rounds_of_reviews
if rounds_num && (rounds_num > 1)
(1..rounds_num).each do |round|
prepare_review_response(assignment, maps, review_final_versions, round)
end
elsif assignment.vary_by_topic?
prepare_review_response_by_topic(assignment, maps, review_final_versions)
else
prepare_review_response(assignment, maps, review_final_versions, nil)
end
review_final_versions
end
def self.prepare_review_response(assignment, maps, review_final_versions, round)
symbol = if round.nil?
:review
else
('review round' + ' ' + round.to_s).to_sym
end
review_final_versions[symbol] = {}
review_final_versions[symbol][:questionnaire_id] = assignment.review_questionnaire_id(round)
response_ids = []
maps.each do |map|
where_map = { map_id: map.id }
where_map[:round] = round unless round.nil?
responses = Response.where(where_map)
response_ids << responses.last.id unless responses.empty?
end
review_final_versions[symbol][:response_ids] = response_ids
end
def self.prepare_review_response_by_topic(assignment, maps, review_final_versions)
responses_by_questionnaire = Hash.new { |hash, key| hash[key] = [] }
maps.each do |map|
team = AssignmentTeam.find(map.reviewee_id)
topic_id = SignedUpTeam.topic_id_by_team_id(team.id)
# Get the questionnaire ID corresponding to the assignment_id and topic_id of the participant
questionnaire = AssignmentQuestionnaire.where(assignment_id: assignment.id, topic_id: topic_id).first
questionnaire_id = questionnaire.questionnaire_id
# Get the responses for the response map
where_map = { map_id: map.id, round: 1 }
responses = Response.where(where_map)
# Append the response ID to the corresponding response_ids array
responses_by_questionnaire[questionnaire_id] << responses.last.id unless responses.empty?
end
# Iterate through the grouped responses
responses_by_questionnaire.each_with_index do |(questionnaire_id, response_ids), index|
symbol = "review for rubric #{index + 1}".to_sym
review_final_versions[symbol] = {
questionnaire_id: questionnaire_id,
response_ids: response_ids
}
end
end
end