Hide score button if exercise has no tests
We check for all teacher-defined assessments (linter and unit tests) to determine whether scoring should be possible
This commit is contained in:

committed by
Sebastian Serth

parent
ba5918b4ca
commit
e0c2c7b806
@ -324,6 +324,8 @@ class ExercisesController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@embed_options[:disable_score] = true unless @exercise.teacher_defined_assessment?
|
||||||
|
|
||||||
@hide_rfc_button = @embed_options[:disable_rfc]
|
@hide_rfc_button = @embed_options[:disable_rfc]
|
||||||
|
|
||||||
@search = Search.new
|
@search = Search.new
|
||||||
|
@ -83,7 +83,7 @@ class SubmissionsController < ApplicationController
|
|||||||
client_socket = tubesock
|
client_socket = tubesock
|
||||||
|
|
||||||
client_socket.onopen do |_event|
|
client_socket.onopen do |_event|
|
||||||
kill_client_socket(client_socket) if @embed_options[:disable_run]
|
return kill_client_socket(client_socket) if @embed_options[:disable_run]
|
||||||
end
|
end
|
||||||
|
|
||||||
client_socket.onclose do |_event|
|
client_socket.onclose do |_event|
|
||||||
@ -199,7 +199,7 @@ class SubmissionsController < ApplicationController
|
|||||||
hijack do |tubesock|
|
hijack do |tubesock|
|
||||||
tubesock.onopen do |_event|
|
tubesock.onopen do |_event|
|
||||||
switch_locale do
|
switch_locale do
|
||||||
kill_client_socket(tubesock) if @embed_options[:disable_score]
|
return kill_client_socket(tubesock) if @embed_options[:disable_score] || !@submission.exercise.teacher_defined_assessment?
|
||||||
|
|
||||||
# The score is stored separately, we can forward it to the client immediately
|
# The score is stored separately, we can forward it to the client immediately
|
||||||
tubesock.send_data(JSON.dump(@submission.calculate_score))
|
tubesock.send_data(JSON.dump(@submission.calculate_score))
|
||||||
@ -226,7 +226,7 @@ class SubmissionsController < ApplicationController
|
|||||||
hijack do |tubesock|
|
hijack do |tubesock|
|
||||||
tubesock.onopen do |_event|
|
tubesock.onopen do |_event|
|
||||||
switch_locale do
|
switch_locale do
|
||||||
kill_client_socket(tubesock) if @embed_options[:disable_run]
|
return kill_client_socket(tubesock) if @embed_options[:disable_run]
|
||||||
|
|
||||||
# The score is stored separately, we can forward it to the client immediately
|
# The score is stored separately, we can forward it to the client immediately
|
||||||
tubesock.send_data(JSON.dump(@submission.test(@file)))
|
tubesock.send_data(JSON.dump(@submission.test(@file)))
|
||||||
|
@ -205,6 +205,10 @@ class Exercise < ApplicationRecord
|
|||||||
"
|
"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def teacher_defined_assessment?
|
||||||
|
files.any?(&:teacher_defined_assessment?)
|
||||||
|
end
|
||||||
|
|
||||||
def get_working_times_for_study_group(study_group_id, user = nil)
|
def get_working_times_for_study_group(study_group_id, user = nil)
|
||||||
user_progress = []
|
user_progress = []
|
||||||
additional_user_data = []
|
additional_user_data = []
|
||||||
|
@ -29,10 +29,14 @@ class ExercisePolicy < AdminOrAuthorPolicy
|
|||||||
define_method(action) { (admin? || teacher_in_study_group? || author?) && @user.codeharbor_link }
|
define_method(action) { (admin? || teacher_in_study_group? || author?) && @user.codeharbor_link }
|
||||||
end
|
end
|
||||||
|
|
||||||
%i[implement? working_times? intervention? search? submit? reload?].each do |action|
|
%i[implement? working_times? intervention? search? reload?].each do |action|
|
||||||
define_method(action) { everyone }
|
define_method(action) { everyone }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def submit?
|
||||||
|
everyone && @record.teacher_defined_assessment?
|
||||||
|
end
|
||||||
|
|
||||||
class Scope < Scope
|
class Scope < Scope
|
||||||
def resolve
|
def resolve
|
||||||
if @user.admin?
|
if @user.admin?
|
||||||
|
@ -6,7 +6,10 @@ describe ExercisesController do
|
|||||||
let(:exercise) { create(:dummy) }
|
let(:exercise) { create(:dummy) }
|
||||||
let(:user) { create(:admin) }
|
let(:user) { create(:admin) }
|
||||||
|
|
||||||
before { allow(controller).to receive(:current_user).and_return(user) }
|
before do
|
||||||
|
create(:test_file, context: exercise)
|
||||||
|
allow(controller).to receive(:current_user).and_return(user)
|
||||||
|
end
|
||||||
|
|
||||||
describe 'PUT #batch_update' do
|
describe 'PUT #batch_update' do
|
||||||
let(:attributes) { {public: 'true'} }
|
let(:attributes) { {public: 'true'} }
|
||||||
|
@ -23,6 +23,7 @@ describe 'Editor', js: true do
|
|||||||
}]
|
}]
|
||||||
end
|
end
|
||||||
let(:user) { create(:teacher) }
|
let(:user) { create(:teacher) }
|
||||||
|
let(:exercise_without_test) { create(:tdd) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
visit(sign_in_path)
|
visit(sign_in_path)
|
||||||
@ -93,12 +94,28 @@ describe 'Editor', js: true do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when an exercise has one or more teacher-defined assessments' do
|
||||||
|
it 'displays the score button' do
|
||||||
|
visit(implement_exercise_path(exercise))
|
||||||
|
expect(page).to have_content(exercise.title)
|
||||||
|
expect(page).to have_content(I18n.t('exercises.editor.score'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when an exercise has no teacher-defined assessment' do
|
||||||
|
it 'disables the score button' do
|
||||||
|
visit(implement_exercise_path(exercise_without_test))
|
||||||
|
expect(page).to have_content(exercise_without_test.title)
|
||||||
|
expect(page).not_to have_content(I18n.t('exercises.editor.score'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it 'contains a button for submitting the exercise' do
|
it 'contains a button for submitting the exercise' do
|
||||||
submission = build(:submission, user: user, exercise: exercise)
|
submission = build(:submission, user: user, exercise: exercise)
|
||||||
allow(submission).to receive(:calculate_score).and_return(scoring_response)
|
allow(submission).to receive(:calculate_score).and_return(scoring_response)
|
||||||
allow(Submission).to receive(:find).and_return(submission)
|
allow(Submission).to receive(:find).and_return(submission)
|
||||||
click_button(I18n.t('exercises.editor.score'))
|
click_button(I18n.t('exercises.editor.score'))
|
||||||
expect(page).not_to have_css('#submit_outdated')
|
expect(page).not_to have_content(I18n.t('exercises.editor.tooltips.exercise_deadline_passed'))
|
||||||
expect(page).to have_css('#submit')
|
expect(page).to have_content(I18n.t('exercises.editor.submit'))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -124,4 +124,41 @@ describe Exercise do
|
|||||||
expect(exercise.duplicate).to be_a(described_class)
|
expect(exercise.duplicate).to be_a(described_class)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#teacher_defined_assessment?' do
|
||||||
|
let(:exercise) { create(:dummy) }
|
||||||
|
|
||||||
|
context 'when no assessment is defined' do
|
||||||
|
it 'returns false' do
|
||||||
|
expect(exercise).not_to be_teacher_defined_assessment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when unit tests are defined' do
|
||||||
|
before { create(:test_file, context: exercise) }
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
|
expect(exercise).to be_teacher_defined_assessment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when linter tests are defined' do
|
||||||
|
before { create(:test_file, context: exercise, role: 'teacher_defined_linter') }
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
|
expect(exercise).to be_teacher_defined_assessment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when unit and linter tests are defined' do
|
||||||
|
before do
|
||||||
|
create(:test_file, context: exercise)
|
||||||
|
create(:test_file, context: exercise, role: 'teacher_defined_linter')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
|
expect(exercise).to be_teacher_defined_assessment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -112,7 +112,7 @@ describe ExercisePolicy do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
%i[implement? submit?].each do |action|
|
%i[implement?].each do |action|
|
||||||
permissions(action) do
|
permissions(action) do
|
||||||
it 'grants access to anyone' do
|
it 'grants access to anyone' do
|
||||||
%i[admin external_user teacher].each do |factory_name|
|
%i[admin external_user teacher].each do |factory_name|
|
||||||
@ -122,6 +122,28 @@ describe ExercisePolicy do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
%i[submit?].each do |action|
|
||||||
|
permissions(action) do
|
||||||
|
context 'when teacher-defined assessments are available' do
|
||||||
|
before { create(:test_file, context: exercise) }
|
||||||
|
|
||||||
|
it 'grants access to anyone' do
|
||||||
|
%i[admin external_user teacher].each do |factory_name|
|
||||||
|
expect(policy).to permit(build(factory_name), exercise)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when teacher-defined assessments are not available' do
|
||||||
|
it 'does not grant access to anyone' do
|
||||||
|
%i[admin external_user teacher].each do |factory_name|
|
||||||
|
expect(policy).not_to permit(build(factory_name), exercise)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe ExercisePolicy::Scope do
|
describe ExercisePolicy::Scope do
|
||||||
describe '#resolve' do
|
describe '#resolve' do
|
||||||
let(:admin) { create(:admin) }
|
let(:admin) { create(:admin) }
|
||||||
|
Reference in New Issue
Block a user