Skip to content

E2512: Reimplement Responses_Controller #165

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

Open
wants to merge 67 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
a1cc70c
Created shell for controller file
MGuron Mar 2, 2025
debaad9
Added helper file
MGuron Mar 2, 2025
b33cb63
Moved email logic out of controller into dedicated mailer
MGuron Mar 6, 2025
48153cb
Pulled out assign_action_params and set_content to a service
MGuron Mar 6, 2025
22dcd66
Merge pull request #11 from ellie-not-found/EmailLogic
ellie-not-found Mar 8, 2025
5e02373
Revert "Email logic & Parameter assignment to helpers/services"
MGuron Mar 9, 2025
5412d1c
Merge pull request #12 from ellie-not-found/revert-11-EmailLogic
MGuron Mar 9, 2025
642695d
Added sorting logic to model
MGuron Mar 11, 2025
ac3ded6
Moved sorting logic
MGuron Mar 12, 2025
1b7a85e
Updated to run on an instance of response
MGuron Mar 13, 2025
5a7ce62
Fixed up function a bit, trying on the tests
MGuron Mar 13, 2025
b6b57f3
fixed method to not be a class method
MGuron Mar 14, 2025
f3f404f
Added email logic to model
MGuron Mar 14, 2025
a301319
Refactored the questionnaire_by_response_map function and moved to he…
Mar 15, 2025
59d4967
Fixed method and adjusted tests
Mar 18, 2025
410ccbc
Merge pull request #14 from ellie-not-found/MoveSortingLogic
MGuron Mar 18, 2025
e8d4c80
added scaffolf controller, helper to set content
MGuron Mar 19, 2025
2419f80
Merge pull request #16 from ellie-not-found/refactor-qbrm-method
dchristman Mar 19, 2025
7d98430
added scaffolf controller, helper to set content
MGuron Mar 19, 2025
d96fb73
Merge branch 'Set-Content' of github.com:ellie-not-found/reimplementa…
MGuron Mar 19, 2025
2e3c5e5
merged in updates, renamed helper
MGuron Mar 20, 2025
22631f2
fixed tests
MGuron Mar 20, 2025
0f37aba
Merge pull request #17 from ellie-not-found/Set-Content
MGuron Mar 20, 2025
da1270c
Added lock function, json function
MGuron Mar 22, 2025
23eb2d4
Updated helpers
MGuron Mar 22, 2025
f91bd91
Added method for new and related helpers. Slight updates to existing …
Mar 22, 2025
345df6f
Merge pull request #18 from ellie-not-found/implement-new-create
dchristman Mar 22, 2025
0dc0e9a
Added edit, updated dropdown or scale
MGuron Mar 22, 2025
5c1d4de
Merge remote-tracking branch 'origin/main' into UpdateFuncton
MGuron Mar 22, 2025
f0cea1e
fixed test structure for controller
MGuron Mar 22, 2025
9163fcb
update tests
MGuron Mar 22, 2025
8092a9a
Added score difference email
MGuron Mar 22, 2025
e39b38a
Added view/read
MGuron Mar 23, 2025
c68882d
added created, working on tests
Mar 23, 2025
37f2f01
Merge pull request #21 from ellie-not-found/UpdateFuncton
MGuron Mar 23, 2025
4ada601
Finshed update and tests for it, tests for new not working
Mar 24, 2025
11a4d94
Merge branch 'main' into implement-new-create
dchristman Mar 24, 2025
0f61427
Merge pull request #22 from ellie-not-found/implement-new-create
dchristman Mar 24, 2025
42dd2ec
Added index+show
MGuron Mar 24, 2025
6980fe0
Merge pull request #23 from ellie-not-found/Index+Show
MGuron Mar 24, 2025
4247342
Finished new and create tests
Mar 24, 2025
7823f4f
Merge branch 'main' into implement-new-create-2
dchristman Mar 24, 2025
5075431
Merge pull request #24 from ellie-not-found/implement-new-create-2
dchristman Mar 24, 2025
f2def03
Copied Eleanor's code and fixed test with current setup
ellie-not-found Mar 24, 2025
8041a82
Merge pull request #25 from ellie-not-found/implement-delete
dchristman Mar 24, 2025
0350297
new_feedback reimplementation
ellie-not-found Mar 24, 2025
5fb475a
new_feedback reimplementation
ellie-not-found Mar 24, 2025
f4d05f0
Merge branch 'main' into new_feedback
ellie-not-found Mar 24, 2025
84806c3
Implemented save function
Mar 24, 2025
755b41d
Merge pull request #27 from ellie-not-found/new_feedback
dchristman Mar 24, 2025
ef91af8
Merge branch 'main' into implement-save
dchristman Mar 24, 2025
d273c11
Merge pull request #29 from ellie-not-found/implement-save
dchristman Mar 24, 2025
15f2432
fixed tests in controller and helper
Mar 24, 2025
2a695a6
Merge pull request #30 from ellie-not-found/fix-tests
dchristman Mar 24, 2025
762bbc7
update to new_feedback reimplementation
ellie-not-found Mar 24, 2025
c86b5e2
Merge remote-tracking branch 'origin/main'
ellie-not-found Mar 24, 2025
d01cceb
toggle_permission reimplementation
ellie-not-found Mar 25, 2025
c6b9ef7
added action allowed and tests
Mar 25, 2025
b98fa01
Merge pull request #32 from ellie-not-found/toggle_permission
dchristman Mar 25, 2025
d1b48f6
Merge branch 'main' into action-allowed
dchristman Mar 25, 2025
81afc37
Merge pull request #33 from ellie-not-found/action-allowed
dchristman Mar 25, 2025
a67212a
moved toggle_permission to responses_helper
ellie-not-found Mar 25, 2025
84117b4
Revert "moved toggle_permission to responses_helper"
Mar 25, 2025
34baf48
finished tests
Mar 25, 2025
78f3236
Merge pull request #34 from ellie-not-found/finish-tests
dchristman Mar 25, 2025
a9cccfa
move redirect method and created routes
Mar 25, 2025
7a609ff
Merge pull request #35 from ellie-not-found/add-redirect
dchristman Mar 25, 2025
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
8 changes: 7 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ gem 'lingua'
gem 'find_with_order'

