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

Allow instructors to configure an end date until which students can run automated tests #6992

Merged
merged 18 commits into from
Mar 31, 2024
Merged
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
1 change: 1 addition & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Enable the deletion of Grade Entry Forms that have no grades (#6915)
- Fixed login_spec.rb flaky test on GitHub Actions run (#6966)
- Minor improvements in assignment association options (#6989)
- Allow instructors to configure an end date until which students can run automated tests (#6992)
- Gave TAs read-only access to starter file information under assignment settings (#6996)
- Allow inactive groups in the submissions table to be toggled for display (#7000)

Expand Down
23 changes: 23 additions & 0 deletions app/assets/javascripts/Components/autotest_manager.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ class AutotestManager extends React.Component {
enable_test: true,
enable_student_tests: true,
token_start_date: "",
token_end_date: "",
tokens_per_period: 0,
token_period: 0,
non_regenerating_tokens: false,
Expand Down Expand Up @@ -226,6 +227,11 @@ class AutotestManager extends React.Component {
this.setState({token_start_date: newDate}, () => this.toggleFormChanged(true));
};

handleTokenEndDateChange = selectedDates => {
const newDate = selectedDates[0] || "";
this.setState({token_end_date: newDate}, () => this.toggleFormChanged(true));
};

handleTokensPerPeriodChange = event => {
this.setState({tokens_per_period: event.target.value}, () => this.toggleFormChanged(true));
};
Expand All @@ -243,6 +249,7 @@ class AutotestManager extends React.Component {
enable_test: this.state.enable_test,
enable_student_tests: this.state.enable_student_tests,
token_start_date: this.state.token_start_date,
token_end_date: this.state.token_end_date,
tokens_per_period: this.state.tokens_per_period,
token_period: this.state.token_period,
non_regenerating_tokens: this.state.non_regenerating_tokens,
Expand Down Expand Up @@ -366,6 +373,22 @@ class AutotestManager extends React.Component {
plugins: [labelPlugin()], // Ensure id is applied to visible input
}}
/>
<label className="inline_label" htmlFor="token_end_date">
{I18n.t("activerecord.attributes.assignment.token_end_date")}
</label>
<Flatpickr
id="token_end_date"
value={this.state.token_end_date}
onChange={this.handleTokenEndDateChange}
placeholder={I18n.t("automated_tests.use_assignment_due_date")}
options={{
david-yz-liu marked this conversation as resolved.
Show resolved Hide resolved
altInput: true,
altFormat: I18n.t("time.format_string.flatpickr"),
dateFormat: "Z",
disabled: !this.state.enable_test || !this.state.enable_student_tests,
plugins: [labelPlugin()], // Ensure id is applied to visible input
}}
/>
<label className="inline_label" htmlFor="token_period">
{I18n.t("activerecord.attributes.assignment.token_period")}
</label>
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/assignments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class AssignmentsController < MainApiController
:assign_graders_to_criteria, :enable_test, :enable_student_tests, :allow_remarks,
:display_grader_names_to_students, :group_name_autogenerated,
:repository_folder, :is_hidden, :vcs_submit, :token_period,
:non_regenerating_tokens, :unlimited_tokens, :token_start_date, :has_peer_review,
:non_regenerating_tokens, :unlimited_tokens, :token_start_date, :token_end_date, :has_peer_review,
:starter_file_type, :default_starter_file_group_id].freeze

# Returns a list of assignments and their attributes
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/automated_tests_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def implicit_authorization_target
private

def required_params
[:enable_test, :enable_student_tests, :tokens_per_period, :token_period, :token_start_date,
[:enable_test, :enable_student_tests, :tokens_per_period, :token_period, :token_start_date, :token_end_date,
:non_regenerating_tokens, :unlimited_tokens]
end

Expand Down
4 changes: 4 additions & 0 deletions app/policies/assignment_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def tokens_released?
!record.token_start_date.nil? && Time.current >= record.token_start_date
end

def before_token_end_date?
Time.current <= record.token_end_date
end

def create_group?
!check?(:collection_date_passed?) &&
check?(:students_form_groups?) &&
Expand Down
10 changes: 8 additions & 2 deletions app/policies/student_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ def run_tests?
unless grouping.nil?
allowed &&= check?(:member?, grouping) &&
check?(:not_in_progress?, grouping) &&
check?(:tokens_available?, grouping) &&
check?(:before_due_date?, grouping)
check?(:tokens_available?, grouping)
end
unless grouping.nil? || assignment.nil?
if assignment.token_end_date.present?
allowed &&= check?(:before_token_end_date?, assignment)
else
allowed &&= check?(:before_due_date?, grouping)
end
end
allowed &&= check?(:before_release?, submission) unless submission.nil?
allowed
Expand Down
5 changes: 5 additions & 0 deletions app/views/automated_tests/student_interface.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
<%= l(@assignment.token_start_date) %>
</p>

<p>
<strong><%= Assignment.human_attribute_name(:token_end_date) %>:</strong>
<%= l(@assignment.token_end_date) %>
</p>

<% unless @assignment.unlimited_tokens || @assignment.non_regenerating_tokens %>
<p>
<strong><%= Assignment.human_attribute_name(:token_period) %>:</strong>
Expand Down
1 change: 1 addition & 0 deletions config/locales/models/assignments/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ en:
short_identifier: Short Identifier
start_time: Start time
student_form_groups: Students may form their own groups
token_end_date: Tokens available until
token_period: Tokens regenerate after
token_start_date: Tokens available on
tokens_per_period: Tokens per group
Expand Down
1 change: 1 addition & 0 deletions config/locales/policies/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ en:
view_ta_subtabs?: You are not authorized to perform this action.
assignment:
autogenerate_group_name?: This assignment does automatically generate group names.
before_token_end_date?: Tokens are no longer available for this assignment.
collection_date_passed?: 'Could not create group: the due date for this assignment has passed.'
create_group?: You cannot form a group at this time.
index?: You are not authorized to perform this action.
Expand Down
1 change: 1 addition & 0 deletions config/locales/views/automated_tests/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,4 @@ en:
tests_run: Tests have been run for this assignment. Please re-run tests once the settings have been updated.
timeout: Timeout (s)
title: Automated Testing
use_assignment_due_date: Leave blank to use assignment due date
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddTokenEndDateToAssignmentProperties < ActiveRecord::Migration[7.1]
def change
add_column :assignment_properties, :token_end_date, :datetime
end
end
4 changes: 3 additions & 1 deletion db/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,8 @@ CREATE TABLE public.assignment_properties (
url_submit boolean DEFAULT false NOT NULL,
autotest_settings json,
api_submit boolean DEFAULT false NOT NULL,
release_with_urls boolean DEFAULT false NOT NULL
release_with_urls boolean DEFAULT false NOT NULL,
token_end_date timestamp(6) without time zone
);


Expand Down Expand Up @@ -4375,6 +4376,7 @@ ALTER TABLE ONLY public.submission_files
SET search_path TO "$user", public;

INSERT INTO "schema_migrations" (version) VALUES
('20240313191809'),
('20230713153536'),
('20230303030615'),
('20230109190029'),
Expand Down
1 change: 1 addition & 0 deletions lib/tasks/autotest.rake
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class AutotestSetup
repository_folder: @assg_short_id,
enable_test: true,
token_start_date: Time.current,
token_end_date: nil,
token_period: 1,
enable_student_tests: true,
unlimited_tokens: true
Expand Down
9 changes: 9 additions & 0 deletions spec/policies/assignment_policy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@
failed 'when token start date is nil'
end

describe_rule :before_token_end_date? do
succeed 'when current date is before the token end date' do
let(:assignment) { create :assignment, assignment_properties_attributes: { token_end_date: 1.hour.from_now } }
end
failed 'when current date is after the token end date' do
let(:assignment) { create :assignment, assignment_properties_attributes: { token_end_date: 1.hour.ago } }
end
end

describe_rule :create_group? do
let(:role) { create :student }
let(:assignment) { create :assignment, assignment_properties_attributes: properties }
Expand Down
34 changes: 30 additions & 4 deletions spec/policies/student_policy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,41 @@
failed 'when there are no tokens available' do
let(:grouping) { create :grouping_with_inviter, inviter: role, test_tokens: 0 }
end
failed 'when the due date has passed' do
let(:assignment) { create :assignment, due_date: 1.day.ago }
let(:grouping) { create :grouping_with_inviter, assignment: assignment, inviter: role, test_tokens: 1 }
end
end
failed 'when the role is not a member' do
let(:grouping) { create :grouping_with_inviter, test_tokens: 1 }
end
end
context 'authorized with a grouping and an assignment' do
let(:context) { { role: role, grouping: grouping, assignment: assignment, real_user: role.user } }
let(:assignment) do
create :assignment, due_date: assign_due_date, assignment_properties_attributes: assignment_attrs
end
failed 'when the due date has passed and token end date is nil' do
let(:assign_due_date) { 1.hour.ago }
let(:assignment_attrs) do
{ token_start_date: 2.hours.ago, token_end_date: nil,
enable_student_tests: true, unlimited_tokens: true }
end
let(:grouping) { create :grouping_with_inviter, assignment: assignment, inviter: role }
end
succeed 'when the token end date has not passed' do
let(:assign_due_date) { 2.hours.from_now }
let(:assignment_attrs) do
{ token_start_date: 2.hours.ago, token_end_date: 1.hour.from_now,
enable_student_tests: true, unlimited_tokens: true }
end
let(:grouping) { create :grouping_with_inviter, assignment: assignment, inviter: role }
end
failed 'when the token end date has passed' do
let(:assign_due_date) { 2.hours.from_now }
let(:assignment_attrs) do
{ token_start_date: 2.hours.ago, token_end_date: 1.hour.ago,
enable_student_tests: true, unlimited_tokens: true }
end
let(:grouping) { create :grouping_with_inviter, assignment: assignment, inviter: role }
end
end
context 'authorized with a submission' do
let(:context) { { role: role, submission: result.submission, real_user: role.user } }
failed 'with a released result' do
Expand Down