group :development, :test do
gem 'debug', platforms: %i[mri mingw x64_mingw]
#gem 'debug', platforms: %i[mri mingw x64_mingw]
gem 'factory_bot_rails'
gem 'faker'
gem 'rspec-rails'
Expand All @@ -52,3 +52,9 @@ group :development do
# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
gem 'spring'
end

group :test do
gem 'database_cleaner-active_record'
gem 'rails-controller-testing'
gem 'pry'
end
20 changes: 16 additions & 4 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ GEM
bootsnap (1.18.4)
msgpack (~> 1.2)
builder (3.2.4)
coderay (1.1.3)
concurrent-ruby (1.3.5)
connection_pool (2.5.0)
coveralls (0.7.1)
Expand All @@ -91,10 +92,11 @@ GEM
term-ansicolor
thor
crass (1.0.6)
database_cleaner-active_record (2.2.0)
activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1)
date (3.4.1)
debug (1.8.0)
irb (>= 1.5.0)
reline (>= 0.3.1)
diff-lcs (1.5.0)
docile (1.4.0)
domain_name (0.6.20240107)
Expand Down Expand Up @@ -137,6 +139,7 @@ GEM
net-pop
net-smtp
marcel (1.0.4)
method_source (1.1.0)
mime-types (3.6.0)
logger
mime-types-data (~> 3.2015)
Expand Down Expand Up @@ -172,6 +175,9 @@ GEM
pp (0.6.2)
prettyprint
prettyprint (0.2.0)
pry (0.15.2)
coderay (~> 1.1)
method_source (~> 1.0)
psych (5.2.3)
date
stringio
Expand Down Expand Up @@ -203,6 +209,10 @@ GEM
activesupport (= 8.0.1)
bundler (>= 1.15.0)
railties (= 8.0.1)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
Expand Down Expand Up @@ -315,16 +325,18 @@ DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap (>= 1.18.4)
coveralls
debug
database_cleaner-active_record
factory_bot_rails
faker
find_with_order
jwt (~> 2.7, >= 2.7.1)
lingua
mysql2 (~> 0.5.5)
pry
puma (~> 5.0)
rack-cors
rails (~> 8.0, >= 8.0.1)
rails-controller-testing
rspec-rails
rswag-api
rswag-specs
Expand Down
295 changes: 295 additions & 0 deletions app/controllers/api/v1/responses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,295 @@
class Api::V1::ResponsesController < ApplicationController
include ResponsesHelper
include ScorableHelper
before_action :set_response, only: %i[ show update destroy ]
skip_before_action :authorize

def action_allowed?
return !current_user.nil? unless %w[edit delete update view].include?(params[:action])

response = Response.find(params[:id])
user_id = response.map.reviewer&.user_id

case params[:action]
when 'edit'
return false if response.is_submitted
current_user_is_reviewer?(response.map, user_id)
when 'delete', 'update'
current_user_is_reviewer?(response.map, user_id)
when 'view'
response_edit_allowed?(response.map, user_id, response)
end
end



# GET /api/v1/responses
def index
@responses = Response.all

render json: @responses
end

# GET /api/v1/responses/1
def show
if @response
render json: @response, status: :ok
else
render json: { error: 'Response not found' }, status: :not_found
end
end

def new
@map = ResponseMap.find(params[:id])
attributes = prepare_response_content(@map, 'New', true)
attributes.each do |key, value|
instance_variable_set("@#{key}", value)
end
questions = sort_items(@questionnaire.items)
@total_score = total_cake_score(@response)
init_answers(@response, questions)
render action: 'response'
end

# POST /api/v1/responses
def create
@map = find_map
@questionnaire = find_questionnaire
is_submitted = (params[:isSubmit] == 'Yes')

@response = find_or_create_response(is_submitted)
was_submitted = @response.is_submitted

if @response.save
update_response(is_submitted)
process_items if params[:responses]
notify_instructor_if_needed(was_submitted)
msg = 'Your response was successfully saved'
error_msg = ''
redirect_to controller: 'responses', action: 'save', id: @map.map_id,
return: params.permit(:return)[:return], msg: msg, review: params.permit(:review)[:review],
save_options: params.permit(:save_options)[:save_options]
else
render json: @response.errors, status: :unprocessable_entity
end
end

def edit
action_params = { action: 'edit', id: params[:id], return: params[:return] }
response_content = prepare_response_content(@map, action_params)

# Assign variables from response_content hash
response_content.each { |key, value| instance_variable_set("@#{key}", value) }

@largest_version_num = Response.sort_by_version(@review_questions)
@review_scores = @review_questions.map do |question|
Answer.where(response_id: @response.response_id, question_id: question.id).first
end
end

# PATCH/PUT /api/v1/responses/1
def update
return render nothing: true unless action_allowed?

@response.update_attribute('additional_comment', params[:review][:comments])
@questionnaire = @response.questionnaire_by_answer(@response.scores.first)

questions = sort_items(@questionnaire.questions)

# for some rubrics, there might be no questions but only file submission (Dr. Ayala's rubric)
create_answers(params, questions) unless params[:responses].nil?
if params['isSubmit'] && params['isSubmit'] == 'Yes'
@response.update_attribute('is_submitted', true)
end

# Add back emailing logic
if (@map.is_a? ReviewResponseMap) && @response.is_submitted && @response.significant_difference?
@response.send_score_difference_email
end

redirect_to_response_update
end

def delete
if @response.delete
render json: @response, status: :deleted, location: @response
else
render json: @response.errors, status: :unprocessable_entity
end
end

# DELETE /api/v1/responses/1
def destroy
@response.destroy!
end

def save
@map = ResponseMap.find(params[:id])
@return = params[:return]
@map.save
msg = 'Your response was successfully saved'
error_msg = ''
redirect_to controller: 'responses', action: 'save', id: @map.map_id,
return: params.permit(:return)[:return], msg: msg, review: params.permit(:review)[:review],
save_options: params.permit(:save_options)[:save_options]
end

def new_feedback
if Response.find(params[:id])
@map = Response.find(params[:id]).map
response_content = prepare_response_content(@map)

# Assign variables from response_content hash
response_content.each { |key, value| instance_variable_set("@#{key}", value) }
if @response
@reviewer = AssignmentParticipant.where(user_id: current_user.id, parent_id: @response.map.assignment.id).first
map = find_or_create_feedback
redirect_to action: 'new', id: map.id, return: 'feedback'
end
else
redirect_back fallback_location: root_path
end
end

# toggle_permission allows user update visibility.
def toggle_permission
return head :no_content unless action_allowed?

error = update_visibility(params[:visibility])
if error == ''
map_id = @response.map.map_id
else
map_id = nil
end
redirect_to action: 'redirect', id: map_id, return: params[:return], msg: params[:msg], error_msg: error
end

def show_calibration_results_for_student
@assignment = Assignment.find(params[:assignment_id])
@calibration_response = ReviewResponseMap.find(params[:calibration_response_map_id]).response[0]
@review_response = ReviewResponseMap.find(params[:review_response_map_id]).response[0]
@review_questions = AssignmentQuestionnaire.get_questions_by_assignment_id(params[:assignment_id])
end

def authorize_show_calibration_results
response_map = ResponseMap.find(params[:review_response_map_id])
user_id = response_map.reviewer.user_id if response_map.reviewer
# Deny access to the calibration result page if the current user is not a reviewer.
unless current_user_is_reviewer?(response_map, user_id)
flash[:error] = 'You are not allowed to view this calibration result'
redirect_to controller: 'student_review', action: 'list', id: user_id
end
end

#This method was not updated
def redirect
error_id = params[:error_msg]
message_id = params[:msg]
flash[:error] = error_id unless error_id&.empty?
flash[:note] = message_id unless message_id&.empty?
@map = Response.find_by(map_id: params[:id])
case params[:return]
when 'feedback'
redirect_to controller: 'grades', action: 'view_my_scores', id: @map.reviewer.id
when 'teammate'
redirect_to view_student_teams_path student_id: @map.reviewer.id
when 'instructor'
redirect_to controller: 'grades', action: 'view', id: @map.response_map.assignment.id
when 'assignment_edit'
redirect_to controller: 'assignments', action: 'edit', id: @map.response_map.assignment.id
when 'selfreview'
redirect_to controller: 'submitted_content', action: 'edit', id: @map.response_map.reviewer_id
when 'survey'
redirect_to controller: 'survey_deployment', action: 'pending_surveys'
when 'bookmark'
bookmark = Bookmark.find(@map.response_map.reviewee_id)
redirect_to controller: 'bookmarks', action: 'list', id: bookmark.topic_id
when 'ta_review' # Page should be directed to list_submissions if TA/instructor performs the review
redirect_to controller: 'assignments', action: 'list_submissions', id: @map.response_map.assignment.id
else
# if reviewer is team, then we have to get the id of the participant from the team
# the id in reviewer_id is of an AssignmentTeam
reviewer_id = @map.response_map.reviewer.get_logged_in_reviewer_id(current_user.try(:id))
redirect_to controller: 'student_review', action: 'list', id: reviewer_id
end
end


private

def find_map
map_id = params[:map_id] || params[:id]

ResponseMap.find_by(id: map_id)
end

def find_questionnaire
if params[:review][:questionnaire_id]
questionnaire = Questionnaire.find(params[:review][:questionnaire_id])
else
questionnaire = nil
end
questionnaire
end

def find_response
@review = Response.find(params[:id]) unless params[:id].nil?
end

# Only allow a list of trusted parameters through.
def response_params
params.fetch(:response, {})
end

def find_or_create_response(is_submitted = false)
response = Response.where(map_id: @map.map_id).order(created_at: :desc).first
if response.nil?
response = Response.create(map_id: @map.id, additional_comment: params[:review][:comments],
is_submitted: is_submitted)
end
response
end

def update_response(is_submitted)
@response.update(additional_comment: params[:review][:comments], is_submitted: is_submitted)
end

def process_items
items = sort_items(@questionnaire.items)
items = @questionnaire.items
create_answers(params, items)
end

def notify_instructor_if_needed(was_submitted)
if @map.is_a?(ReviewResponseMap) && !was_submitted && @response.is_submitted && @response.significant_difference?
@response.notify_instructor_on_difference
@response.email
end
end

def redirect_to_response_update
msg = 'Your response was successfully updated'
error_msg = ''
redirect_to controller: 'responses', action: 'save', id: @map.map_id,
return: params.permit(:return)[:return], msg: msg, review: params.permit(:review)[:review],
save_options: params.permit(:save_options)[:save_options]
end

# Use callbacks to share common setup or constraints between actions.
def set_response
@response = Response.find(params[:id])
end

# Only allow a list of trusted parameters through.
def response_params
params.require(:response).permit(
:isSubmit,
:map_id,
:id,
review: [:comments, :questionnaire_id],
responses: {}, # Adjust based on structure
save_options: {},
return: {}
)
end
end
Loading