From 3ae95f8a14fccbd231f463b821bb5ee7fcac2413 Mon Sep 17 00:00:00 2001 From: Daniel Maddern Date: Tue, 5 Dec 2023 12:24:47 +1100 Subject: [PATCH 001/124] new:numbas feature backend intital commit first commit containing endpoints and DB changes new faeture --- app/api/api_root.rb | 5 + app/api/entities/numbas_entity.rb | 7 ++ app/api/entities/test_attempt_entity.rb | 8 ++ app/api/numbas_api.rb | 79 ++++++++++++ app/api/test_attempts_api.rb | 159 ++++++++++++++++++++++++ 5 files changed, 258 insertions(+) create mode 100644 app/api/entities/numbas_entity.rb create mode 100644 app/api/entities/test_attempt_entity.rb create mode 100644 app/api/numbas_api.rb create mode 100644 app/api/test_attempts_api.rb diff --git a/app/api/api_root.rb b/app/api/api_root.rb index bde5f0236..cdf6e6404 100644 --- a/app/api/api_root.rb +++ b/app/api/api_root.rb @@ -76,6 +76,9 @@ class ApiRoot < Grape::API mount Tii::TiiGroupAttachmentApi mount Tii::TiiActionApi + + mount NumbasApi + mount TestAttemptsApi mount CampusesPublicApi mount CampusesAuthenticatedApi mount TutorialsApi @@ -122,6 +125,8 @@ class ApiRoot < Grape::API AuthenticationHelpers.add_auth_to UnitRolesApi AuthenticationHelpers.add_auth_to UnitsApi AuthenticationHelpers.add_auth_to WebcalApi + AuthenticationHelpers.add_auth_to NumbasApi + AuthenticationHelpers.add_auth_to TestAttemptsApi add_swagger_documentation \ base_path: nil, diff --git a/app/api/entities/numbas_entity.rb b/app/api/entities/numbas_entity.rb new file mode 100644 index 000000000..4235ebb3f --- /dev/null +++ b/app/api/entities/numbas_entity.rb @@ -0,0 +1,7 @@ + +module Entities + class NumbasEntity < Grape::Entity + expose :file_content, documentation: { type: 'string', desc: 'File content' } + expose :content_type, documentation: { type: 'string', desc: 'Content type' } + end +end diff --git a/app/api/entities/test_attempt_entity.rb b/app/api/entities/test_attempt_entity.rb new file mode 100644 index 000000000..1b3e35968 --- /dev/null +++ b/app/api/entities/test_attempt_entity.rb @@ -0,0 +1,8 @@ + +module Entities + class TestAttemptEntity < Grape::Entity + expose :id, :name, :attempt_number, :pass_status, :exam_data, :completed, :cmi_entry + expose :task_id, as: :associated_task_id + expose :exam_result, :attempted_at + end +end diff --git a/app/api/numbas_api.rb b/app/api/numbas_api.rb new file mode 100644 index 000000000..798ba28ef --- /dev/null +++ b/app/api/numbas_api.rb @@ -0,0 +1,79 @@ +require 'grape' +require 'zip' +require 'mime/types' +class NumbasApi < Grape::API + # Include the AuthenticationHelpers for authentication functionality + helpers AuthenticationHelpers + + helpers do + # Method to stream a file from a zip archive at the specified path + # @param zip_path [String] the path to the zip archive + # @param file_path [String] the path of the file within the zip archive + def stream_file_from_zip(zip_path, file_path) + file_stream = nil + + # Get an input stream for the requested file within the ZIP archive + Zip::File.open(zip_path) do |zip_file| + zip_file.each do |entry| + logger.debug "Entry name: #{entry.name}" + if entry.name == file_path + file_stream = entry.get_input_stream + break + end + end + end + + # If the file was not found in the ZIP archive, return a 404 response + unless file_stream + error!({ error: 'File not found' }, 404) + end + + # Set the content type based on the file extension + content_type = MIME::Types.type_for(file_path).first.content_type + logger.debug "Content type: #{content_type}" + + # Set the content type header + header 'Content-Type', content_type + + # Set cache control header to prevent caching + header 'Cache-Control', 'no-cache, no-store, must-revalidate' + + # Set the body to the contents of the file_stream and return the response + body file_stream.read + end + end + + # Define the API namespace + namespace :numbas_api do + # Use Grape's before hook to check authentication before processing any route + before do + authenticated? + end + + get '/index.html' do + env['api.format'] = :txt + zip_path = FileHelper.get_numbas_test_path(params[:unit_code], params[:task_definition_id], 'numbas_test.zip') + stream_file_from_zip(zip_path, 'index.html') + end + + get '*file_path' do + env['api.format'] = :txt + zip_path = FileHelper.get_numbas_test_path(params[:unit_code], params[:task_definition_id], 'numbas_test.zip') + requested_file_path = "#{params[:file_path]}.#{params[:format]}" + stream_file_from_zip(zip_path, requested_file_path) + end + + post '/uploadNumbasTest' do + # Ensure the uploaded file is present + unless params[:file] && params[:file][:tempfile] + error!({ error: 'File upload is missing' }, 400) + end + + # Use the FileHelper to save the uploaded test + save_path = FileHelper.get_numbas_test_path(params[:unit_code], params[:task_definition_id], 'numbas_test.zip') + File.binwrite(save_path, params[:file][:tempfile].read) + + { success: true, message: 'File uploaded successfully' } + end + end +end diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb new file mode 100644 index 000000000..96816c2b4 --- /dev/null +++ b/app/api/test_attempts_api.rb @@ -0,0 +1,159 @@ +require 'grape' + +class TestAttemptsApi < Grape::API + format :json + + # Assigning AuthenticationHelpers + helpers AuthenticationHelpers + + # Handle common exceptions + rescue_from :all do |e| + error!({ error: e.message }, 500) + end + + # Specific exception handler for record not found + rescue_from ActiveRecord::RecordNotFound do |e| + error!({ error: e.message }, 404) + end + + # Handling validation errors from Grape + rescue_from Grape::Exceptions::ValidationErrors do |e| + error!({ errors: e.full_messages }, 400) + end + + # Define the TestAttemptEntity + class TestAttemptEntity < Grape::Entity + expose :id, :name, :attempt_number, :pass_status, :exam_data, :completed, :cmi_entry + expose :task_id, as: :associated_task_id + expose :exam_result, :attempted_at + end + + # Fetch all test results + desc 'Get all test results' + get do + tests = TestAttempt.order(id: :desc) + present tests, with: TestAttemptEntity + end + + # Get latest test or create a new one based on completion status + desc 'Get latest test or create a new one based on completion status' + get 'latest' do + test = TestAttempt.order(id: :desc).first + + if test.nil? + test = TestAttempt.create!( + name: "Default Test", + attempt_number: 1, + pass_status: false, + exam_data: nil, + completed: false, + cmi_entry: 'ab-initio', + task_id: params[:task_id] + ) + elsif test.completed + test = TestAttempt.create!( + name: "Default Test", + attempt_number: test.attempt_number + 1, + pass_status: false, + exam_data: nil, + completed: false, + cmi_entry: 'ab-initio', + task_id: params[:task_id] + ) + else + test.update!(cmi_entry: 'resume') + end + + present test, with: TestAttemptEntity + end + + # Fetch the latest completed test result + desc 'Get the latest completed test result' + get 'completed-latest' do + test = TestAttempt.where(completed: true).order(id: :desc).first + + if test.nil? + error!({ message: 'No completed tests found' }, 404) + else + present test, with: TestAttemptEntity + end + end + + # Fetch a specific test result by ID + desc 'Get a specific test result' + params do + requires :id, type: String, desc: 'ID of the test' + end + get ':id' do + present TestAttempt.find(params[:id]), with: TestAttemptEntity + end + + # Create a new test result entry + desc 'Create a new test result' + params do + requires :task_id, type: Integer, desc: 'ID of the associated task' + requires :name, type: String, desc: 'Name of the test' + requires :attempt_number, type: Integer, desc: 'Number of attempts' + requires :pass_status, type: Boolean, desc: 'Passing status' + optional :exam_data, type: String, desc: 'Data related to the exam' + requires :completed, type: Boolean, desc: 'Completion status' + optional :cmi_entry, type: String, desc: 'CMI Entry', default: "ab-initio" + optional :exam_result, type: String, desc: 'Result of the exam' + optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' + end + post do + test = TestAttempt.create!(declared(params)) + present test, with: TestAttemptEntity + end + + # Update the details of a specific test result + desc 'Update a test result' + params do + optional :name, type: String, desc: 'Name of the test' + optional :attempt_number, type: Integer, desc: 'Number of attempts' + optional :pass_status, type: Boolean, desc: 'Passing status' + optional :exam_data, type: String, desc: 'Data related to the exam' + optional :completed, type: Boolean, desc: 'Completion status' + optional :cmi_entry, type: String, desc: 'CMI Entry' + optional :task_id, type: Integer, desc: 'ID of the associated task' + end + put ':id' do + test = TestAttempt.find(params[:id]) + test.update!(declared(params, include_missing: false)) + present test, with: TestAttemptEntity + end + + # Delete a specific test result by ID + desc 'Delete a test result' + params do + requires :id, type: String, desc: 'ID of the test' + end + delete ':id' do + TestAttempt.find(params[:id]).destroy! + end + + # Update the exam_data of a specific test result + desc 'Update exam data for a test result' + params do + requires :id, type: String, desc: 'ID of the test' + end + put ':id/exam_data' do + test = TestAttempt.find_by(id: params[:id]) + + error!('Test not found', 404) unless test + + # Treat the entire params as the data to be saved + exam_data = params.to_json + + begin + JSON.parse(exam_data) + test.update!(exam_data: exam_data) + { message: 'Exam data updated successfully', test: test } + rescue JSON::ParserError + error!('Invalid JSON provided', 400) + rescue StandardError => e + error!(e.message, 500) + end + end + +end From fa2de362e11fc1c23c2b8cb428aedc475f479aa5 Mon Sep 17 00:00:00 2001 From: Daniel Maddern Date: Tue, 5 Dec 2023 12:25:03 +1100 Subject: [PATCH 002/124] new:numbas feature backend intital commit first commit containing endpoints and DB changes new faeture --- app/models/test_attempt.rb | 36 +++++++++++++++++++ .../20231205011842_create_test_attempts.rb | 16 +++++++++ .../20231205011958_add_fields_to_task_def.rb | 19 ++++++++++ db/schema.rb | 20 +++++++++++ 4 files changed, 91 insertions(+) create mode 100644 app/models/test_attempt.rb create mode 100644 db/migrate/20231205011842_create_test_attempts.rb create mode 100644 db/migrate/20231205011958_add_fields_to_task_def.rb diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb new file mode 100644 index 000000000..9391144b1 --- /dev/null +++ b/app/models/test_attempt.rb @@ -0,0 +1,36 @@ +class TestAttempt < ApplicationRecord + include ApplicationHelper + include LogHelper + include GradeHelper + + belongs_to :task + + def self.permissions + student_role_permissions = [ + :create, + :view_own, + :delete_own + ] + + tutor_role_permissions = [ + :create, + :view_own, + :delete_own + ] + + convenor_role_permissions = [ + :create, + :view_own, + :delete_own + ] + + nil_role_permissions = [] + + { + student: student_role_permissions, + tutor: tutor_role_permissions, + convenor: convenor_role_permissions, + nil: nil_role_permissions + } + end +end diff --git a/db/migrate/20231205011842_create_test_attempts.rb b/db/migrate/20231205011842_create_test_attempts.rb new file mode 100644 index 000000000..3828d1154 --- /dev/null +++ b/db/migrate/20231205011842_create_test_attempts.rb @@ -0,0 +1,16 @@ +class CreateTestAttempts < ActiveRecord::Migration[7.0] + def change + create_table :test_attempts do |t| + t.references :task, foreign_key: true + t.string :name + t.integer :attempt_number, default: 1, null: false + t.boolean :pass_status + t.text :exam_data + t.boolean :completed, default: false + t.datetime :attempted_at + t.string :cmi_entry, default: "ab-initio" + t.string :exam_result + t.timestamps + end + end +end diff --git a/db/migrate/20231205011958_add_fields_to_task_def.rb b/db/migrate/20231205011958_add_fields_to_task_def.rb new file mode 100644 index 000000000..35d9bb7cc --- /dev/null +++ b/db/migrate/20231205011958_add_fields_to_task_def.rb @@ -0,0 +1,19 @@ +class AddFieldsToTaskDef < ActiveRecord::Migration[7.0] + def change + change_table :task_definitions do |t| + t.boolean :has_test, default: false + t.boolean :restrict_attempts, default: false + t.integer :delay_restart_minutes + t.boolean :retake_on_resubmit, default: false + end + end + + def down + change_table :task_definitions do |t| + t.remove :has_test + t.remove :restrict_attempts + t.remove :delay_restart_minutes + t.remove :retake_on_resubmit + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 6daa71ebf..29c978802 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -250,6 +250,10 @@ t.bigint "overseer_image_id" t.string "tii_group_id" t.string "moss_language" + t.boolean "has_test", default: false + t.boolean "restrict_attempts", default: false + t.integer "delay_restart_minutes" + t.boolean "retake_on_resubmit", default: false t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" t.index ["overseer_image_id"], name: "index_task_definitions_on_overseer_image_id" t.index ["tutorial_stream_id"], name: "index_task_definitions_on_tutorial_stream_id" @@ -344,6 +348,21 @@ t.index ["period", "year"], name: "index_teaching_periods_on_period_and_year", unique: true end + create_table "test_attempts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| + t.bigint "task_id" + t.string "name" + t.integer "attempt_number", default: 1, null: false + t.boolean "pass_status" + t.text "exam_data" + t.boolean "completed", default: false + t.datetime "attempted_at" + t.string "cmi_entry", default: "ab-initio" + t.string "exam_result" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["task_id"], name: "index_test_attempts_on_task_id" + end + create_table "tii_actions", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.string "entity_type" t.bigint "entity_id" @@ -531,4 +550,5 @@ t.index ["user_id"], name: "index_webcals_on_user_id", unique: true end + add_foreign_key "test_attempts", "tasks" end From f035c44943cbbb0e755b683f1782c69f09d6daca Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 12 Mar 2024 08:49:01 +1100 Subject: [PATCH 003/124] fix test_attempts api paths --- app/api/test_attempts_api.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 96816c2b4..05b3d5615 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -37,7 +37,7 @@ class TestAttemptEntity < Grape::Entity # Get latest test or create a new one based on completion status desc 'Get latest test or create a new one based on completion status' - get 'latest' do + get '/test_attempts/latest' do test = TestAttempt.order(id: :desc).first if test.nil? @@ -69,7 +69,7 @@ class TestAttemptEntity < Grape::Entity # Fetch the latest completed test result desc 'Get the latest completed test result' - get 'completed-latest' do + get '/test_attempts/completed-latest' do test = TestAttempt.where(completed: true).order(id: :desc).first if test.nil? @@ -84,7 +84,7 @@ class TestAttemptEntity < Grape::Entity params do requires :id, type: String, desc: 'ID of the test' end - get ':id' do + get '/test_attempts/:id' do present TestAttempt.find(params[:id]), with: TestAttemptEntity end @@ -117,7 +117,7 @@ class TestAttemptEntity < Grape::Entity optional :cmi_entry, type: String, desc: 'CMI Entry' optional :task_id, type: Integer, desc: 'ID of the associated task' end - put ':id' do + put '/test_attempts/:id' do test = TestAttempt.find(params[:id]) test.update!(declared(params, include_missing: false)) present test, with: TestAttemptEntity @@ -128,7 +128,7 @@ class TestAttemptEntity < Grape::Entity params do requires :id, type: String, desc: 'ID of the test' end - delete ':id' do + delete '/test_attempts/:id' do TestAttempt.find(params[:id]).destroy! end @@ -137,7 +137,7 @@ class TestAttemptEntity < Grape::Entity params do requires :id, type: String, desc: 'ID of the test' end - put ':id/exam_data' do + put '/test_attempts/:id/exam_data' do test = TestAttempt.find_by(id: params[:id]) error!('Test not found', 404) unless test From 4165b106e3c437273a8c487f3f247db47e4492d1 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Wed, 13 Mar 2024 15:38:01 +1100 Subject: [PATCH 004/124] Enforce authentication for the test_attempts api --- app/api/test_attempts_api.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 05b3d5615..c9a78a171 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -3,6 +3,11 @@ class TestAttemptsApi < Grape::API format :json + # Enforce authentication + before do + authenticated? + end + # Assigning AuthenticationHelpers helpers AuthenticationHelpers From 55fcbc571fa29502e484ef8a6ab949cab55887d4 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Wed, 13 Mar 2024 21:20:57 +1100 Subject: [PATCH 005/124] Modify the api to fetch test attempts with task id --- app/api/test_attempts_api.rb | 38 ++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index c9a78a171..803f14dc6 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -41,9 +41,24 @@ class TestAttemptEntity < Grape::Entity end # Get latest test or create a new one based on completion status - desc 'Get latest test or create a new one based on completion status' + desc 'Get latest test attempt for a specific task or create a new one based on completion status' + params do + requires :task_id, type: Integer, desc: 'Task ID to fetch test attempts for' + end get '/test_attempts/latest' do - test = TestAttempt.order(id: :desc).first + # Ensure task exists + task = Task.find(params[:task_id]) + if task.nil? + error!({ message: 'Task ID is invalid' }, 404) + return + else + test_attempts = TestAttempt.find_by(task_id: :task_id) + end + + # Take the latest test attempt if there are any for this task + unless test_attempts.nil? + test = test_attempts.order(id: :desc).first + end if test.nil? test = TestAttempt.create!( @@ -74,11 +89,26 @@ class TestAttemptEntity < Grape::Entity # Fetch the latest completed test result desc 'Get the latest completed test result' + params do + requires :task_id, type: Integer, desc: 'Task ID to fetch completed test attempt for' + end get '/test_attempts/completed-latest' do - test = TestAttempt.where(completed: true).order(id: :desc).first + # Ensure task exists + task = Task.find(params[:task_id]) + if task.nil? + error!({ message: 'Task ID is invalid' }, 404) + return + else + test_attempts = TestAttempt.find_by(task_id: :task_id) + end + + # Take the latest completed test attempt if there are any for this task + unless test_attempts.nil? + test = test_attempts.where(completed: true).order(id: :desc).first + end if test.nil? - error!({ message: 'No completed tests found' }, 404) + error!({ message: 'No completed tests found for this task' }, 404) else present test, with: TestAttemptEntity end From 061f49f137e5973d0fec730a65d8a6c47dfe51c1 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Thu, 21 Mar 2024 10:52:32 +1100 Subject: [PATCH 006/124] Numbas data management features - Implement methods in task_definition model for numbas data management - Implement routes in task_definition_api for numbas data managemnt - Remove unused upload API in numbas_api --- app/api/numbas_api.rb | 13 ------ app/api/task_definitions_api.rb | 75 +++++++++++++++++++++++++++++++++ app/models/task_definition.rb | 34 +++++++++++++++ 3 files changed, 109 insertions(+), 13 deletions(-) diff --git a/app/api/numbas_api.rb b/app/api/numbas_api.rb index 798ba28ef..cb81ae944 100644 --- a/app/api/numbas_api.rb +++ b/app/api/numbas_api.rb @@ -62,18 +62,5 @@ def stream_file_from_zip(zip_path, file_path) requested_file_path = "#{params[:file_path]}.#{params[:format]}" stream_file_from_zip(zip_path, requested_file_path) end - - post '/uploadNumbasTest' do - # Ensure the uploaded file is present - unless params[:file] && params[:file][:tempfile] - error!({ error: 'File upload is missing' }, 400) - end - - # Use the FileHelper to save the uploaded test - save_path = FileHelper.get_numbas_test_path(params[:unit_code], params[:task_definition_id], 'numbas_test.zip') - File.binwrite(save_path, params[:file][:tempfile].read) - - { success: true, message: 'File uploaded successfully' } - end end end diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index 03536c9ef..e33b52772 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -614,4 +614,79 @@ class TaskDefinitionsApi < Grape::API stream_file path end + + desc 'Upload the Numbas SCORM-2004 container (zip file) for a task' + params do + requires :unit_id, type: Integer, desc: 'The related unit' + requires :task_def_id, type: Integer, desc: 'The related task definition' + requires :file, type: File, desc: 'The Numbas data container' + end + post '/units/:unit_id/task_definitions/:task_def_id/numbas_data' do + unit = Unit.find(params[:unit_id]) + + unless authorise? current_user, unit, :add_task_def + error!({ error: 'Not authorised to upload numbas test for the unit' }, 403) + end + + task_def = unit.task_definitions.find(params[:task_def_id]) + + unless params[:file].present? + error!({ error: "No file uploaded" }, 403) + end + + file_path = params[:file][:tempfile].path + + check_mime_against_list! file_path, 'zip', ['application/zip', 'multipart/x-gzip', 'multipart/x-zip', 'application/x-gzip', 'application/octet-stream'] + + # Actually import... + task_def.add_numbas_data(file_path) + true + end + + desc 'Download the Numbas test data' + params do + requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' + requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' + end + get '/units/:unit_id/task_definitions/:task_def_id/numbas_data' do + unit = Unit.find(params[:unit_id]) + task_def = unit.task_definitions.find(params[:task_def_id]) + + unless authorise? current_user, unit, :get_unit + error!({ error: 'Not authorised to download task details of unit' }, 403) + end + + if task_def.has_numbas_data? + path = task_def.task_numbas_data + content_type 'application/octet-stream' + header['Content-Disposition'] = "attachment; filename=#{task_def.abbreviation}-numbas.zip" + else + path = Rails.root.join('public', 'resources', 'FileNotFound.pdf') + content_type 'application/pdf' + header['Content-Disposition'] = 'attachment; filename=FileNotFound.pdf' + end + header['Access-Control-Expose-Headers'] = 'Content-Disposition' + + env['api.format'] = :binary + File.read(path) + end + + desc 'Remove the Numbas test data for a given task' + params do + requires :unit_id, type: Integer, desc: 'The related unit' + requires :task_def_id, type: Integer, desc: 'The related task definition' + end + delete '/units/:unit_id/task_definitions/:task_def_id/numbas_data' do + unit = Unit.find(params[:unit_id]) + + unless authorise? current_user, unit, :add_task_def + error!({ error: 'Not authorised to remove task numbas data of unit' }, 403) + end + + task_def = unit.task_definitions.find(params[:task_def_id]) + + # Actually remove... + task_def.remove_numbas_data + true + end end diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 7e78bd2a7..f0fcfa749 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -384,6 +384,10 @@ def has_task_sheet? File.exist? task_sheet end + def has_numbas_data? + File.exist? task_numbas_data + end + def is_graded? is_graded end @@ -436,6 +440,16 @@ def remove_task_assessment_resources() end end + def add_numbas_data(file) + FileUtils.mv file, task_numbas_data + end + + def remove_numbas_data() + if has_numbas_data? + FileUtils.rm task_numbas_data + end + end + # Get the path to the task sheet - using the current abbreviation def task_sheet task_sheet_with_abbreviation(abbreviation) @@ -449,6 +463,10 @@ def task_assessment_resources task_assessment_resources_with_abbreviation(abbreviation) end + def task_numbas_data + task_numbas_data_with_abbreviation(abbreviation) + end + def related_tasks_with_files(consolidate_groups = true) tasks_with_files = tasks.select(&:has_pdf) @@ -537,4 +555,20 @@ def task_assessment_resources_with_abbreviation(abbr) result_with_sanitised_file end end + + # Calculate the path to the numbas containzer zip file using the provided abbreviation + # This allows the path to be calculated on abbreviation change to allow files to + # be moved + def task_numbas_data_with_abbreviation(abbr) + task_path = FileHelper.task_file_dir_for_unit unit, create = true + + result_with_sanitised_path = "#{task_path}#{FileHelper.sanitized_path(abbr)}.numbas.zip" + result_with_sanitised_file = "#{task_path}#{FileHelper.sanitized_filename(abbr)}.numbas.zip" + + if File.exist? result_with_sanitised_path + result_with_sanitised_path + else + result_with_sanitised_file + end + end end From d53610a3f4b0c8077aea34cbfa2924e301914e1f Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Fri, 22 Mar 2024 13:38:53 +1100 Subject: [PATCH 007/124] feat: add Numbas config options to task def backend --- app/api/entities/task_definition_entity.rb | 6 ++ app/api/task_definitions_api.rb | 92 +++++++++++-------- app/models/task_definition.rb | 75 +++++++++++---- .../20231205011958_add_fields_to_task_def.rb | 19 ---- ...021829_modify_numbas_fields_in_task_def.rb | 21 +++++ db/schema.rb | 9 +- 6 files changed, 145 insertions(+), 77 deletions(-) delete mode 100644 db/migrate/20231205011958_add_fields_to_task_def.rb create mode 100644 db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index 94ba180d4..3fdcd3b65 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -39,6 +39,12 @@ def staff?(my_role) expose :has_task_sheet?, as: :has_task_sheet expose :has_task_resources?, as: :has_task_resources expose :has_task_assessment_resources?, as: :has_task_assessment_resources, if: ->(unit, options) { staff?(options[:my_role]) } + expose :has_numbas_data?, as: :has_numbas_data + expose :has_enabled_numbas_test, if: ->(unit, options) { staff?(options[:my_role]) } + expose :has_unlimited_retries_for_numbas, if: ->(unit, options) { staff?(options[:my_role]) } + expose :has_time_delay_for_numbas, if: ->(unit, options) { staff?(options[:my_role]) } + expose :is_numbas_restricted_to_1_attempt, if: ->(unit, options) { staff?(options[:my_role]) } + expose :numbas_time_delay, if: ->(unit, options) { staff?(options[:my_role]) } expose :is_graded expose :max_quality_pts expose :overseer_image_id, if: ->(unit, options) { staff?(options[:my_role]) } diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index e33b52772..b75a83224 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -15,24 +15,29 @@ class TaskDefinitionsApi < Grape::API desc 'Add a new task definition to the given unit' params do requires :task_def, type: Hash do - optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of tutorial stream' - requires :name, type: String, desc: 'The name of this task def' - requires :description, type: String, desc: 'The description of this task def' - requires :weighting, type: Integer, desc: 'The weighting of this task' - requires :target_grade, type: Integer, desc: 'Minimum grade for task' - optional :group_set_id, type: Integer, desc: 'Related group set' - requires :start_date, type: Date, desc: 'The date when the task should be started' - requires :target_date, type: Date, desc: 'The date when the task is due' - optional :due_date, type: Date, desc: 'The deadline date' - requires :abbreviation, type: String, desc: 'The abbreviation of the task' - requires :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' - optional :upload_requirements, type: String, desc: 'Task file upload requirements' - requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' - requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' - optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' - optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image for overseer' - optional :moss_language, type: String, desc: 'The language to use for code similarity checks' + optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of tutorial stream' + requires :name, type: String, desc: 'The name of this task def' + requires :description, type: String, desc: 'The description of this task def' + requires :weighting, type: Integer, desc: 'The weighting of this task' + requires :target_grade, type: Integer, desc: 'Minimum grade for task' + optional :group_set_id, type: Integer, desc: 'Related group set' + requires :start_date, type: Date, desc: 'The date when the task should be started' + requires :target_date, type: Date, desc: 'The date when the task is due' + optional :due_date, type: Date, desc: 'The deadline date' + requires :abbreviation, type: String, desc: 'The abbreviation of the task' + requires :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' + optional :upload_requirements, type: String, desc: 'Task file upload requirements' + requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' + requires :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' + requires :has_unlimited_retries_for_numbas, type: Boolean, desc: 'Whether or not the Numbas test can be attempted unlimited times' + requires :has_time_delay_for_numbas, type: Boolean, desc: 'Whether or not there is a time delay between Numbas test attempts' + requires :is_numbas_restricted_to_1_attempt, type: Boolean, desc: 'Whether or not the Numbas test is restricted to 1 attempt' + requires :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' + requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' + requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' + optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' + optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image for overseer' + optional :moss_language, type: String, desc: 'The language to use for code similarity checks' end end post '/units/:unit_id/task_definitions/' do @@ -57,6 +62,11 @@ class TaskDefinitionsApi < Grape::API :abbreviation, :restrict_status_updates, :plagiarism_warn_pct, + :has_enabled_numbas_test, + :has_unlimited_retries_for_numbas, + :has_time_delay_for_numbas, + :is_numbas_restricted_to_1_attempt, + :numbas_time_delay, :is_graded, :max_quality_pts, :assessment_enabled, @@ -93,24 +103,29 @@ class TaskDefinitionsApi < Grape::API params do requires :id, type: Integer, desc: 'The task id to edit' requires :task_def, type: Hash do - optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of the tutorial stream' - optional :name, type: String, desc: 'The name of this task def' - optional :description, type: String, desc: 'The description of this task def' - optional :weighting, type: Integer, desc: 'The weighting of this task' - optional :target_grade, type: Integer, desc: 'Target grade for task' - optional :group_set_id, type: Integer, desc: 'Related group set' - optional :start_date, type: Date, desc: 'The date when the task should be started' - optional :target_date, type: Date, desc: 'The date when the task is due' - optional :due_date, type: Date, desc: 'The deadline date' - optional :abbreviation, type: String, desc: 'The abbreviation of the task' - optional :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' - optional :upload_requirements, type: String, desc: 'Task file upload requirements' - optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' - optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' - optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' - optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image name for overseer' - optional :moss_language, type: String, desc: 'The language to use for code similarity checks' + optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of the tutorial stream' + optional :name, type: String, desc: 'The name of this task def' + optional :description, type: String, desc: 'The description of this task def' + optional :weighting, type: Integer, desc: 'The weighting of this task' + optional :target_grade, type: Integer, desc: 'Target grade for task' + optional :group_set_id, type: Integer, desc: 'Related group set' + optional :start_date, type: Date, desc: 'The date when the task should be started' + optional :target_date, type: Date, desc: 'The date when the task is due' + optional :due_date, type: Date, desc: 'The deadline date' + optional :abbreviation, type: String, desc: 'The abbreviation of the task' + optional :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' + optional :upload_requirements, type: String, desc: 'Task file upload requirements' + optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' + optional :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' + optional :has_unlimited_retries_for_numbas, type: Boolean, desc: 'Whether or not the Numbas test can be attempted unlimited times' + optional :has_time_delay_for_numbas, type: Boolean, desc: 'Whether or not there is a time delay between Numbas test attempts' + optional :is_numbas_restricted_to_1_attempt, type: Boolean, desc: 'Whether or not the Numbas test is restricted to 1 attempt' + optional :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' + optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' + optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' + optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' + optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image name for overseer' + optional :moss_language, type: String, desc: 'The language to use for code similarity checks' end end put '/units/:unit_id/task_definitions/:id' do @@ -134,6 +149,11 @@ class TaskDefinitionsApi < Grape::API :abbreviation, :restrict_status_updates, :plagiarism_warn_pct, + :has_enabled_numbas_test, + :has_unlimited_retries_for_numbas, + :has_time_delay_for_numbas, + :is_numbas_restricted_to_1_attempt, + :numbas_time_delay, :is_graded, :max_quality_pts, :assessment_enabled, diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index f0fcfa749..6ec540d6b 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -95,6 +95,10 @@ def copy_to(other_unit) new_td.add_task_resources(task_resources, copy: true) end + if has_numbas_data? + new_td.add_numbas_data(task_numbas_data, copy: true) + end + new_td.save! new_td @@ -133,6 +137,10 @@ def move_files_on_abbreviation_change if File.exist? task_assessment_resources_with_abbreviation(old_abbr) FileUtils.mv(task_assessment_resources_with_abbreviation(old_abbr), task_assessment_resources()) end + + if File.exist? task_numbas_data_with_abbreviation(old_abbr) + FileUtils.mv(task_numbas_data_with_abbreviation(old_abbr), task_numbas_data()) + end end def docker_image_name_tag @@ -292,7 +300,7 @@ def to_csv_row end def self.csv_columns - [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] + [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :has_enabled_numbas_test, :has_unlimited_retries_for_numbas, :has_time_delay_for_numbas, :is_numbas_restricted_to_1_attempt, :numbas_time_delay, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] end def self.task_def_for_csv_row(unit, row) @@ -324,21 +332,27 @@ def self.task_def_for_csv_row(unit, row) new_task = true end - result.name = name - result.unit_id = unit.id - result.abbreviation = abbreviation - result.description = "#{row[:description]}".strip - result.weighting = row[:weighting].to_i - result.target_grade = row[:target_grade].to_i - result.restrict_status_updates = %w(Yes y Y yes true TRUE 1).include? "#{row[:restrict_status_updates]}".strip - result.max_quality_pts = row[:max_quality_pts].to_i - result.is_graded = %w(Yes y Y yes true TRUE 1).include? "#{row[:is_graded]}".strip - result.start_date = start_date - result.target_date = target_date - result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? - result.due_date = due_date - - result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i + result.name = name + result.unit_id = unit.id + result.abbreviation = abbreviation + result.description = "#{row[:description]}".strip + result.weighting = row[:weighting].to_i + result.target_grade = row[:target_grade].to_i + result.restrict_status_updates = %w(Yes y Y yes true TRUE 1).include? "#{row[:restrict_status_updates]}".strip + result.max_quality_pts = row[:max_quality_pts].to_i + result.is_graded = %w(Yes y Y yes true TRUE 1).include? "#{row[:is_graded]}".strip + result.start_date = start_date + result.target_date = target_date + result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? + result.due_date = due_date + + result.has_enabled_numbas_test = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_enabled_numbas_test]}".strip + result.has_unlimited_retries_for_numbas = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_unlimited_retries_for_numbas]}".strip + result.has_time_delay_for_numbas = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_time_delay_for_numbas]}".strip + result.is_numbas_restricted_to_1_attempt = %w(Yes y Y yes true TRUE 1).include? "#{row[:is_numbas_restricted_to_1_attempt]}".strip + result.numbas_time_delay = "#{row[:numbas_time_delay]}".strip + + result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i if row[:group_set].present? result.group_set = unit.group_sets.where(name: row[:group_set]).first @@ -388,6 +402,26 @@ def has_numbas_data? File.exist? task_numbas_data end + def has_enabled_numbas_test? + has_enabled_numbas_test + end + + def has_unlimited_retries_for_numbas? + has_unlimited_retries_for_numbas + end + + def has_time_delay_for_numbas? + has_time_delay_for_numbas + end + + def is_numbas_restricted_to_1_attempt? + is_numbas_restricted_to_1_attempt + end + + def numbas_time_delay? + numbas_time_delay + end + def is_graded? is_graded end @@ -440,8 +474,12 @@ def remove_task_assessment_resources() end end - def add_numbas_data(file) - FileUtils.mv file, task_numbas_data + def add_numbas_data(file, copy: false) + if copy + FileUtils.cp file, task_numbas_data + else + FileUtils.mv file, task_numbas_data + end end def remove_numbas_data() @@ -509,6 +547,7 @@ def delete_associated_files() remove_task_sheet() remove_task_resources() remove_task_assessment_resources() + remove_numbas_data() end # Calculate the path to the task sheet using the provided abbreviation diff --git a/db/migrate/20231205011958_add_fields_to_task_def.rb b/db/migrate/20231205011958_add_fields_to_task_def.rb deleted file mode 100644 index 35d9bb7cc..000000000 --- a/db/migrate/20231205011958_add_fields_to_task_def.rb +++ /dev/null @@ -1,19 +0,0 @@ -class AddFieldsToTaskDef < ActiveRecord::Migration[7.0] - def change - change_table :task_definitions do |t| - t.boolean :has_test, default: false - t.boolean :restrict_attempts, default: false - t.integer :delay_restart_minutes - t.boolean :retake_on_resubmit, default: false - end - end - - def down - change_table :task_definitions do |t| - t.remove :has_test - t.remove :restrict_attempts - t.remove :delay_restart_minutes - t.remove :retake_on_resubmit - end - end -end diff --git a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb new file mode 100644 index 000000000..3ff5a6e89 --- /dev/null +++ b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb @@ -0,0 +1,21 @@ +class ModifyNumbasFieldsInTaskDef < ActiveRecord::Migration[7.0] + def change + change_table :task_definitions do |t| + t.boolean :has_enabled_numbas_test, default: false + t.boolean :has_unlimited_retries_for_numbas, default: false + t.boolean :has_time_delay_for_numbas, default: false + t.boolean :is_numbas_restricted_to_1_attempt, default: false + t.string :numbas_time_delay + end + end + + def down + change_table :task_definitions do |t| + t.remove :has_enabled_numbas_test + t.remove :has_unlimited_retries_for_numbas + t.remove :has_time_delay_for_numbas + t.remove :is_numbas_restricted_to_1_attempt + t.remove :numbas_time_delay + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 29c978802..9e43b0390 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -250,10 +250,11 @@ t.bigint "overseer_image_id" t.string "tii_group_id" t.string "moss_language" - t.boolean "has_test", default: false - t.boolean "restrict_attempts", default: false - t.integer "delay_restart_minutes" - t.boolean "retake_on_resubmit", default: false + t.boolean "has_enabled_numbas_test", default: false + t.boolean "has_unlimited_retries_for_numbas", default: false + t.boolean "has_time_delay_for_numbas", default: false + t.boolean "is_numbas_restricted_to_1_attempt", default: false + t.string "numbas_time_delay" t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" t.index ["overseer_image_id"], name: "index_task_definitions_on_overseer_image_id" t.index ["tutorial_stream_id"], name: "index_task_definitions_on_tutorial_stream_id" From dade800cd9fb8bc253746b0716ee300f0a9ff0c8 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Fri, 22 Mar 2024 21:20:19 +1100 Subject: [PATCH 008/124] Remove foreign key reference and add missing columns to csv file Rubocop offenses are fixed as well --- app/api/api_root.rb | 1 - app/api/entities/numbas_entity.rb | 1 - app/api/entities/test_attempt_entity.rb | 1 - app/models/task_definition.rb | 5 ++++- db/migrate/20231205011842_create_test_attempts.rb | 2 +- db/schema.rb | 1 - test_files/COS10001-Tasks.csv | 2 +- 7 files changed, 6 insertions(+), 7 deletions(-) diff --git a/app/api/api_root.rb b/app/api/api_root.rb index cdf6e6404..becca1574 100644 --- a/app/api/api_root.rb +++ b/app/api/api_root.rb @@ -76,7 +76,6 @@ class ApiRoot < Grape::API mount Tii::TiiGroupAttachmentApi mount Tii::TiiActionApi - mount NumbasApi mount TestAttemptsApi mount CampusesPublicApi diff --git a/app/api/entities/numbas_entity.rb b/app/api/entities/numbas_entity.rb index 4235ebb3f..ab0554219 100644 --- a/app/api/entities/numbas_entity.rb +++ b/app/api/entities/numbas_entity.rb @@ -1,4 +1,3 @@ - module Entities class NumbasEntity < Grape::Entity expose :file_content, documentation: { type: 'string', desc: 'File content' } diff --git a/app/api/entities/test_attempt_entity.rb b/app/api/entities/test_attempt_entity.rb index 1b3e35968..796bb1420 100644 --- a/app/api/entities/test_attempt_entity.rb +++ b/app/api/entities/test_attempt_entity.rb @@ -1,4 +1,3 @@ - module Entities class TestAttemptEntity < Grape::Entity expose :id, :name, :attempt_number, :pass_status, :exam_data, :completed, :cmi_entry diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 6ec540d6b..eb3202e11 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -300,7 +300,10 @@ def to_csv_row end def self.csv_columns - [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :has_enabled_numbas_test, :has_unlimited_retries_for_numbas, :has_time_delay_for_numbas, :is_numbas_restricted_to_1_attempt, :numbas_time_delay, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] + [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, + :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :has_enabled_numbas_test, + :has_unlimited_retries_for_numbas, :has_time_delay_for_numbas, :is_numbas_restricted_to_1_attempt, :numbas_time_delay, + :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] end def self.task_def_for_csv_row(unit, row) diff --git a/db/migrate/20231205011842_create_test_attempts.rb b/db/migrate/20231205011842_create_test_attempts.rb index 3828d1154..8430b8a8d 100644 --- a/db/migrate/20231205011842_create_test_attempts.rb +++ b/db/migrate/20231205011842_create_test_attempts.rb @@ -1,7 +1,7 @@ class CreateTestAttempts < ActiveRecord::Migration[7.0] def change create_table :test_attempts do |t| - t.references :task, foreign_key: true + t.references :task t.string :name t.integer :attempt_number, default: 1, null: false t.boolean :pass_status diff --git a/db/schema.rb b/db/schema.rb index 9e43b0390..8095e6a87 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -551,5 +551,4 @@ t.index ["user_id"], name: "index_webcals_on_user_id", unique: true end - add_foreign_key "test_attempts", "tasks" end diff --git a/test_files/COS10001-Tasks.csv b/test_files/COS10001-Tasks.csv index bc86315bc..66667e3f7 100644 --- a/test_files/COS10001-Tasks.csv +++ b/test_files/COS10001-Tasks.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_unlimited_retries_for_numbas,has_time_delay_for_numbas,is_numbas_restricted_to_1_attempt,numbas_time_delay Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks From aa8926e59523c604b5e892245d42b5a66d873298 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 23 Mar 2024 00:04:32 +1100 Subject: [PATCH 009/124] refactor: simplify Numbas config storage --- app/api/entities/task_definition_entity.rb | 4 +- app/api/task_definitions_api.rb | 96 +++++++++---------- app/models/task_definition.rb | 60 +++++------- ...021829_modify_numbas_fields_in_task_def.rb | 8 +- db/schema.rb | 4 +- test_files/COS10001-Tasks.csv | 2 +- 6 files changed, 74 insertions(+), 100 deletions(-) diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index 3fdcd3b65..7861f3b3d 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -41,10 +41,8 @@ def staff?(my_role) expose :has_task_assessment_resources?, as: :has_task_assessment_resources, if: ->(unit, options) { staff?(options[:my_role]) } expose :has_numbas_data?, as: :has_numbas_data expose :has_enabled_numbas_test, if: ->(unit, options) { staff?(options[:my_role]) } - expose :has_unlimited_retries_for_numbas, if: ->(unit, options) { staff?(options[:my_role]) } - expose :has_time_delay_for_numbas, if: ->(unit, options) { staff?(options[:my_role]) } - expose :is_numbas_restricted_to_1_attempt, if: ->(unit, options) { staff?(options[:my_role]) } expose :numbas_time_delay, if: ->(unit, options) { staff?(options[:my_role]) } + expose :numbas_attempt_limit, if: ->(unit, options) { staff?(options[:my_role]) } expose :is_graded expose :max_quality_pts expose :overseer_image_id, if: ->(unit, options) { staff?(options[:my_role]) } diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index b75a83224..69bee9e9d 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -15,29 +15,27 @@ class TaskDefinitionsApi < Grape::API desc 'Add a new task definition to the given unit' params do requires :task_def, type: Hash do - optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of tutorial stream' - requires :name, type: String, desc: 'The name of this task def' - requires :description, type: String, desc: 'The description of this task def' - requires :weighting, type: Integer, desc: 'The weighting of this task' - requires :target_grade, type: Integer, desc: 'Minimum grade for task' - optional :group_set_id, type: Integer, desc: 'Related group set' - requires :start_date, type: Date, desc: 'The date when the task should be started' - requires :target_date, type: Date, desc: 'The date when the task is due' - optional :due_date, type: Date, desc: 'The deadline date' - requires :abbreviation, type: String, desc: 'The abbreviation of the task' - requires :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' - optional :upload_requirements, type: String, desc: 'Task file upload requirements' - requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - requires :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' - requires :has_unlimited_retries_for_numbas, type: Boolean, desc: 'Whether or not the Numbas test can be attempted unlimited times' - requires :has_time_delay_for_numbas, type: Boolean, desc: 'Whether or not there is a time delay between Numbas test attempts' - requires :is_numbas_restricted_to_1_attempt, type: Boolean, desc: 'Whether or not the Numbas test is restricted to 1 attempt' - requires :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' - requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' - requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' - optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' - optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image for overseer' - optional :moss_language, type: String, desc: 'The language to use for code similarity checks' + optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of tutorial stream' + requires :name, type: String, desc: 'The name of this task def' + requires :description, type: String, desc: 'The description of this task def' + requires :weighting, type: Integer, desc: 'The weighting of this task' + requires :target_grade, type: Integer, desc: 'Minimum grade for task' + optional :group_set_id, type: Integer, desc: 'Related group set' + requires :start_date, type: Date, desc: 'The date when the task should be started' + requires :target_date, type: Date, desc: 'The date when the task is due' + optional :due_date, type: Date, desc: 'The deadline date' + requires :abbreviation, type: String, desc: 'The abbreviation of the task' + requires :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' + optional :upload_requirements, type: String, desc: 'Task file upload requirements' + requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' + requires :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' + requires :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' + requires :numbas_attempt_limit, type: Integer, desc: 'The number of times a Numbas test can be attempted' + requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' + requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' + optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' + optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image for overseer' + optional :moss_language, type: String, desc: 'The language to use for code similarity checks' end end post '/units/:unit_id/task_definitions/' do @@ -63,10 +61,8 @@ class TaskDefinitionsApi < Grape::API :restrict_status_updates, :plagiarism_warn_pct, :has_enabled_numbas_test, - :has_unlimited_retries_for_numbas, - :has_time_delay_for_numbas, - :is_numbas_restricted_to_1_attempt, :numbas_time_delay, + :numbas_attempt_limit, :is_graded, :max_quality_pts, :assessment_enabled, @@ -103,29 +99,27 @@ class TaskDefinitionsApi < Grape::API params do requires :id, type: Integer, desc: 'The task id to edit' requires :task_def, type: Hash do - optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of the tutorial stream' - optional :name, type: String, desc: 'The name of this task def' - optional :description, type: String, desc: 'The description of this task def' - optional :weighting, type: Integer, desc: 'The weighting of this task' - optional :target_grade, type: Integer, desc: 'Target grade for task' - optional :group_set_id, type: Integer, desc: 'Related group set' - optional :start_date, type: Date, desc: 'The date when the task should be started' - optional :target_date, type: Date, desc: 'The date when the task is due' - optional :due_date, type: Date, desc: 'The deadline date' - optional :abbreviation, type: String, desc: 'The abbreviation of the task' - optional :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' - optional :upload_requirements, type: String, desc: 'Task file upload requirements' - optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - optional :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' - optional :has_unlimited_retries_for_numbas, type: Boolean, desc: 'Whether or not the Numbas test can be attempted unlimited times' - optional :has_time_delay_for_numbas, type: Boolean, desc: 'Whether or not there is a time delay between Numbas test attempts' - optional :is_numbas_restricted_to_1_attempt, type: Boolean, desc: 'Whether or not the Numbas test is restricted to 1 attempt' - optional :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' - optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' - optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' - optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' - optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image name for overseer' - optional :moss_language, type: String, desc: 'The language to use for code similarity checks' + optional :tutorial_stream_abbr, type: String, desc: 'The abbreviation of the tutorial stream' + optional :name, type: String, desc: 'The name of this task def' + optional :description, type: String, desc: 'The description of this task def' + optional :weighting, type: Integer, desc: 'The weighting of this task' + optional :target_grade, type: Integer, desc: 'Target grade for task' + optional :group_set_id, type: Integer, desc: 'Related group set' + optional :start_date, type: Date, desc: 'The date when the task should be started' + optional :target_date, type: Date, desc: 'The date when the task is due' + optional :due_date, type: Date, desc: 'The deadline date' + optional :abbreviation, type: String, desc: 'The abbreviation of the task' + optional :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' + optional :upload_requirements, type: String, desc: 'Task file upload requirements' + optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' + optional :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' + optional :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' + optional :numbas_attempt_limit, type: Integer, desc: 'The number of times a Numbas test can be attempted' + optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' + optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' + optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' + optional :overseer_image_id, type: Integer, desc: 'The id of the Docker image name for overseer' + optional :moss_language, type: String, desc: 'The language to use for code similarity checks' end end put '/units/:unit_id/task_definitions/:id' do @@ -150,10 +144,8 @@ class TaskDefinitionsApi < Grape::API :restrict_status_updates, :plagiarism_warn_pct, :has_enabled_numbas_test, - :has_unlimited_retries_for_numbas, - :has_time_delay_for_numbas, - :is_numbas_restricted_to_1_attempt, :numbas_time_delay, + :numbas_attempt_limit, :is_graded, :max_quality_pts, :assessment_enabled, diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index eb3202e11..1010323aa 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -302,8 +302,8 @@ def to_csv_row def self.csv_columns [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :has_enabled_numbas_test, - :has_unlimited_retries_for_numbas, :has_time_delay_for_numbas, :is_numbas_restricted_to_1_attempt, :numbas_time_delay, - :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] + :numbas_time_delay, :numbas_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, + :tutorial_stream] end def self.task_def_for_csv_row(unit, row) @@ -335,27 +335,25 @@ def self.task_def_for_csv_row(unit, row) new_task = true end - result.name = name - result.unit_id = unit.id - result.abbreviation = abbreviation - result.description = "#{row[:description]}".strip - result.weighting = row[:weighting].to_i - result.target_grade = row[:target_grade].to_i - result.restrict_status_updates = %w(Yes y Y yes true TRUE 1).include? "#{row[:restrict_status_updates]}".strip - result.max_quality_pts = row[:max_quality_pts].to_i - result.is_graded = %w(Yes y Y yes true TRUE 1).include? "#{row[:is_graded]}".strip - result.start_date = start_date - result.target_date = target_date - result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? - result.due_date = due_date - - result.has_enabled_numbas_test = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_enabled_numbas_test]}".strip - result.has_unlimited_retries_for_numbas = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_unlimited_retries_for_numbas]}".strip - result.has_time_delay_for_numbas = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_time_delay_for_numbas]}".strip - result.is_numbas_restricted_to_1_attempt = %w(Yes y Y yes true TRUE 1).include? "#{row[:is_numbas_restricted_to_1_attempt]}".strip - result.numbas_time_delay = "#{row[:numbas_time_delay]}".strip - - result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i + result.name = name + result.unit_id = unit.id + result.abbreviation = abbreviation + result.description = "#{row[:description]}".strip + result.weighting = row[:weighting].to_i + result.target_grade = row[:target_grade].to_i + result.restrict_status_updates = %w(Yes y Y yes true TRUE 1).include? "#{row[:restrict_status_updates]}".strip + result.max_quality_pts = row[:max_quality_pts].to_i + result.is_graded = %w(Yes y Y yes true TRUE 1).include? "#{row[:is_graded]}".strip + result.start_date = start_date + result.target_date = target_date + result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? + result.due_date = due_date + + result.has_enabled_numbas_test = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_enabled_numbas_test]}".strip + result.numbas_time_delay = "#{row[:numbas_time_delay]}".strip + result.numbas_attempt_limit = row[:numbas_attempt_limit].to_i + + result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i if row[:group_set].present? result.group_set = unit.group_sets.where(name: row[:group_set]).first @@ -409,22 +407,14 @@ def has_enabled_numbas_test? has_enabled_numbas_test end - def has_unlimited_retries_for_numbas? - has_unlimited_retries_for_numbas - end - - def has_time_delay_for_numbas? - has_time_delay_for_numbas - end - - def is_numbas_restricted_to_1_attempt? - is_numbas_restricted_to_1_attempt - end - def numbas_time_delay? numbas_time_delay end + def numbas_attempt_limit? + numbas_attempt_limit + end + def is_graded? is_graded end diff --git a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb index 3ff5a6e89..1efd31a89 100644 --- a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb +++ b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb @@ -2,20 +2,16 @@ class ModifyNumbasFieldsInTaskDef < ActiveRecord::Migration[7.0] def change change_table :task_definitions do |t| t.boolean :has_enabled_numbas_test, default: false - t.boolean :has_unlimited_retries_for_numbas, default: false - t.boolean :has_time_delay_for_numbas, default: false - t.boolean :is_numbas_restricted_to_1_attempt, default: false t.string :numbas_time_delay + t.integer :numbas_attempt_limit end end def down change_table :task_definitions do |t| t.remove :has_enabled_numbas_test - t.remove :has_unlimited_retries_for_numbas - t.remove :has_time_delay_for_numbas - t.remove :is_numbas_restricted_to_1_attempt t.remove :numbas_time_delay + t.remove :numbas_attempt_limit end end end diff --git a/db/schema.rb b/db/schema.rb index 8095e6a87..41a50f670 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -251,10 +251,8 @@ t.string "tii_group_id" t.string "moss_language" t.boolean "has_enabled_numbas_test", default: false - t.boolean "has_unlimited_retries_for_numbas", default: false - t.boolean "has_time_delay_for_numbas", default: false - t.boolean "is_numbas_restricted_to_1_attempt", default: false t.string "numbas_time_delay" + t.integer "numbas_attempt_limit" t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" t.index ["overseer_image_id"], name: "index_task_definitions_on_overseer_image_id" t.index ["tutorial_stream_id"], name: "index_task_definitions_on_tutorial_stream_id" diff --git a/test_files/COS10001-Tasks.csv b/test_files/COS10001-Tasks.csv index 66667e3f7..7fc9fe863 100644 --- a/test_files/COS10001-Tasks.csv +++ b/test_files/COS10001-Tasks.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_unlimited_retries_for_numbas,has_time_delay_for_numbas,is_numbas_restricted_to_1_attempt,numbas_time_delay +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,numbas_time_delay,numbas_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks From 3f19ffa6f4f465ed0691582b5012cf997ec62852 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 23 Mar 2024 19:32:59 +1100 Subject: [PATCH 010/124] fix: reset Numbas configs if no zip file has been uploaded --- app/models/task_definition.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 1010323aa..2349c3c5d 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -41,6 +41,8 @@ class TaskDefinition < ApplicationRecord validates :weighting, presence: true + after_initialize :reset_numbas_configs_if_no_zip + include TaskDefinitionTiiModule include TaskDefinitionSimilarityModule @@ -479,6 +481,8 @@ def remove_numbas_data() if has_numbas_data? FileUtils.rm task_numbas_data end + + reset_numbas_configs_if_no_zip() end # Get the path to the task sheet - using the current abbreviation @@ -603,4 +607,12 @@ def task_numbas_data_with_abbreviation(abbr) result_with_sanitised_file end end + + def reset_numbas_configs_if_no_zip() + if !has_numbas_data? + self.has_enabled_numbas_test = false + self.numbas_time_delay = 'no delay' + self.numbas_attempt_limit = 0 + end + end end From 54c27cef2b8ff57fd8ac972728ec3d249e2862b8 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sun, 24 Mar 2024 13:42:04 +1100 Subject: [PATCH 011/124] feat: change Numbas time delay config to enable incremental delays --- app/api/entities/task_definition_entity.rb | 2 +- app/api/task_definitions_api.rb | 8 ++++---- app/models/task_definition.rb | 12 ++++++------ ...0240322021829_modify_numbas_fields_in_task_def.rb | 4 ++-- db/schema.rb | 2 +- test_files/COS10001-Tasks.csv | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index 7861f3b3d..4b4454ef1 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -41,7 +41,7 @@ def staff?(my_role) expose :has_task_assessment_resources?, as: :has_task_assessment_resources, if: ->(unit, options) { staff?(options[:my_role]) } expose :has_numbas_data?, as: :has_numbas_data expose :has_enabled_numbas_test, if: ->(unit, options) { staff?(options[:my_role]) } - expose :numbas_time_delay, if: ->(unit, options) { staff?(options[:my_role]) } + expose :has_numbas_time_delay, if: ->(unit, options) { staff?(options[:my_role]) } expose :numbas_attempt_limit, if: ->(unit, options) { staff?(options[:my_role]) } expose :is_graded expose :max_quality_pts diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index 69bee9e9d..eb59ce87b 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -29,7 +29,7 @@ class TaskDefinitionsApi < Grape::API optional :upload_requirements, type: String, desc: 'Task file upload requirements' requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' requires :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' - requires :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' + requires :has_numbas_time_delay, type: Boolean, desc: 'Whether or not there is an incremental time delay between Numbas test attempts' requires :numbas_attempt_limit, type: Integer, desc: 'The number of times a Numbas test can be attempted' requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' @@ -61,7 +61,7 @@ class TaskDefinitionsApi < Grape::API :restrict_status_updates, :plagiarism_warn_pct, :has_enabled_numbas_test, - :numbas_time_delay, + :has_numbas_time_delay, :numbas_attempt_limit, :is_graded, :max_quality_pts, @@ -113,7 +113,7 @@ class TaskDefinitionsApi < Grape::API optional :upload_requirements, type: String, desc: 'Task file upload requirements' optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' optional :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' - optional :numbas_time_delay, type: String, desc: 'The time delay between Numbas test attempts' + optional :has_numbas_time_delay, type: Boolean, desc: 'Whether or not there is an incremental time delay between Numbas test attempts' optional :numbas_attempt_limit, type: Integer, desc: 'The number of times a Numbas test can be attempted' optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' @@ -144,7 +144,7 @@ class TaskDefinitionsApi < Grape::API :restrict_status_updates, :plagiarism_warn_pct, :has_enabled_numbas_test, - :numbas_time_delay, + :has_numbas_time_delay, :numbas_attempt_limit, :is_graded, :max_quality_pts, diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 2349c3c5d..389e042df 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -304,8 +304,8 @@ def to_csv_row def self.csv_columns [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :has_enabled_numbas_test, - :numbas_time_delay, :numbas_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, - :tutorial_stream] + :has_numbas_time_delay, :numbas_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, + :due_day, :tutorial_stream] end def self.task_def_for_csv_row(unit, row) @@ -352,7 +352,7 @@ def self.task_def_for_csv_row(unit, row) result.due_date = due_date result.has_enabled_numbas_test = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_enabled_numbas_test]}".strip - result.numbas_time_delay = "#{row[:numbas_time_delay]}".strip + result.has_numbas_time_delay = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_numbas_time_delay]}".strip result.numbas_attempt_limit = row[:numbas_attempt_limit].to_i result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i @@ -409,8 +409,8 @@ def has_enabled_numbas_test? has_enabled_numbas_test end - def numbas_time_delay? - numbas_time_delay + def has_numbas_time_delay? + has_numbas_time_delay end def numbas_attempt_limit? @@ -611,7 +611,7 @@ def task_numbas_data_with_abbreviation(abbr) def reset_numbas_configs_if_no_zip() if !has_numbas_data? self.has_enabled_numbas_test = false - self.numbas_time_delay = 'no delay' + self.has_numbas_time_delay = false self.numbas_attempt_limit = 0 end end diff --git a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb index 1efd31a89..7fd3cd82a 100644 --- a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb +++ b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb @@ -2,7 +2,7 @@ class ModifyNumbasFieldsInTaskDef < ActiveRecord::Migration[7.0] def change change_table :task_definitions do |t| t.boolean :has_enabled_numbas_test, default: false - t.string :numbas_time_delay + t.boolean :has_numbas_time_delay, default: false t.integer :numbas_attempt_limit end end @@ -10,7 +10,7 @@ def change def down change_table :task_definitions do |t| t.remove :has_enabled_numbas_test - t.remove :numbas_time_delay + t.remove :has_numbas_time_delay t.remove :numbas_attempt_limit end end diff --git a/db/schema.rb b/db/schema.rb index 41a50f670..a6b0f6cae 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -251,7 +251,7 @@ t.string "tii_group_id" t.string "moss_language" t.boolean "has_enabled_numbas_test", default: false - t.string "numbas_time_delay" + t.boolean "has_numbas_time_delay", default: false t.integer "numbas_attempt_limit" t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" t.index ["overseer_image_id"], name: "index_task_definitions_on_overseer_image_id" diff --git a/test_files/COS10001-Tasks.csv b/test_files/COS10001-Tasks.csv index 7fc9fe863..c961c8e5b 100644 --- a/test_files/COS10001-Tasks.csv +++ b/test_files/COS10001-Tasks.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,numbas_time_delay,numbas_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks From 20d526533a2ecab592d7d22f3330d37cee7e0f45 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 27 Mar 2024 23:46:07 +1100 Subject: [PATCH 012/124] fix: expose enable Numbas test config to all users --- app/api/entities/task_definition_entity.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index 4b4454ef1..9fda48f8e 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -40,7 +40,7 @@ def staff?(my_role) expose :has_task_resources?, as: :has_task_resources expose :has_task_assessment_resources?, as: :has_task_assessment_resources, if: ->(unit, options) { staff?(options[:my_role]) } expose :has_numbas_data?, as: :has_numbas_data - expose :has_enabled_numbas_test, if: ->(unit, options) { staff?(options[:my_role]) } + expose :has_enabled_numbas_test expose :has_numbas_time_delay, if: ->(unit, options) { staff?(options[:my_role]) } expose :numbas_attempt_limit, if: ->(unit, options) { staff?(options[:my_role]) } expose :is_graded From 5d80830d3564bb7137db3c4adb3b1d906342e851 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:01:06 +1100 Subject: [PATCH 013/124] fix: use correct Numbas data path in Numbas api --- app/api/numbas_api.rb | 52 ++++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/app/api/numbas_api.rb b/app/api/numbas_api.rb index cb81ae944..c58cf8fc8 100644 --- a/app/api/numbas_api.rb +++ b/app/api/numbas_api.rb @@ -5,6 +5,10 @@ class NumbasApi < Grape::API # Include the AuthenticationHelpers for authentication functionality helpers AuthenticationHelpers + before do + authenticated? + end + helpers do # Method to stream a file from a zip archive at the specified path # @param zip_path [String] the path to the zip archive @@ -43,24 +47,40 @@ def stream_file_from_zip(zip_path, file_path) end end - # Define the API namespace - namespace :numbas_api do - # Use Grape's before hook to check authentication before processing any route - before do - authenticated? - end - - get '/index.html' do - env['api.format'] = :txt - zip_path = FileHelper.get_numbas_test_path(params[:unit_code], params[:task_definition_id], 'numbas_test.zip') - stream_file_from_zip(zip_path, 'index.html') + desc 'Start streaming the Numbas test from the index.html' + params do + requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' + requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' + end + get '/units/:unit_id/task_definitions/:task_def_id/numbas_data/index.html' do + env['api.format'] = :txt + unit = Unit.find(params[:unit_id]) + task_def = unit.task_definitions.find(params[:task_def_id]) + if task_def.has_numbas_data? + zip_path = task_def.task_numbas_data + content_type 'application/octet-stream' + else + error!({ error: 'Numbas data does not exist.' }, 401) end + stream_file_from_zip(zip_path, 'index.html') + end - get '*file_path' do - env['api.format'] = :txt - zip_path = FileHelper.get_numbas_test_path(params[:unit_code], params[:task_definition_id], 'numbas_test.zip') - requested_file_path = "#{params[:file_path]}.#{params[:format]}" - stream_file_from_zip(zip_path, requested_file_path) + desc 'Start streaming the Numbas test from the specified file' + params do + requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' + requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' + end + get '/units/:unit_id/task_definitions/:task_def_id/numbas_data/*file_path' do + env['api.format'] = :txt + unit = Unit.find(params[:unit_id]) + task_def = unit.task_definitions.find(params[:task_def_id]) + if task_def.has_numbas_data? + zip_path = task_def.task_numbas_data + content_type 'application/octet-stream' + else + error!({ error: 'Numbas data does not exist.' }, 401) end + requested_file_path = "#{params[:file_path]}.#{params[:format]}" + stream_file_from_zip(zip_path, requested_file_path) end end From 0cc4915c85d7d55b48ca6832f6779e49362a7870 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 9 Apr 2024 10:44:47 +1000 Subject: [PATCH 014/124] fix: use custom endpoint for Numbas --- app/api/numbas_api.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/numbas_api.rb b/app/api/numbas_api.rb index c58cf8fc8..119484775 100644 --- a/app/api/numbas_api.rb +++ b/app/api/numbas_api.rb @@ -52,7 +52,7 @@ def stream_file_from_zip(zip_path, file_path) requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' end - get '/units/:unit_id/task_definitions/:task_def_id/numbas_data/index.html' do + get 'numbas_api/units/:unit_id/task_definitions/:task_def_id/index.html' do env['api.format'] = :txt unit = Unit.find(params[:unit_id]) task_def = unit.task_definitions.find(params[:task_def_id]) @@ -70,7 +70,7 @@ def stream_file_from_zip(zip_path, file_path) requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' end - get '/units/:unit_id/task_definitions/:task_def_id/numbas_data/*file_path' do + get 'numbas_api/units/:unit_id/task_definitions/:task_def_id/*file_path' do env['api.format'] = :txt unit = Unit.find(params[:unit_id]) task_def = unit.task_definitions.find(params[:task_def_id]) From 27253bd1b1d5640d00098f692160dd4b50675640 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 9 Apr 2024 16:20:35 +1000 Subject: [PATCH 015/124] fix: consolidate numbas api endpoints --- app/api/numbas_api.rb | 37 +++++++++---------------------------- 1 file changed, 9 insertions(+), 28 deletions(-) diff --git a/app/api/numbas_api.rb b/app/api/numbas_api.rb index 119484775..e422afac8 100644 --- a/app/api/numbas_api.rb +++ b/app/api/numbas_api.rb @@ -16,14 +16,16 @@ class NumbasApi < Grape::API def stream_file_from_zip(zip_path, file_path) file_stream = nil + logger.debug "Streaming zip file at #{zip_path}" # Get an input stream for the requested file within the ZIP archive Zip::File.open(zip_path) do |zip_file| zip_file.each do |entry| - logger.debug "Entry name: #{entry.name}" if entry.name == file_path + logger.debug "Found file #{file_path} from numbas container" file_stream = entry.get_input_stream break end + logger.debug "Requested file #{file_path} not found from numbas container" end end @@ -47,40 +49,19 @@ def stream_file_from_zip(zip_path, file_path) end end - desc 'Start streaming the Numbas test from the index.html' + desc 'Serve numbas content' params do - requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' - requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' + requires :task_def_id, type: Integer, desc: 'Task Definition ID to get Numbas test data for' end - get 'numbas_api/units/:unit_id/task_definitions/:task_def_id/index.html' do + get '/numbas_api/:task_def_id/*file_path' do env['api.format'] = :txt - unit = Unit.find(params[:unit_id]) - task_def = unit.task_definitions.find(params[:task_def_id]) + task_def = TaskDefinition.find(params[:task_def_id]) if task_def.has_numbas_data? zip_path = task_def.task_numbas_data content_type 'application/octet-stream' + stream_file_from_zip(zip_path, params[:file_path]) else - error!({ error: 'Numbas data does not exist.' }, 401) + error!({ error: 'Numbas data does not exist.' }, 404) end - stream_file_from_zip(zip_path, 'index.html') - end - - desc 'Start streaming the Numbas test from the specified file' - params do - requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' - requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' - end - get 'numbas_api/units/:unit_id/task_definitions/:task_def_id/*file_path' do - env['api.format'] = :txt - unit = Unit.find(params[:unit_id]) - task_def = unit.task_definitions.find(params[:task_def_id]) - if task_def.has_numbas_data? - zip_path = task_def.task_numbas_data - content_type 'application/octet-stream' - else - error!({ error: 'Numbas data does not exist.' }, 401) - end - requested_file_path = "#{params[:file_path]}.#{params[:format]}" - stream_file_from_zip(zip_path, requested_file_path) end end From ff5ff62061c05e509f15af3048fe047b0d69dc68 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:00:19 +1000 Subject: [PATCH 016/124] fix: refactor numbas config reset logic --- app/models/task_definition.rb | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 389e042df..a3a39c074 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -41,8 +41,6 @@ class TaskDefinition < ApplicationRecord validates :weighting, presence: true - after_initialize :reset_numbas_configs_if_no_zip - include TaskDefinitionTiiModule include TaskDefinitionSimilarityModule @@ -482,7 +480,7 @@ def remove_numbas_data() FileUtils.rm task_numbas_data end - reset_numbas_configs_if_no_zip() + reset_numbas_config() end # Get the path to the task sheet - using the current abbreviation @@ -608,11 +606,9 @@ def task_numbas_data_with_abbreviation(abbr) end end - def reset_numbas_configs_if_no_zip() - if !has_numbas_data? - self.has_enabled_numbas_test = false - self.has_numbas_time_delay = false - self.numbas_attempt_limit = 0 - end + def reset_numbas_config() + self.has_enabled_numbas_test = false + self.has_numbas_time_delay = false + self.numbas_attempt_limit = 0 end end From 89a66157b4fde887a19912ca40261243b4961e2f Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:15:39 +1000 Subject: [PATCH 017/124] fix: add missing numbas config fields to fix unit tests --- test/api/units/task_definitions_api_test.rb | 5 +- test/models/task_definition_test.rb | 2 +- ...COS10001-ImportTasksWithTutorialStream.csv | 74 +++++++++--------- ...10001-ImportTasksWithoutTutorialStream.csv | 74 +++++++++--------- test_files/csv_test_files/COS10001-Tasks.csv | 4 +- test_files/csv_test_files/COS10001-Tasks.xlsx | Bin 10335 -> 6646 bytes .../unit_csv_imports/import_group_tasks.csv | 6 +- 7 files changed, 84 insertions(+), 81 deletions(-) diff --git a/test/api/units/task_definitions_api_test.rb b/test/api/units/task_definitions_api_test.rb index 656d2d67c..2817d372c 100644 --- a/test/api/units/task_definitions_api_test.rb +++ b/test/api/units/task_definitions_api_test.rb @@ -49,7 +49,10 @@ def test_task_definition_cud upload_requirements: '[ { "key": "file0", "name": "Shape Class", "type": "document" } ]', plagiarism_warn_pct: 80, is_graded: false, - max_quality_pts: 0 + max_quality_pts: 0, + has_enabled_numbas_test: false, + has_numbas_time_delay: true, + numbas_attempt_limit: 0 } } diff --git a/test/models/task_definition_test.rb b/test/models/task_definition_test.rb index d20634d8c..8c22317c1 100644 --- a/test/models/task_definition_test.rb +++ b/test/models/task_definition_test.rb @@ -145,7 +145,7 @@ def test_export_task_definitions_csv task_defs_csv = CSV.parse unit.task_definitions_csv, headers: true task_defs_csv.each do |task_def_csv| task_def = unit.task_definitions.find_by(abbreviation: task_def_csv['abbreviation']) - keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day'] + keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'has_enabled_numbas_test', 'has_numbas_time_delay', 'numbas_attempt_limit'] task_def_csv.each do |key, value| unless keys_to_ignore.include?(key) assert_equal(task_def[key].to_s, value) diff --git a/test_files/COS10001-ImportTasksWithTutorialStream.csv b/test_files/COS10001-ImportTasksWithTutorialStream.csv index d31f822b0..dde8a9e07 100644 --- a/test_files/COS10001-ImportTasksWithTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithTutorialStream.csv @@ -1,37 +1,37 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream -Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks -Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks -Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks -Credit Task 1.4 - Concept Map,1.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",1,Tue,2,Tue,,,0,FALSE,90,,,import-tasks -Pass Task 2.1 - Hand Execute Assignment,2.1P,"Using the assignment statement, you can assign a value to a variable. In this task you will demonstrate how this action works within the computer.",2,0,FALSE,"[{""key"":""file0"",""name"":""Program Execution 1"",""type"":""image""},{""key"":""file1"",""name"":""Program Execution 2"",""type"":""image""},{""key"":""file2"",""name"":""Program Execution 3"",""type"":""image""},{""key"":""file3"",""name"":""Program Execution 4"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks -Pass Task 2.2 - Hello User,2.2P,Now that we have variables we can create a program that reads in the users name from the Terminal and echoes back a welcome message.,4,0,FALSE,"[{""key"":""file0"",""name"":""HelloUser.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks -Pass Task 2.3 - My Drawing Procedure,2.3P,Procedures are a great way of encapsulating the instructions needed to perform a task. In most cases the task will need some input data for it to work with. Use parameters to provide data to your procedures.,2,0,FALSE,"[{""key"":""file0"",""name"":""Shape Drawing Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks -Pass Task 2.4 - My Functions,2.4P,Using functions you can now create artefacts to encapsulate the steps needed to calculate a value.,4,0,FALSE,"[{""key"":""file0"",""name"":""My Function Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks -Credit Task 2.5 - Concept Maps,2.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",2,Tue,3,Tue,,,5,FALSE,90,,,import-tasks -Pass Task 3.1 - Hand Execution of Control Flow,3.1P,In this task you will use the hand execution process to demonstrate how the control flow constructs operate within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Button Code"",""type"":""code""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,import-tasks -Pass Task 3.2 - Name Tester,3.2P,Control flow enables you to easily add conditions and loops to your programs. In this task you will create a small program that uses conditions and loops to output custom messages to users.,4,0,FALSE,"[{""key"":""file0"",""name"":""Name Tester code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,import-tasks -Pass Task 3.3 - Circle Moving,3.3P,In this task you will create a small program that allows the user to move a circle around on the screen.,4,0,FALSE,"[{""key"":""file0"",""name"":""Circle Mover code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,import-tasks -Credit Task 3.4 - User Input Functions,3.4C,So far we have provided you with a unit to read and check values entered by the user: the Terminal User Input unit. In this task you will extend this library so that it has a number of additional functions.,4,1,FALSE,"[{""key"":""file0"",""name"":""User Input unit code"",""type"":""code""},{""key"":""file1"",""name"":""Program code"",""type"":""code""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,,import-tasks -Credit Task 3.5 - Concept Map,3.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",3,Tue,4,Tue,,,0,FALSE,90,,,import-tasks -Distinction Task 3.6 - Mandelbrot,3.6D,The Mandelbrot provides an interesting challenge in order to determine how to zoom in to and out of the section of the Mandelbrot being shown to the user.,4,2,FALSE,"[{""key"":""file0"",""name"":""Mandelbrot code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,,import-tasks -Pass Task 4.1 - Using Records and Enumerations,4.1P,Effectively organising your data makes programs much easier to develop. By using records and enumerations you can start to model the entities associated with your programs.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,7,Mon,0,FALSE,90,,,import-tasks -Credit Task 4.2 - Fruit Punch,4.2C,Create a program using the concepts covered so far.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,,,0,FALSE,90,,,import-tasks -Credit Task 4.3 - Concept Map,4.3C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",4,Tue,5,Tue,,,0,FALSE,90,,,import-tasks -Test 1,T1,Test 1 covers weeks 1 to 3,1,0,TRUE,[],5,Fri,5,Fri,,,0,FALSE,90,,,import-tasks -Pass Task 5.1 - Hand Execution of Arrays,5.1P,Demonstrate how arrays work within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,,import-tasks -Pass Task 5.2 - Arrays of Records,5.2P,Add an array of records to your program that uses records.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,,import-tasks -Credit Task 5.3 - Food Hunter,5.3C,Extend a small game to make use of arrays.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,,import-tasks -Credit Task 5.4 - Concept Map,5.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",5,Tue,6,Tue,,,0,FALSE,90,,,import-tasks -Distinction Task 5.5 - Sort Visualiser,5.5D,Create a program to demonstrate sorting working within the computer.,4,2,FALSE,"[{""key"":""file0"",""name"":""Sort Visualiser"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,,import-tasks -Pass Task 6.1 - Structure Charts,6.1P,Illustrate the structure of your program using a structure chart.,2,0,FALSE,"[{""key"":""file0"",""name"":""Program structrue chart"",""type"":""image""}]",6,Tue,7,Tue,10,Mon,0,FALSE,90,,,import-tasks -Pass Task 7.1 - Programming Principles,7.1P,"Describe the principles of structured, procedural, programming.",4,0,FALSE,"[{""key"":""file0"",""name"":""Program Principles Description"",""type"":""document""}]",7,Tue,8,Tue,10,Mon,0,FALSE,90,,,import-tasks -Distinction Task 7.2 - Game of Life,7.2D,Create the Game of Life,4,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",7,Tue,8,Tue,,,0,FALSE,90,,,import-tasks -Pass Task 8.1 - Language Reference Sheet,8.1P,Create a reference sheet for C or C#,4,0,FALSE,"[{""key"":""file0"",""name"":""Reference Sheet"",""type"":""document""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,,import-tasks -Pass Task 8.2 - Circle Moving 2,8.2P,Recreate your circle moving program using C,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,,import-tasks -Test 2,T2,Covers all core concepts.,1,0,TRUE,[],9,Fri,9,Fri,,,0,FALSE,90,,,import-tasks -Pass Task 9.1 - Reading Another Language,9.1P,Demonstrate how programs written in C work within the computer,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,,import-tasks -Credit Task 9.2 - Another Language,9.2C,Create a program with C using the concepts covered.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,,import-tasks -High Distinction Task 10.1 - Custom Program,10.1H,Extend your custom program to meet the High Distinction criteria.,4,3,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",10,Tue,13,Tue,,,0,FALSE,90,,,import-tasks -High Distinction Task 10.2 - Research Report,10.2H,Start working on a research project,8,3,FALSE,"[{""key"":""file0"",""name"":""Research Report Document"",""type"":""document""}]",10,Tue,13,Tue,,,0,FALSE,90,,,import-tasks -Pass Task 11.1 - Learning Summary Report,11.1P,Summarise your learning from the unit.,4,0,FALSE,"[{""key"":""file0"",""name"":""Learning Summary Report"",""type"":""document""}]",11,Tue,12,Tue,,,0,FALSE,90,,,import-tasks -Distinction Task 6.2 - Custom Program,6.2D,Start working on your custom program!,16,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",6,Tue,13,Tue,,,5,TRUE,90,,,import-tasks \ No newline at end of file +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Credit Task 1.4 - Concept Map,1.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",1,Tue,2,Tue,,,0,FALSE,90,,,import-tasks,,, +Pass Task 2.1 - Hand Execute Assignment,2.1P,"Using the assignment statement, you can assign a value to a variable. In this task you will demonstrate how this action works within the computer.",2,0,FALSE,"[{""key"":""file0"",""name"":""Program Execution 1"",""type"":""image""},{""key"":""file1"",""name"":""Program Execution 2"",""type"":""image""},{""key"":""file2"",""name"":""Program Execution 3"",""type"":""image""},{""key"":""file3"",""name"":""Program Execution 4"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 2.2 - Hello User,2.2P,Now that we have variables we can create a program that reads in the users name from the Terminal and echoes back a welcome message.,4,0,FALSE,"[{""key"":""file0"",""name"":""HelloUser.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 2.3 - My Drawing Procedure,2.3P,Procedures are a great way of encapsulating the instructions needed to perform a task. In most cases the task will need some input data for it to work with. Use parameters to provide data to your procedures.,2,0,FALSE,"[{""key"":""file0"",""name"":""Shape Drawing Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 2.4 - My Functions,2.4P,Using functions you can now create artefacts to encapsulate the steps needed to calculate a value.,4,0,FALSE,"[{""key"":""file0"",""name"":""My Function Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, +Credit Task 2.5 - Concept Maps,2.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",2,Tue,3,Tue,,,5,FALSE,90,,,import-tasks,,, +Pass Task 3.1 - Hand Execution of Control Flow,3.1P,In this task you will use the hand execution process to demonstrate how the control flow constructs operate within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Button Code"",""type"":""code""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 3.2 - Name Tester,3.2P,Control flow enables you to easily add conditions and loops to your programs. In this task you will create a small program that uses conditions and loops to output custom messages to users.,4,0,FALSE,"[{""key"":""file0"",""name"":""Name Tester code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 3.3 - Circle Moving,3.3P,In this task you will create a small program that allows the user to move a circle around on the screen.,4,0,FALSE,"[{""key"":""file0"",""name"":""Circle Mover code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,import-tasks,,, +Credit Task 3.4 - User Input Functions,3.4C,So far we have provided you with a unit to read and check values entered by the user: the Terminal User Input unit. In this task you will extend this library so that it has a number of additional functions.,4,1,FALSE,"[{""key"":""file0"",""name"":""User Input unit code"",""type"":""code""},{""key"":""file1"",""name"":""Program code"",""type"":""code""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,,import-tasks,,, +Credit Task 3.5 - Concept Map,3.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",3,Tue,4,Tue,,,0,FALSE,90,,,import-tasks,,, +Distinction Task 3.6 - Mandelbrot,3.6D,The Mandelbrot provides an interesting challenge in order to determine how to zoom in to and out of the section of the Mandelbrot being shown to the user.,4,2,FALSE,"[{""key"":""file0"",""name"":""Mandelbrot code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,,import-tasks,,, +Pass Task 4.1 - Using Records and Enumerations,4.1P,Effectively organising your data makes programs much easier to develop. By using records and enumerations you can start to model the entities associated with your programs.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,7,Mon,0,FALSE,90,,,import-tasks,,, +Credit Task 4.2 - Fruit Punch,4.2C,Create a program using the concepts covered so far.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,,,0,FALSE,90,,,import-tasks,,, +Credit Task 4.3 - Concept Map,4.3C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",4,Tue,5,Tue,,,0,FALSE,90,,,import-tasks,,, +Test 1,T1,Test 1 covers weeks 1 to 3,1,0,TRUE,[],5,Fri,5,Fri,,,0,FALSE,90,,,import-tasks,,, +Pass Task 5.1 - Hand Execution of Arrays,5.1P,Demonstrate how arrays work within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 5.2 - Arrays of Records,5.2P,Add an array of records to your program that uses records.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,,import-tasks,,, +Credit Task 5.3 - Food Hunter,5.3C,Extend a small game to make use of arrays.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,,import-tasks,,, +Credit Task 5.4 - Concept Map,5.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",5,Tue,6,Tue,,,0,FALSE,90,,,import-tasks,,, +Distinction Task 5.5 - Sort Visualiser,5.5D,Create a program to demonstrate sorting working within the computer.,4,2,FALSE,"[{""key"":""file0"",""name"":""Sort Visualiser"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,,import-tasks,,, +Pass Task 6.1 - Structure Charts,6.1P,Illustrate the structure of your program using a structure chart.,2,0,FALSE,"[{""key"":""file0"",""name"":""Program structrue chart"",""type"":""image""}]",6,Tue,7,Tue,10,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 7.1 - Programming Principles,7.1P,"Describe the principles of structured, procedural, programming.",4,0,FALSE,"[{""key"":""file0"",""name"":""Program Principles Description"",""type"":""document""}]",7,Tue,8,Tue,10,Mon,0,FALSE,90,,,import-tasks,,, +Distinction Task 7.2 - Game of Life,7.2D,Create the Game of Life,4,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",7,Tue,8,Tue,,,0,FALSE,90,,,import-tasks,,, +Pass Task 8.1 - Language Reference Sheet,8.1P,Create a reference sheet for C or C#,4,0,FALSE,"[{""key"":""file0"",""name"":""Reference Sheet"",""type"":""document""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,,import-tasks,,, +Pass Task 8.2 - Circle Moving 2,8.2P,Recreate your circle moving program using C,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,,import-tasks,,, +Test 2,T2,Covers all core concepts.,1,0,TRUE,[],9,Fri,9,Fri,,,0,FALSE,90,,,import-tasks,,, +Pass Task 9.1 - Reading Another Language,9.1P,Demonstrate how programs written in C work within the computer,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,,import-tasks,,, +Credit Task 9.2 - Another Language,9.2C,Create a program with C using the concepts covered.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,,import-tasks,,, +High Distinction Task 10.1 - Custom Program,10.1H,Extend your custom program to meet the High Distinction criteria.,4,3,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",10,Tue,13,Tue,,,0,FALSE,90,,,import-tasks,,, +High Distinction Task 10.2 - Research Report,10.2H,Start working on a research project,8,3,FALSE,"[{""key"":""file0"",""name"":""Research Report Document"",""type"":""document""}]",10,Tue,13,Tue,,,0,FALSE,90,,,import-tasks,,, +Pass Task 11.1 - Learning Summary Report,11.1P,Summarise your learning from the unit.,4,0,FALSE,"[{""key"":""file0"",""name"":""Learning Summary Report"",""type"":""document""}]",11,Tue,12,Tue,,,0,FALSE,90,,,import-tasks,,, +Distinction Task 6.2 - Custom Program,6.2D,Start working on your custom program!,16,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",6,Tue,13,Tue,,,5,TRUE,90,,,import-tasks,,, diff --git a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv index c44b12a4b..aac958d5e 100644 --- a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv @@ -1,37 +1,37 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream -Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,, -Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,, -Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,, -Credit Task 1.4 - Concept Map,1.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",1,Tue,2,Tue,,,0,FALSE,90,,, -Pass Task 2.1 - Hand Execute Assignment,2.1P,"Using the assignment statement, you can assign a value to a variable. In this task you will demonstrate how this action works within the computer.",2,0,FALSE,"[{""key"":""file0"",""name"":""Program Execution 1"",""type"":""image""},{""key"":""file1"",""name"":""Program Execution 2"",""type"":""image""},{""key"":""file2"",""name"":""Program Execution 3"",""type"":""image""},{""key"":""file3"",""name"":""Program Execution 4"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,, -Pass Task 2.2 - Hello User,2.2P,Now that we have variables we can create a program that reads in the users name from the Terminal and echoes back a welcome message.,4,0,FALSE,"[{""key"":""file0"",""name"":""HelloUser.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,, -Pass Task 2.3 - My Drawing Procedure,2.3P,Procedures are a great way of encapsulating the instructions needed to perform a task. In most cases the task will need some input data for it to work with. Use parameters to provide data to your procedures.,2,0,FALSE,"[{""key"":""file0"",""name"":""Shape Drawing Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,, -Pass Task 2.4 - My Functions,2.4P,Using functions you can now create artefacts to encapsulate the steps needed to calculate a value.,4,0,FALSE,"[{""key"":""file0"",""name"":""My Function Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,, -Credit Task 2.5 - Concept Maps,2.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",2,Tue,3,Tue,,,5,FALSE,90,,, -Pass Task 3.1 - Hand Execution of Control Flow,3.1P,In this task you will use the hand execution process to demonstrate how the control flow constructs operate within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Button Code"",""type"":""code""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,, -Pass Task 3.2 - Name Tester,3.2P,Control flow enables you to easily add conditions and loops to your programs. In this task you will create a small program that uses conditions and loops to output custom messages to users.,4,0,FALSE,"[{""key"":""file0"",""name"":""Name Tester code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,, -Pass Task 3.3 - Circle Moving,3.3P,In this task you will create a small program that allows the user to move a circle around on the screen.,4,0,FALSE,"[{""key"":""file0"",""name"":""Circle Mover code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,, -Credit Task 3.4 - User Input Functions,3.4C,So far we have provided you with a unit to read and check values entered by the user: the Terminal User Input unit. In this task you will extend this library so that it has a number of additional functions.,4,1,FALSE,"[{""key"":""file0"",""name"":""User Input unit code"",""type"":""code""},{""key"":""file1"",""name"":""Program code"",""type"":""code""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,, -Credit Task 3.5 - Concept Map,3.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",3,Tue,4,Tue,,,0,FALSE,90,,, -Distinction Task 3.6 - Mandelbrot,3.6D,The Mandelbrot provides an interesting challenge in order to determine how to zoom in to and out of the section of the Mandelbrot being shown to the user.,4,2,FALSE,"[{""key"":""file0"",""name"":""Mandelbrot code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,, -Pass Task 4.1 - Using Records and Enumerations,4.1P,Effectively organising your data makes programs much easier to develop. By using records and enumerations you can start to model the entities associated with your programs.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,7,Mon,0,FALSE,90,,, -Credit Task 4.2 - Fruit Punch,4.2C,Create a program using the concepts covered so far.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,,,0,FALSE,90,,, -Credit Task 4.3 - Concept Map,4.3C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",4,Tue,5,Tue,,,0,FALSE,90,,, -Test 1,T1,Test 1 covers weeks 1 to 3,1,0,TRUE,[],5,Fri,5,Fri,,,0,FALSE,90,,, -Pass Task 5.1 - Hand Execution of Arrays,5.1P,Demonstrate how arrays work within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,, -Pass Task 5.2 - Arrays of Records,5.2P,Add an array of records to your program that uses records.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,, -Credit Task 5.3 - Food Hunter,5.3C,Extend a small game to make use of arrays.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,, -Credit Task 5.4 - Concept Map,5.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",5,Tue,6,Tue,,,0,FALSE,90,,, -Distinction Task 5.5 - Sort Visualiser,5.5D,Create a program to demonstrate sorting working within the computer.,4,2,FALSE,"[{""key"":""file0"",""name"":""Sort Visualiser"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,, -Pass Task 6.1 - Structure Charts,6.1P,Illustrate the structure of your program using a structure chart.,2,0,FALSE,"[{""key"":""file0"",""name"":""Program structrue chart"",""type"":""image""}]",6,Tue,7,Tue,10,Mon,0,FALSE,90,,, -Pass Task 7.1 - Programming Principles,7.1P,"Describe the principles of structured, procedural, programming.",4,0,FALSE,"[{""key"":""file0"",""name"":""Program Principles Description"",""type"":""document""}]",7,Tue,8,Tue,10,Mon,0,FALSE,90,,, -Distinction Task 7.2 - Game of Life,7.2D,Create the Game of Life,4,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",7,Tue,8,Tue,,,0,FALSE,90,,, -Pass Task 8.1 - Language Reference Sheet,8.1P,Create a reference sheet for C or C#,4,0,FALSE,"[{""key"":""file0"",""name"":""Reference Sheet"",""type"":""document""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,, -Pass Task 8.2 - Circle Moving 2,8.2P,Recreate your circle moving program using C,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,, -Test 2,T2,Covers all core concepts.,1,0,TRUE,[],9,Fri,9,Fri,,,0,FALSE,90,,, -Pass Task 9.1 - Reading Another Language,9.1P,Demonstrate how programs written in C work within the computer,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,, -Credit Task 9.2 - Another Language,9.2C,Create a program with C using the concepts covered.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,, -High Distinction Task 10.1 - Custom Program,10.1H,Extend your custom program to meet the High Distinction criteria.,4,3,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",10,Tue,13,Tue,,,0,FALSE,90,,, -High Distinction Task 10.2 - Research Report,10.2H,Start working on a research project,8,3,FALSE,"[{""key"":""file0"",""name"":""Research Report Document"",""type"":""document""}]",10,Tue,13,Tue,,,0,FALSE,90,,, -Pass Task 11.1 - Learning Summary Report,11.1P,Summarise your learning from the unit.,4,0,FALSE,"[{""key"":""file0"",""name"":""Learning Summary Report"",""type"":""document""}]",11,Tue,12,Tue,,,0,FALSE,90,,, -Distinction Task 6.2 - Custom Program,6.2D,Start working on your custom program!,16,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",6,Tue,13,Tue,,,5,TRUE,90,,, \ No newline at end of file +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, +Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, +Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, +Credit Task 1.4 - Concept Map,1.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",1,Tue,2,Tue,,,0,FALSE,90,,,,,, +Pass Task 2.1 - Hand Execute Assignment,2.1P,"Using the assignment statement, you can assign a value to a variable. In this task you will demonstrate how this action works within the computer.",2,0,FALSE,"[{""key"":""file0"",""name"":""Program Execution 1"",""type"":""image""},{""key"":""file1"",""name"":""Program Execution 2"",""type"":""image""},{""key"":""file2"",""name"":""Program Execution 3"",""type"":""image""},{""key"":""file3"",""name"":""Program Execution 4"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,,,, +Pass Task 2.2 - Hello User,2.2P,Now that we have variables we can create a program that reads in the users name from the Terminal and echoes back a welcome message.,4,0,FALSE,"[{""key"":""file0"",""name"":""HelloUser.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,,,, +Pass Task 2.3 - My Drawing Procedure,2.3P,Procedures are a great way of encapsulating the instructions needed to perform a task. In most cases the task will need some input data for it to work with. Use parameters to provide data to your procedures.,2,0,FALSE,"[{""key"":""file0"",""name"":""Shape Drawing Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,,,, +Pass Task 2.4 - My Functions,2.4P,Using functions you can now create artefacts to encapsulate the steps needed to calculate a value.,4,0,FALSE,"[{""key"":""file0"",""name"":""My Function Code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",2,Tue,3,Tue,5,Mon,0,FALSE,90,,,,,, +Credit Task 2.5 - Concept Maps,2.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",2,Tue,3,Tue,,,5,FALSE,90,,,,,, +Pass Task 3.1 - Hand Execution of Control Flow,3.1P,In this task you will use the hand execution process to demonstrate how the control flow constructs operate within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Button Code"",""type"":""code""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,,,, +Pass Task 3.2 - Name Tester,3.2P,Control flow enables you to easily add conditions and loops to your programs. In this task you will create a small program that uses conditions and loops to output custom messages to users.,4,0,FALSE,"[{""key"":""file0"",""name"":""Name Tester code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,,,, +Pass Task 3.3 - Circle Moving,3.3P,In this task you will create a small program that allows the user to move a circle around on the screen.,4,0,FALSE,"[{""key"":""file0"",""name"":""Circle Mover code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,7,Mon,0,FALSE,90,,,,,, +Credit Task 3.4 - User Input Functions,3.4C,So far we have provided you with a unit to read and check values entered by the user: the Terminal User Input unit. In this task you will extend this library so that it has a number of additional functions.,4,1,FALSE,"[{""key"":""file0"",""name"":""User Input unit code"",""type"":""code""},{""key"":""file1"",""name"":""Program code"",""type"":""code""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,,,,, +Credit Task 3.5 - Concept Map,3.5C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",3,Tue,4,Tue,,,0,FALSE,90,,,,,, +Distinction Task 3.6 - Mandelbrot,3.6D,The Mandelbrot provides an interesting challenge in order to determine how to zoom in to and out of the section of the Mandelbrot being shown to the user.,4,2,FALSE,"[{""key"":""file0"",""name"":""Mandelbrot code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",3,Tue,4,Tue,,,0,FALSE,90,,,,,, +Pass Task 4.1 - Using Records and Enumerations,4.1P,Effectively organising your data makes programs much easier to develop. By using records and enumerations you can start to model the entities associated with your programs.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,7,Mon,0,FALSE,90,,,,,, +Credit Task 4.2 - Fruit Punch,4.2C,Create a program using the concepts covered so far.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",4,Tue,5,Tue,,,0,FALSE,90,,,,,, +Credit Task 4.3 - Concept Map,4.3C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",4,Tue,5,Tue,,,0,FALSE,90,,,,,, +Test 1,T1,Test 1 covers weeks 1 to 3,1,0,TRUE,[],5,Fri,5,Fri,,,0,FALSE,90,,,,,, +Pass Task 5.1 - Hand Execution of Arrays,5.1P,Demonstrate how arrays work within the computer.,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,,,,, +Pass Task 5.2 - Arrays of Records,5.2P,Add an array of records to your program that uses records.,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,10,Mon,0,FALSE,90,,,,,, +Credit Task 5.3 - Food Hunter,5.3C,Extend a small game to make use of arrays.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,,,,, +Credit Task 5.4 - Concept Map,5.4C,A concept map visually shows the relationships between concepts. This task aims to help you think through the various relationships between the structured procedural programming concepts and the associated programming artefacts.,4,1,FALSE,"[{""key"":""file0"",""name"":""Concept map"",""type"":""document""}]",5,Tue,6,Tue,,,0,FALSE,90,,,,,, +Distinction Task 5.5 - Sort Visualiser,5.5D,Create a program to demonstrate sorting working within the computer.,4,2,FALSE,"[{""key"":""file0"",""name"":""Sort Visualiser"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",5,Tue,6,Tue,,,0,FALSE,90,,,,,, +Pass Task 6.1 - Structure Charts,6.1P,Illustrate the structure of your program using a structure chart.,2,0,FALSE,"[{""key"":""file0"",""name"":""Program structrue chart"",""type"":""image""}]",6,Tue,7,Tue,10,Mon,0,FALSE,90,,,,,, +Pass Task 7.1 - Programming Principles,7.1P,"Describe the principles of structured, procedural, programming.",4,0,FALSE,"[{""key"":""file0"",""name"":""Program Principles Description"",""type"":""document""}]",7,Tue,8,Tue,10,Mon,0,FALSE,90,,,,,, +Distinction Task 7.2 - Game of Life,7.2D,Create the Game of Life,4,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",7,Tue,8,Tue,,,0,FALSE,90,,,,,, +Pass Task 8.1 - Language Reference Sheet,8.1P,Create a reference sheet for C or C#,4,0,FALSE,"[{""key"":""file0"",""name"":""Reference Sheet"",""type"":""document""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,,,,, +Pass Task 8.2 - Circle Moving 2,8.2P,Recreate your circle moving program using C,4,0,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",8,Tue,9,Tue,10,Mon,0,FALSE,90,,,,,, +Test 2,T2,Covers all core concepts.,1,0,TRUE,[],9,Fri,9,Fri,,,0,FALSE,90,,,,,, +Pass Task 9.1 - Reading Another Language,9.1P,Demonstrate how programs written in C work within the computer,2,0,FALSE,"[{""key"":""file0"",""name"":""Execution of Program 1"",""type"":""image""},{""key"":""file1"",""name"":""Execution of Program 2"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,,,,, +Credit Task 9.2 - Another Language,9.2C,Create a program with C using the concepts covered.,4,1,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",9,Tue,10,Tue,,,0,FALSE,90,,,,,, +High Distinction Task 10.1 - Custom Program,10.1H,Extend your custom program to meet the High Distinction criteria.,4,3,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",10,Tue,13,Tue,,,0,FALSE,90,,,,,, +High Distinction Task 10.2 - Research Report,10.2H,Start working on a research project,8,3,FALSE,"[{""key"":""file0"",""name"":""Research Report Document"",""type"":""document""}]",10,Tue,13,Tue,,,0,FALSE,90,,,,,, +Pass Task 11.1 - Learning Summary Report,11.1P,Summarise your learning from the unit.,4,0,FALSE,"[{""key"":""file0"",""name"":""Learning Summary Report"",""type"":""document""}]",11,Tue,12,Tue,,,0,FALSE,90,,,,,, +Distinction Task 6.2 - Custom Program,6.2D,Start working on your custom program!,16,2,FALSE,"[{""key"":""file0"",""name"":""Program code"",""type"":""code""},{""key"":""file1"",""name"":""Design overview"",""type"":""document""},{""key"":""file2"",""name"":""Screenshot"",""type"":""image""}]",6,Tue,13,Tue,,,5,TRUE,90,,,,,, diff --git a/test_files/csv_test_files/COS10001-Tasks.csv b/test_files/csv_test_files/COS10001-Tasks.csv index fc9930340..3560d3695 100644 --- a/test_files/csv_test_files/COS10001-Tasks.csv +++ b/test_files/csv_test_files/COS10001-Tasks.csv @@ -1,2 +1,2 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day -Assignment 12,A12,rerum ut fugit saepe ipsa in quidem,2,0,FALSE,0,FALSE,50,[],,"[{""key"":""file0"",""name"":""Assumenda accusamus quas"",""type"":""image""}]",-1,Sat,1,Mon,13,Mon \ No newline at end of file +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +Assignment 12,A12,rerum ut fugit saepe ipsa in quidem,2,0,FALSE,0,FALSE,50,[],,"[{""key"":""file0"",""name"":""Assumenda accusamus quas"",""type"":""image""}]",-1,Sat,1,Mon,13,Mon,,, diff --git a/test_files/csv_test_files/COS10001-Tasks.xlsx b/test_files/csv_test_files/COS10001-Tasks.xlsx index 49839ecf8f4239b18c46ee9fbe1e339a7d2d96c3..4ca8b1c63e9168a3ff159adaf95c318155a2e209 100644 GIT binary patch literal 6646 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 TbVxBU2+$h>-IkbXE|2~PTfszt literal 10335 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 Date: Tue, 30 Apr 2024 13:03:51 +1000 Subject: [PATCH 018/124] fix: use correct endpoint url and include exam result for numbas test attempts --- app/api/test_attempts_api.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 803f14dc6..f93a1d3ee 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -35,7 +35,7 @@ class TestAttemptEntity < Grape::Entity # Fetch all test results desc 'Get all test results' - get do + get '/test_attempts' do tests = TestAttempt.order(id: :desc) present tests, with: TestAttemptEntity end @@ -136,7 +136,7 @@ class TestAttemptEntity < Grape::Entity optional :exam_result, type: String, desc: 'Result of the exam' optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' end - post do + post '/test_attempts' do test = TestAttempt.create!(declared(params)) present test, with: TestAttemptEntity end @@ -149,6 +149,7 @@ class TestAttemptEntity < Grape::Entity optional :pass_status, type: Boolean, desc: 'Passing status' optional :exam_data, type: String, desc: 'Data related to the exam' optional :completed, type: Boolean, desc: 'Completion status' + optional :exam_result, type: String, desc: 'Exam score' optional :cmi_entry, type: String, desc: 'CMI Entry' optional :task_id, type: Integer, desc: 'ID of the associated task' end From a7c400669bf199f30b627b54c4ed49157ff88222 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:18:47 +1000 Subject: [PATCH 019/124] fix: use test attempt entity in file instead --- app/api/test_attempts_api.rb | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index f93a1d3ee..ad8e64f0b 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -3,14 +3,12 @@ class TestAttemptsApi < Grape::API format :json - # Enforce authentication + helpers AuthenticationHelpers + before do authenticated? end - # Assigning AuthenticationHelpers - helpers AuthenticationHelpers - # Handle common exceptions rescue_from :all do |e| error!({ error: e.message }, 500) @@ -26,18 +24,11 @@ class TestAttemptsApi < Grape::API error!({ errors: e.full_messages }, 400) end - # Define the TestAttemptEntity - class TestAttemptEntity < Grape::Entity - expose :id, :name, :attempt_number, :pass_status, :exam_data, :completed, :cmi_entry - expose :task_id, as: :associated_task_id - expose :exam_result, :attempted_at - end - # Fetch all test results desc 'Get all test results' get '/test_attempts' do tests = TestAttempt.order(id: :desc) - present tests, with: TestAttemptEntity + present tests, with: Entities::TestAttemptEntity end # Get latest test or create a new one based on completion status @@ -84,7 +75,7 @@ class TestAttemptEntity < Grape::Entity test.update!(cmi_entry: 'resume') end - present test, with: TestAttemptEntity + present test, with: Entities::TestAttemptEntity end # Fetch the latest completed test result @@ -110,7 +101,7 @@ class TestAttemptEntity < Grape::Entity if test.nil? error!({ message: 'No completed tests found for this task' }, 404) else - present test, with: TestAttemptEntity + present test, with: Entities::TestAttemptEntity end end @@ -120,7 +111,7 @@ class TestAttemptEntity < Grape::Entity requires :id, type: String, desc: 'ID of the test' end get '/test_attempts/:id' do - present TestAttempt.find(params[:id]), with: TestAttemptEntity + present TestAttempt.find(params[:id]), with: Entities::TestAttemptEntity end # Create a new test result entry @@ -138,7 +129,7 @@ class TestAttemptEntity < Grape::Entity end post '/test_attempts' do test = TestAttempt.create!(declared(params)) - present test, with: TestAttemptEntity + present test, with: Entities::TestAttemptEntity end # Update the details of a specific test result @@ -156,7 +147,7 @@ class TestAttemptEntity < Grape::Entity put '/test_attempts/:id' do test = TestAttempt.find(params[:id]) test.update!(declared(params, include_missing: false)) - present test, with: TestAttemptEntity + present test, with: Entities::TestAttemptEntity end # Delete a specific test result by ID From b4d3f9dc1661b733eaf704c551ceb5836789db22 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Sat, 4 May 2024 22:14:02 +1000 Subject: [PATCH 020/124] fix: temporarily disable auth and fix test attempt lookup --- app/api/numbas_api.rb | 7 +++---- app/api/test_attempts_api.rb | 8 +------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/app/api/numbas_api.rb b/app/api/numbas_api.rb index e422afac8..af711a9bc 100644 --- a/app/api/numbas_api.rb +++ b/app/api/numbas_api.rb @@ -5,9 +5,9 @@ class NumbasApi < Grape::API # Include the AuthenticationHelpers for authentication functionality helpers AuthenticationHelpers - before do - authenticated? - end + # before do + # authenticated? + # end helpers do # Method to stream a file from a zip archive at the specified path @@ -25,7 +25,6 @@ def stream_file_from_zip(zip_path, file_path) file_stream = entry.get_input_stream break end - logger.debug "Requested file #{file_path} not found from numbas container" end end diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index ad8e64f0b..1b69d4eb1 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -3,12 +3,6 @@ class TestAttemptsApi < Grape::API format :json - helpers AuthenticationHelpers - - before do - authenticated? - end - # Handle common exceptions rescue_from :all do |e| error!({ error: e.message }, 500) @@ -43,7 +37,7 @@ class TestAttemptsApi < Grape::API error!({ message: 'Task ID is invalid' }, 404) return else - test_attempts = TestAttempt.find_by(task_id: :task_id) + test_attempts = TestAttempt.where("task_id = ?", params[:task_id]) end # Take the latest test attempt if there are any for this task From e650ef19d08b3fb31c93ef53eb4a82f80ff9a612 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sun, 5 May 2024 16:28:12 +1000 Subject: [PATCH 021/124] refactor: modify test attempt files to match PoC --- app/api/entities/test_attempt_entity.rb | 13 +- app/api/test_attempts_api.rb | 284 +++++++++--------- .../20231205011842_create_test_attempts.rb | 2 +- db/schema.rb | 2 +- 4 files changed, 154 insertions(+), 147 deletions(-) diff --git a/app/api/entities/test_attempt_entity.rb b/app/api/entities/test_attempt_entity.rb index 796bb1420..b522f4774 100644 --- a/app/api/entities/test_attempt_entity.rb +++ b/app/api/entities/test_attempt_entity.rb @@ -1,7 +1,14 @@ module Entities class TestAttemptEntity < Grape::Entity - expose :id, :name, :attempt_number, :pass_status, :exam_data, :completed, :cmi_entry - expose :task_id, as: :associated_task_id - expose :exam_result, :attempted_at + expose :id + expose :name + expose :attempt_number + expose :pass_status + expose :suspend_data + expose :completed + expose :cmi_entry + expose :exam_result + expose :attempted_at + expose :task_id end end diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 1b69d4eb1..3eba39430 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -3,178 +3,178 @@ class TestAttemptsApi < Grape::API format :json + helpers AuthenticationHelpers + + # before do + # authenticated? + # end + # Handle common exceptions rescue_from :all do |e| error!({ error: e.message }, 500) end - # Specific exception handler for record not found rescue_from ActiveRecord::RecordNotFound do |e| error!({ error: e.message }, 404) end - # Handling validation errors from Grape rescue_from Grape::Exceptions::ValidationErrors do |e| error!({ errors: e.full_messages }, 400) end - # Fetch all test results - desc 'Get all test results' - get '/test_attempts' do - tests = TestAttempt.order(id: :desc) - present tests, with: Entities::TestAttemptEntity - end + resources :test_attempts do + # Fetch all test results, ordered by ID in descending order + desc 'Get all test results' + get do + tests = TestAttempt.order(id: :desc) + present :data, tests, with: Entities::TestAttemptEntity + end - # Get latest test or create a new one based on completion status - desc 'Get latest test attempt for a specific task or create a new one based on completion status' - params do - requires :task_id, type: Integer, desc: 'Task ID to fetch test attempts for' - end - get '/test_attempts/latest' do - # Ensure task exists - task = Task.find(params[:task_id]) - if task.nil? - error!({ message: 'Task ID is invalid' }, 404) - return - else - test_attempts = TestAttempt.where("task_id = ?", params[:task_id]) + # Get latest test or create a new one based on completion status + desc 'Get latest test attempt for a specific task or create a new one based on completion status' + params do + requires :task_id, type: Integer, desc: 'Task ID to fetch test attempts for' end + get 'latest' do + # Ensure task exists + task = Task.find(params[:task_id]) + if task.nil? + error!({ message: 'Task ID is invalid' }, 404) + return + else + test_attempts = TestAttempt.where("task_id = ?", params[:task_id]) + end - # Take the latest test attempt if there are any for this task - unless test_attempts.nil? test = test_attempts.order(id: :desc).first - end - if test.nil? - test = TestAttempt.create!( - name: "Default Test", - attempt_number: 1, - pass_status: false, - exam_data: nil, - completed: false, - cmi_entry: 'ab-initio', - task_id: params[:task_id] - ) - elsif test.completed - test = TestAttempt.create!( - name: "Default Test", - attempt_number: test.attempt_number + 1, - pass_status: false, - exam_data: nil, - completed: false, - cmi_entry: 'ab-initio', - task_id: params[:task_id] - ) - else - test.update!(cmi_entry: 'resume') + if test.nil? + test = TestAttempt.create!( + name: "First Test", + attempt_number: 1, + pass_status: false, + suspend_data: nil, + completed: false, + cmi_entry: 'ab-initio', + attempted_at: DateTime.now, + task_id: params[:task_id] + ) + elsif test.completed + test = TestAttempt.create!( + name: "New Attempt", + attempt_number: test.attempt_number + 1, + pass_status: false, + suspend_data: nil, + completed: false, + cmi_entry: 'ab-initio', + attempted_at: DateTime.now, + task_id: params[:task_id] + ) + else + test.update!(cmi_entry: 'resume') + end + + present :data, test, with: Entities::TestAttemptEntity end - present test, with: Entities::TestAttemptEntity - end - - # Fetch the latest completed test result - desc 'Get the latest completed test result' - params do - requires :task_id, type: Integer, desc: 'Task ID to fetch completed test attempt for' - end - get '/test_attempts/completed-latest' do - # Ensure task exists - task = Task.find(params[:task_id]) - if task.nil? - error!({ message: 'Task ID is invalid' }, 404) - return - else - test_attempts = TestAttempt.find_by(task_id: :task_id) + # Fetch the latest completed test result + desc 'Get the latest completed test result' + params do + requires :task_id, type: Integer, desc: 'Task ID to fetch completed test attempt for' end + get 'completed-latest' do + # Ensure task exists + task = Task.find(params[:task_id]) + if task.nil? + error!({ message: 'Task ID is invalid' }, 404) + return + else + test_attempts = TestAttempt.where("task_id = ?", params[:task_id]) + end - # Take the latest completed test attempt if there are any for this task - unless test_attempts.nil? test = test_attempts.where(completed: true).order(id: :desc).first - end - if test.nil? - error!({ message: 'No completed tests found for this task' }, 404) - else - present test, with: Entities::TestAttemptEntity + if test.nil? + error!({ message: 'No completed tests found for this task' }, 404) + else + present :data, test, with: Entities::TestAttemptEntity + end end - end - # Fetch a specific test result by ID - desc 'Get a specific test result' - params do - requires :id, type: String, desc: 'ID of the test' - end - get '/test_attempts/:id' do - present TestAttempt.find(params[:id]), with: Entities::TestAttemptEntity - end + # Fetch a specific test result by ID + desc 'Get a specific test result' + params do + requires :id, type: String, desc: 'ID of the test' + end + get ':id' do + present TestAttempt.find(params[:id]), with: Entities::TestAttemptEntity + end - # Create a new test result entry - desc 'Create a new test result' - params do - requires :task_id, type: Integer, desc: 'ID of the associated task' - requires :name, type: String, desc: 'Name of the test' - requires :attempt_number, type: Integer, desc: 'Number of attempts' - requires :pass_status, type: Boolean, desc: 'Passing status' - optional :exam_data, type: String, desc: 'Data related to the exam' - requires :completed, type: Boolean, desc: 'Completion status' - optional :cmi_entry, type: String, desc: 'CMI Entry', default: "ab-initio" - optional :exam_result, type: String, desc: 'Result of the exam' - optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' - end - post '/test_attempts' do - test = TestAttempt.create!(declared(params)) - present test, with: Entities::TestAttemptEntity - end + # Create a new test result entry + desc 'Create a new test result' + params do + requires :name, type: String, desc: 'Name of the test' + requires :attempt_number, type: Integer, desc: 'Number of attempts' + requires :pass_status, type: Boolean, desc: 'Passing status' + requires :suspend_data, type: String, desc: 'Suspended data in JSON' + requires :completed, type: Boolean, desc: 'Completion status' + optional :cmi_entry, type: String, desc: 'CMI Entry', default: "ab-initio" + optional :exam_result, type: String, desc: 'Result of the exam' + optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' + requires :task_id, type: Integer, desc: 'ID of the associated task' + end + post do + test = TestAttempt.create!(params) + present :data, test, with: Entities::TestAttemptEntity + end - # Update the details of a specific test result - desc 'Update a test result' - params do - optional :name, type: String, desc: 'Name of the test' - optional :attempt_number, type: Integer, desc: 'Number of attempts' - optional :pass_status, type: Boolean, desc: 'Passing status' - optional :exam_data, type: String, desc: 'Data related to the exam' - optional :completed, type: Boolean, desc: 'Completion status' - optional :exam_result, type: String, desc: 'Exam score' - optional :cmi_entry, type: String, desc: 'CMI Entry' - optional :task_id, type: Integer, desc: 'ID of the associated task' - end - put '/test_attempts/:id' do - test = TestAttempt.find(params[:id]) - test.update!(declared(params, include_missing: false)) - present test, with: Entities::TestAttemptEntity - end + # Update the details of a specific test result + desc 'Update a test result' + params do + requires :id, type: String, desc: 'ID of the test' + optional :name, type: String, desc: 'Name of the test' + optional :attempt_number, type: Integer, desc: 'Number of attempts' + optional :pass_status, type: Boolean, desc: 'Passing status' + optional :suspend_data, type: String, desc: 'Suspended data in JSON' + optional :completed, type: Boolean, desc: 'Completion status' + optional :exam_result, type: String, desc: 'Exam score' + optional :cmi_entry, type: String, desc: 'CMI Entry' + optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' + end + put ':id' do + TestAttempt.find(params[:id]).update!(params.except(:id)) + end - # Delete a specific test result by ID - desc 'Delete a test result' - params do - requires :id, type: String, desc: 'ID of the test' - end - delete '/test_attempts/:id' do - TestAttempt.find(params[:id]).destroy! - end + # Delete a specific test result by ID + desc 'Delete a test result' + params do + requires :id, type: String, desc: 'ID of the test' + end + delete ':id' do + TestAttempt.find(params[:id]).destroy! + end - # Update the exam_data of a specific test result - desc 'Update exam data for a test result' - params do - requires :id, type: String, desc: 'ID of the test' - end - put '/test_attempts/:id/exam_data' do - test = TestAttempt.find_by(id: params[:id]) - - error!('Test not found', 404) unless test - - # Treat the entire params as the data to be saved - exam_data = params.to_json - - begin - JSON.parse(exam_data) - test.update!(exam_data: exam_data) - { message: 'Exam data updated successfully', test: test } - rescue JSON::ParserError - error!('Invalid JSON provided', 400) - rescue StandardError => e - error!(e.message, 500) + # Update the suspend_data of a specific test result + desc 'Update suspend data for a test result' + params do + requires :id, type: String, desc: 'ID of the test' + requires :suspend_data, type: Hash, desc: 'Suspend data to be saved' + end + put ':id/suspend' do + test = TestAttempt.find_by(id: params[:id]) + + error!('Test not found', 404) unless test + + suspend_data = params[:suspend_data].to_json + + begin + JSON.parse(suspend_data) + test.update!(suspend_data: suspend_data) + { message: 'Suspend data updated successfully', test: test } + rescue JSON::ParserError + error!('Invalid JSON provided', 400) + rescue => e + error!(e.message, 500) + end end end - end diff --git a/db/migrate/20231205011842_create_test_attempts.rb b/db/migrate/20231205011842_create_test_attempts.rb index 8430b8a8d..fc112bcb2 100644 --- a/db/migrate/20231205011842_create_test_attempts.rb +++ b/db/migrate/20231205011842_create_test_attempts.rb @@ -5,7 +5,7 @@ def change t.string :name t.integer :attempt_number, default: 1, null: false t.boolean :pass_status - t.text :exam_data + t.text :suspend_data t.boolean :completed, default: false t.datetime :attempted_at t.string :cmi_entry, default: "ab-initio" diff --git a/db/schema.rb b/db/schema.rb index a6b0f6cae..eb29b90d5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -352,7 +352,7 @@ t.string "name" t.integer "attempt_number", default: 1, null: false t.boolean "pass_status" - t.text "exam_data" + t.text "suspend_data" t.boolean "completed", default: false t.datetime "attempted_at" t.string "cmi_entry", default: "ab-initio" From 3f5aa2be6bd69441730375b689751fe881d7617a Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 7 May 2024 03:23:31 +1000 Subject: [PATCH 022/124] feat: add numbas task comment on test completion --- app/api/test_attempts_api.rb | 10 +++++++++- app/models/task.rb | 12 ++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 3eba39430..99e4c3d42 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -124,6 +124,10 @@ class TestAttemptsApi < Grape::API end post do test = TestAttempt.create!(params) + + task = Task.find(test.task_id) + task.add_numbas_comment(test) + present :data, test, with: Entities::TestAttemptEntity end @@ -141,7 +145,11 @@ class TestAttemptsApi < Grape::API optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' end put ':id' do - TestAttempt.find(params[:id]).update!(params.except(:id)) + test = TestAttempt.find(params[:id]) + test.update!(params.except(:id)) + + task = Task.find(test.task_id) + task.add_numbas_comment(test) end # Delete a specific test result by ID diff --git a/app/models/task.rb b/app/models/task.rb index e75815f90..44a55da72 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -668,6 +668,18 @@ def add_text_comment(user, text, reply_to_id = nil) comment end + def add_numbas_comment(test) + comment = TaskComment.create + comment.task = self + comment.user = self.tutor + comment.comment = "Numbas Attempt #{test.attempt_number} completed with score: #{test.exam_result}" + comment.content_type = 'numbas' + comment.recipient = project.student + comment.save! + + comment + end + def individual_task_or_submitter_of_group_task? return true if !group_task? # its individual return true unless group.present? # no group yet... so individual From 26d75f51b7fcf11dac0834ddc5a46f40c07407de Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 7 May 2024 07:08:01 +1000 Subject: [PATCH 023/124] feat: restrict test attempts by limit and comments to when test is completed --- app/api/test_attempts_api.rb | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 99e4c3d42..342f736ed 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -46,6 +46,12 @@ class TestAttemptsApi < Grape::API end test = test_attempts.order(id: :desc).first + + attempt_limit = task.task_definition.numbas_attempt_limit + if attempt_limit != 0 && test.present? && test.completed == true && test.attempt_number == attempt_limit + error!({ message: 'Attempt limit has been reached' }, 400) + return + end if test.nil? test = TestAttempt.create!( @@ -125,8 +131,10 @@ class TestAttemptsApi < Grape::API post do test = TestAttempt.create!(params) - task = Task.find(test.task_id) - task.add_numbas_comment(test) + if test.completed == true + task = Task.find(test.task_id) + task.add_numbas_comment(test) + end present :data, test, with: Entities::TestAttemptEntity end @@ -148,8 +156,10 @@ class TestAttemptsApi < Grape::API test = TestAttempt.find(params[:id]) test.update!(params.except(:id)) - task = Task.find(test.task_id) - task.add_numbas_comment(test) + if test.completed == true + task = Task.find(test.task_id) + task.add_numbas_comment(test) + end end # Delete a specific test result by ID From d9f640fd790b862bd5aa041775f692cd5c2d4b87 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Sun, 12 May 2024 08:41:25 +1000 Subject: [PATCH 024/124] refactor: rewrite test_attempt api and generalize scorm variables --- app/api/api_root.rb | 4 +- app/api/entities/numbas_entity.rb | 2 +- app/api/entities/task_definition_entity.rb | 9 +- app/api/entities/test_attempt_entity.rb | 15 +- app/api/{numbas_api.rb => scorm_api.rb} | 23 ++- app/api/task_definitions_api.rb | 54 +++--- app/api/test_attempts_api.rb | 176 +++++------------- app/models/task.rb | 8 +- app/models/task_definition.rb | 70 +++---- app/models/test_attempt.rb | 79 +++++++- .../20231205011842_create_test_attempts.rb | 14 +- ...0322021829_add_scorm_config_to_task_def.rb | 19 ++ ...021829_modify_numbas_fields_in_task_def.rb | 17 -- db/schema.rb | 22 +-- test/api/units/task_definitions_api_test.rb | 6 +- test/models/task_definition_test.rb | 2 +- ...COS10001-ImportTasksWithTutorialStream.csv | 2 +- ...10001-ImportTasksWithoutTutorialStream.csv | 2 +- test_files/COS10001-Tasks.csv | 2 +- test_files/csv_test_files/COS10001-Tasks.csv | 2 +- .../unit_csv_imports/import_group_tasks.csv | 2 +- 21 files changed, 261 insertions(+), 269 deletions(-) rename app/api/{numbas_api.rb => scorm_api.rb} (78%) create mode 100644 db/migrate/20240322021829_add_scorm_config_to_task_def.rb delete mode 100644 db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb diff --git a/app/api/api_root.rb b/app/api/api_root.rb index becca1574..030bd313d 100644 --- a/app/api/api_root.rb +++ b/app/api/api_root.rb @@ -76,7 +76,7 @@ class ApiRoot < Grape::API mount Tii::TiiGroupAttachmentApi mount Tii::TiiActionApi - mount NumbasApi + mount ScormApi mount TestAttemptsApi mount CampusesPublicApi mount CampusesAuthenticatedApi @@ -124,7 +124,7 @@ class ApiRoot < Grape::API AuthenticationHelpers.add_auth_to UnitRolesApi AuthenticationHelpers.add_auth_to UnitsApi AuthenticationHelpers.add_auth_to WebcalApi - AuthenticationHelpers.add_auth_to NumbasApi + AuthenticationHelpers.add_auth_to ScormApi AuthenticationHelpers.add_auth_to TestAttemptsApi add_swagger_documentation \ diff --git a/app/api/entities/numbas_entity.rb b/app/api/entities/numbas_entity.rb index ab0554219..07977ac3c 100644 --- a/app/api/entities/numbas_entity.rb +++ b/app/api/entities/numbas_entity.rb @@ -1,5 +1,5 @@ module Entities - class NumbasEntity < Grape::Entity + class ScormEntity < Grape::Entity expose :file_content, documentation: { type: 'string', desc: 'File content' } expose :content_type, documentation: { type: 'string', desc: 'Content type' } end diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index 9fda48f8e..f6549d3d0 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -39,10 +39,11 @@ def staff?(my_role) expose :has_task_sheet?, as: :has_task_sheet expose :has_task_resources?, as: :has_task_resources expose :has_task_assessment_resources?, as: :has_task_assessment_resources, if: ->(unit, options) { staff?(options[:my_role]) } - expose :has_numbas_data?, as: :has_numbas_data - expose :has_enabled_numbas_test - expose :has_numbas_time_delay, if: ->(unit, options) { staff?(options[:my_role]) } - expose :numbas_attempt_limit, if: ->(unit, options) { staff?(options[:my_role]) } + expose :has_scorm_data?, as: :has_scorm_data + expose :scorm_enabled + expose :scorm_allow_review + expose :scorm_time_delay_enabled, if: ->(unit, options) { staff?(options[:my_role]) } + expose :scorm_attempt_limit, if: ->(unit, options) { staff?(options[:my_role]) } expose :is_graded expose :max_quality_pts expose :overseer_image_id, if: ->(unit, options) { staff?(options[:my_role]) } diff --git a/app/api/entities/test_attempt_entity.rb b/app/api/entities/test_attempt_entity.rb index b522f4774..23f343790 100644 --- a/app/api/entities/test_attempt_entity.rb +++ b/app/api/entities/test_attempt_entity.rb @@ -1,14 +1,13 @@ module Entities class TestAttemptEntity < Grape::Entity expose :id - expose :name - expose :attempt_number - expose :pass_status - expose :suspend_data - expose :completed - expose :cmi_entry - expose :exam_result - expose :attempted_at expose :task_id + expose :attempted_time + expose :attempt_number + expose :terminated + expose :success_status + expose :score_scaled + expose :completion_status + expose :cmi_datamodel end end diff --git a/app/api/numbas_api.rb b/app/api/scorm_api.rb similarity index 78% rename from app/api/numbas_api.rb rename to app/api/scorm_api.rb index af711a9bc..89c7112cd 100644 --- a/app/api/numbas_api.rb +++ b/app/api/scorm_api.rb @@ -1,7 +1,7 @@ require 'grape' require 'zip' require 'mime/types' -class NumbasApi < Grape::API +class ScormApi < Grape::API # Include the AuthenticationHelpers for authentication functionality helpers AuthenticationHelpers @@ -20,11 +20,10 @@ def stream_file_from_zip(zip_path, file_path) # Get an input stream for the requested file within the ZIP archive Zip::File.open(zip_path) do |zip_file| zip_file.each do |entry| - if entry.name == file_path - logger.debug "Found file #{file_path} from numbas container" - file_stream = entry.get_input_stream - break - end + next unless entry.name == file_path + logger.debug "Found file #{file_path} from SCORM container" + file_stream = entry.get_input_stream + break end end @@ -48,19 +47,19 @@ def stream_file_from_zip(zip_path, file_path) end end - desc 'Serve numbas content' + desc 'Serve SCORM content' params do - requires :task_def_id, type: Integer, desc: 'Task Definition ID to get Numbas test data for' + requires :task_def_id, type: Integer, desc: 'Task Definition ID to get SCORM test data for' end - get '/numbas_api/:task_def_id/*file_path' do + get '/scorm/:task_def_id/*file_path' do env['api.format'] = :txt task_def = TaskDefinition.find(params[:task_def_id]) - if task_def.has_numbas_data? - zip_path = task_def.task_numbas_data + if task_def.has_scorm_data? + zip_path = task_def.task_scorm_data content_type 'application/octet-stream' stream_file_from_zip(zip_path, params[:file_path]) else - error!({ error: 'Numbas data does not exist.' }, 404) + error!({ error: 'SCORM data does not exist.' }, 404) end end end diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index eb59ce87b..eee95fb6d 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -28,9 +28,9 @@ class TaskDefinitionsApi < Grape::API requires :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' optional :upload_requirements, type: String, desc: 'Task file upload requirements' requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - requires :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' - requires :has_numbas_time_delay, type: Boolean, desc: 'Whether or not there is an incremental time delay between Numbas test attempts' - requires :numbas_attempt_limit, type: Integer, desc: 'The number of times a Numbas test can be attempted' + requires :scorm_enabled, type: Boolean, desc: 'Whether SCORM assessment is enabled for this task' + requires :scorm_time_delay_enabled, type: Boolean, desc: 'Whether there is an incremental time delay between SCORM test attempts' + requires :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' @@ -60,9 +60,9 @@ class TaskDefinitionsApi < Grape::API :abbreviation, :restrict_status_updates, :plagiarism_warn_pct, - :has_enabled_numbas_test, - :has_numbas_time_delay, - :numbas_attempt_limit, + :scorm_enabled, + :scorm_time_delay_enabled, + :scorm_attempt_limit, :is_graded, :max_quality_pts, :assessment_enabled, @@ -112,9 +112,9 @@ class TaskDefinitionsApi < Grape::API optional :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' optional :upload_requirements, type: String, desc: 'Task file upload requirements' optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - optional :has_enabled_numbas_test, type: Boolean, desc: 'Whether or not Numbas test assessment is enabled for this task' - optional :has_numbas_time_delay, type: Boolean, desc: 'Whether or not there is an incremental time delay between Numbas test attempts' - optional :numbas_attempt_limit, type: Integer, desc: 'The number of times a Numbas test can be attempted' + optional :scorm_enabled, type: Boolean, desc: 'Whether or not SCORM test assessment is enabled for this task' + optional :scorm_time_delay_enabled, type: Boolean, desc: 'Whether or not there is an incremental time delay between SCORM test attempts' + optional :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' @@ -143,9 +143,9 @@ class TaskDefinitionsApi < Grape::API :abbreviation, :restrict_status_updates, :plagiarism_warn_pct, - :has_enabled_numbas_test, - :has_numbas_time_delay, - :numbas_attempt_limit, + :scorm_enabled, + :scorm_time_delay_enabled, + :scorm_attempt_limit, :is_graded, :max_quality_pts, :assessment_enabled, @@ -627,17 +627,17 @@ class TaskDefinitionsApi < Grape::API stream_file path end - desc 'Upload the Numbas SCORM-2004 container (zip file) for a task' + desc 'Upload the SCORM container (zip file) for a task' params do requires :unit_id, type: Integer, desc: 'The related unit' requires :task_def_id, type: Integer, desc: 'The related task definition' - requires :file, type: File, desc: 'The Numbas data container' + requires :file, type: File, desc: 'The SCORM data container' end - post '/units/:unit_id/task_definitions/:task_def_id/numbas_data' do + post '/units/:unit_id/task_definitions/:task_def_id/scorm_data' do unit = Unit.find(params[:unit_id]) unless authorise? current_user, unit, :add_task_def - error!({ error: 'Not authorised to upload numbas test for the unit' }, 403) + error!({ error: 'Not authorised to upload SCORM data for the unit' }, 403) end task_def = unit.task_definitions.find(params[:task_def_id]) @@ -651,16 +651,16 @@ class TaskDefinitionsApi < Grape::API check_mime_against_list! file_path, 'zip', ['application/zip', 'multipart/x-gzip', 'multipart/x-zip', 'application/x-gzip', 'application/octet-stream'] # Actually import... - task_def.add_numbas_data(file_path) + task_def.add_scorm_data(file_path) true end - desc 'Download the Numbas test data' + desc 'Download the SCORM test data' params do requires :unit_id, type: Integer, desc: 'The unit to modify tasks for' - requires :task_def_id, type: Integer, desc: 'The task definition to get the Numbas test data of' + requires :task_def_id, type: Integer, desc: 'The task definition to get the SCORM test data of' end - get '/units/:unit_id/task_definitions/:task_def_id/numbas_data' do + get '/units/:unit_id/task_definitions/:task_def_id/scorm_data' do unit = Unit.find(params[:unit_id]) task_def = unit.task_definitions.find(params[:task_def_id]) @@ -668,10 +668,10 @@ class TaskDefinitionsApi < Grape::API error!({ error: 'Not authorised to download task details of unit' }, 403) end - if task_def.has_numbas_data? - path = task_def.task_numbas_data + if task_def.has_scorm_data? + path = task_def.task_scorm_data content_type 'application/octet-stream' - header['Content-Disposition'] = "attachment; filename=#{task_def.abbreviation}-numbas.zip" + header['Content-Disposition'] = "attachment; filename=#{task_def.abbreviation}-scorm.zip" else path = Rails.root.join('public', 'resources', 'FileNotFound.pdf') content_type 'application/pdf' @@ -683,22 +683,22 @@ class TaskDefinitionsApi < Grape::API File.read(path) end - desc 'Remove the Numbas test data for a given task' + desc 'Remove the SCORM test data for a given task' params do requires :unit_id, type: Integer, desc: 'The related unit' requires :task_def_id, type: Integer, desc: 'The related task definition' end - delete '/units/:unit_id/task_definitions/:task_def_id/numbas_data' do + delete '/units/:unit_id/task_definitions/:task_def_id/scorm_data' do unit = Unit.find(params[:unit_id]) unless authorise? current_user, unit, :add_task_def - error!({ error: 'Not authorised to remove task numbas data of unit' }, 403) + error!({ error: 'Not authorised to remove task SCORM data of unit' }, 403) end task_def = unit.task_definitions.find(params[:task_def_id]) # Actually remove... - task_def.remove_numbas_data + task_def.remove_scorm_data true end end diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 342f736ed..cb54c256e 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -23,176 +23,102 @@ class TestAttemptsApi < Grape::API end resources :test_attempts do - # Fetch all test results, ordered by ID in descending order - desc 'Get all test results' - get do - tests = TestAttempt.order(id: :desc) - present :data, tests, with: Entities::TestAttemptEntity - end - - # Get latest test or create a new one based on completion status - desc 'Get latest test attempt for a specific task or create a new one based on completion status' + desc 'Get all test results for a task' params do requires :task_id, type: Integer, desc: 'Task ID to fetch test attempts for' end - get 'latest' do - # Ensure task exists + get ':task_id' do task = Task.find(params[:task_id]) if task.nil? error!({ message: 'Task ID is invalid' }, 404) return else - test_attempts = TestAttempt.where("task_id = ?", params[:task_id]) - end - - test = test_attempts.order(id: :desc).first - - attempt_limit = task.task_definition.numbas_attempt_limit - if attempt_limit != 0 && test.present? && test.completed == true && test.attempt_number == attempt_limit - error!({ message: 'Attempt limit has been reached' }, 400) - return - end - - if test.nil? - test = TestAttempt.create!( - name: "First Test", - attempt_number: 1, - pass_status: false, - suspend_data: nil, - completed: false, - cmi_entry: 'ab-initio', - attempted_at: DateTime.now, - task_id: params[:task_id] - ) - elsif test.completed - test = TestAttempt.create!( - name: "New Attempt", - attempt_number: test.attempt_number + 1, - pass_status: false, - suspend_data: nil, - completed: false, - cmi_entry: 'ab-initio', - attempted_at: DateTime.now, - task_id: params[:task_id] - ) - else - test.update!(cmi_entry: 'resume') + attempts = TestAttempt.where("task_id = ?", params[:task_id]) end - - present :data, test, with: Entities::TestAttemptEntity + tests = attempts.order(id: :desc) + present tests, with: Entities::TestAttemptEntity end - # Fetch the latest completed test result - desc 'Get the latest completed test result' + desc 'Get the latest test result' params do - requires :task_id, type: Integer, desc: 'Task ID to fetch completed test attempt for' + requires :task_id, type: Integer, desc: 'Task ID to fetch the latest test attempt for' + optional :completed, type: Boolean, desc: 'Get the latest completed test?' end - get 'completed-latest' do + get ':task_id/latest' do # Ensure task exists task = Task.find(params[:task_id]) if task.nil? error!({ message: 'Task ID is invalid' }, 404) return else - test_attempts = TestAttempt.where("task_id = ?", params[:task_id]) + attempts = TestAttempt.where("task_id = ?", params[:task_id]) end - test = test_attempts.where(completed: true).order(id: :desc).first + test = if params[:completed] + attempts.where(completion_status: true).order(id: :desc).first + else + attempts.order(id: :desc).first + end if test.nil? - error!({ message: 'No completed tests found for this task' }, 404) + error!({ message: 'No tests found for this task' }, 404) else - present :data, test, with: Entities::TestAttemptEntity + present test, with: Entities::TestAttemptEntity end end - # Fetch a specific test result by ID - desc 'Get a specific test result' + desc 'Review a completed session' params do - requires :id, type: String, desc: 'ID of the test' + requires :task_id, type: Integer, desc: 'Task ID to fetch the latest test attempt for' + requires :session_id, type: Integer, desc: 'Test attempt ID to review' end - get ':id' do - present TestAttempt.find(params[:id]), with: Entities::TestAttemptEntity + get ':task_id/review/:session_id' do + session = TestAttempt.find(params[:session_id]) + if session.nil? + error!({ message: 'Session ID is invalid' }, 404) + return + else + # TODO: do review stuff + # TODO: add review permission flag to taskdef + end + present test, with: Entities::TestAttemptEntity end - # Create a new test result entry - desc 'Create a new test result' + desc 'Initiate a new test session' params do - requires :name, type: String, desc: 'Name of the test' - requires :attempt_number, type: Integer, desc: 'Number of attempts' - requires :pass_status, type: Boolean, desc: 'Passing status' - requires :suspend_data, type: String, desc: 'Suspended data in JSON' - requires :completed, type: Boolean, desc: 'Completion status' - optional :cmi_entry, type: String, desc: 'CMI Entry', default: "ab-initio" - optional :exam_result, type: String, desc: 'Result of the exam' - optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' requires :task_id, type: Integer, desc: 'ID of the associated task' end - post do + post ':task_id/session' do test = TestAttempt.create!(params) - - if test.completed == true - task = Task.find(test.task_id) - task.add_numbas_comment(test) - end - - present :data, test, with: Entities::TestAttemptEntity + present test, with: Entities::TestAttemptEntity end - # Update the details of a specific test result - desc 'Update a test result' + desc 'Update an existing session' params do - requires :id, type: String, desc: 'ID of the test' - optional :name, type: String, desc: 'Name of the test' - optional :attempt_number, type: Integer, desc: 'Number of attempts' - optional :pass_status, type: Boolean, desc: 'Passing status' - optional :suspend_data, type: String, desc: 'Suspended data in JSON' - optional :completed, type: Boolean, desc: 'Completion status' - optional :exam_result, type: String, desc: 'Exam score' - optional :cmi_entry, type: String, desc: 'CMI Entry' - optional :attempted_at, type: DateTime, desc: 'Timestamp of the test attempt' + requires :task_id, type: Integer, desc: 'ID of the associated task' + requires :id, type: String, desc: 'ID of the test attempt' + optional :cmi_datamodel, type: String, desc: 'JSON CMI datamodel to update' + optional :terminated, type: Boolean, desc: 'Terminate the current session' end - put ':id' do + patch ':task_id/session/:id' do + session_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) test = TestAttempt.find(params[:id]) - test.update!(params.except(:id)) - - if test.completed == true - task = Task.find(test.task_id) - task.add_numbas_comment(test) - end - end - - # Delete a specific test result by ID - desc 'Delete a test result' - params do - requires :id, type: String, desc: 'ID of the test' - end - delete ':id' do - TestAttempt.find(params[:id]).destroy! + test.update!(session_data) + test.save! + present test, with: Entities::TestAttemptEntity end - # Update the suspend_data of a specific test result - desc 'Update suspend data for a test result' + desc 'Delete a test attempt' params do - requires :id, type: String, desc: 'ID of the test' - requires :suspend_data, type: Hash, desc: 'Suspend data to be saved' + requires :task_id, type: Integer, desc: 'ID of the associated task' + requires :id, type: String, desc: 'ID of the test attempt' end - put ':id/suspend' do - test = TestAttempt.find_by(id: params[:id]) + delete ':task_id/:id' do + raise NotImplementedError + # TODO: fix permissions before enabling this - error!('Test not found', 404) unless test - - suspend_data = params[:suspend_data].to_json - - begin - JSON.parse(suspend_data) - test.update!(suspend_data: suspend_data) - { message: 'Suspend data updated successfully', test: test } - rescue JSON::ParserError - error!('Invalid JSON provided', 400) - rescue => e - error!(e.message, 500) - end + # test = TestAttempt.find(params[:id]) + # test.destroy! end end end diff --git a/app/models/task.rb b/app/models/task.rb index 44a55da72..706ab1838 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -668,18 +668,18 @@ def add_text_comment(user, text, reply_to_id = nil) comment end - def add_numbas_comment(test) + def add_scorm_comment(test) comment = TaskComment.create comment.task = self comment.user = self.tutor - comment.comment = "Numbas Attempt #{test.attempt_number} completed with score: #{test.exam_result}" - comment.content_type = 'numbas' + comment.comment = "Test Attempt #{test.attempt_number} completed with score: #{test.exam_result}" + comment.content_type = 'scorm' comment.recipient = project.student comment.save! comment end - + def individual_task_or_submitter_of_group_task? return true if !group_task? # its individual return true unless group.present? # no group yet... so individual diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index a3a39c074..6eaefe55d 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -95,8 +95,8 @@ def copy_to(other_unit) new_td.add_task_resources(task_resources, copy: true) end - if has_numbas_data? - new_td.add_numbas_data(task_numbas_data, copy: true) + if has_scorm_data? + new_td.add_scorm_data(task_scorm_data, copy: true) end new_td.save! @@ -138,8 +138,8 @@ def move_files_on_abbreviation_change FileUtils.mv(task_assessment_resources_with_abbreviation(old_abbr), task_assessment_resources()) end - if File.exist? task_numbas_data_with_abbreviation(old_abbr) - FileUtils.mv(task_numbas_data_with_abbreviation(old_abbr), task_numbas_data()) + if File.exist? task_scorm_data_with_abbreviation(old_abbr) + FileUtils.mv(task_scorm_data_with_abbreviation(old_abbr), task_scorm_data()) end end @@ -301,8 +301,8 @@ def to_csv_row def self.csv_columns [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, - :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :has_enabled_numbas_test, - :has_numbas_time_delay, :numbas_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, + :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :scorm_enabled, + :scorm_time_delay_enabled, :scorm_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] end @@ -349,9 +349,9 @@ def self.task_def_for_csv_row(unit, row) result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? result.due_date = due_date - result.has_enabled_numbas_test = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_enabled_numbas_test]}".strip - result.has_numbas_time_delay = %w(Yes y Y yes true TRUE 1).include? "#{row[:has_numbas_time_delay]}".strip - result.numbas_attempt_limit = row[:numbas_attempt_limit].to_i + result.scorm_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_enabled]}".strip + result.scorm_time_delay_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_time_delay_enabled]}".strip + result.scorm_attempt_limit = row[:scorm_attempt_limit].to_i result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i @@ -399,20 +399,20 @@ def has_task_sheet? File.exist? task_sheet end - def has_numbas_data? - File.exist? task_numbas_data + def has_scorm_data? + File.exist? task_scorm_data end - def has_enabled_numbas_test? - has_enabled_numbas_test + def scorm_enabled? + scorm_enabled end - def has_numbas_time_delay? - has_numbas_time_delay + def scorm_time_delay_enabled? + scorm_time_delay_enabled end - def numbas_attempt_limit? - numbas_attempt_limit + def scorm_attempt_limit? + scorm_attempt_limit end def is_graded? @@ -467,20 +467,20 @@ def remove_task_assessment_resources() end end - def add_numbas_data(file, copy: false) + def add_scorm_data(file, copy: false) if copy - FileUtils.cp file, task_numbas_data + FileUtils.cp file, task_scorm_data else - FileUtils.mv file, task_numbas_data + FileUtils.mv file, task_scorm_data end end - def remove_numbas_data() - if has_numbas_data? - FileUtils.rm task_numbas_data + def remove_scorm_data() + if has_scorm_data? + FileUtils.rm task_scorm_data end - reset_numbas_config() + reset_scorm_config() end # Get the path to the task sheet - using the current abbreviation @@ -496,8 +496,8 @@ def task_assessment_resources task_assessment_resources_with_abbreviation(abbreviation) end - def task_numbas_data - task_numbas_data_with_abbreviation(abbreviation) + def task_scorm_data + task_scorm_data_with_abbreviation(abbreviation) end def related_tasks_with_files(consolidate_groups = true) @@ -542,7 +542,7 @@ def delete_associated_files() remove_task_sheet() remove_task_resources() remove_task_assessment_resources() - remove_numbas_data() + remove_scorm_data() end # Calculate the path to the task sheet using the provided abbreviation @@ -590,14 +590,14 @@ def task_assessment_resources_with_abbreviation(abbr) end end - # Calculate the path to the numbas containzer zip file using the provided abbreviation + # Calculate the path to the SCORM containzer zip file using the provided abbreviation # This allows the path to be calculated on abbreviation change to allow files to # be moved - def task_numbas_data_with_abbreviation(abbr) + def task_scorm_data_with_abbreviation(abbr) task_path = FileHelper.task_file_dir_for_unit unit, create = true - result_with_sanitised_path = "#{task_path}#{FileHelper.sanitized_path(abbr)}.numbas.zip" - result_with_sanitised_file = "#{task_path}#{FileHelper.sanitized_filename(abbr)}.numbas.zip" + result_with_sanitised_path = "#{task_path}#{FileHelper.sanitized_path(abbr)}.scorm.zip" + result_with_sanitised_file = "#{task_path}#{FileHelper.sanitized_filename(abbr)}.scorm.zip" if File.exist? result_with_sanitised_path result_with_sanitised_path @@ -606,9 +606,9 @@ def task_numbas_data_with_abbreviation(abbr) end end - def reset_numbas_config() - self.has_enabled_numbas_test = false - self.has_numbas_time_delay = false - self.numbas_attempt_limit = 0 + def reset_scorm_config() + self.scorm_enabled = false + self.scorm_time_delay_enabled = false + self.scorm_attempt_limit = 0 end end diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index 9391144b1..a05dbd9ec 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -1,11 +1,10 @@ -class TestAttempt < ApplicationRecord - include ApplicationHelper - include LogHelper - include GradeHelper +require 'json' +require 'time' - belongs_to :task +class TestAttempt < ApplicationRecord def self.permissions + # TODO: this is all wrong, students should not be able to delete test attempts student_role_permissions = [ :create, :view_own, @@ -33,4 +32,74 @@ def self.permissions nil: nil_role_permissions } end + + # task + # t.references :task + + # extra non-cmi metadata + # t.datetime :attempted_time, null:false + # t.integer :attempt_number, default: 1, null: false + # t.boolean :terminated, default: false + + # fields that must be synced from cmi data whenever it's updated + # t.boolean :completion_status, default: false + # t.boolean :success_status, default: false + # t.float :score_scaled, default: 0 + + # scorm datamodel + # t.text :cmi_datamodel, default: "{}", null: false + + after_initialize if: :new_record? do + self.attempted_time = Time.now + task = Task.find(self.task_id) + learner_name = task.project.student.name + learner_id = task.project.student.student_id + + init_state = { + "cmi.completion_status": 'not attempted', + "cmi.entry": 'ab-initio', # init state + "cmi.objectives._count": '0', # this counter will be managed on the frontend + "cmi.interactions._count": '0', # this counter will be managed on the frontend + "cmi.mode": 'normal', + "cmi.learner_name": learner_name, + "cmi.learner_id": learner_id + } + self.cmi_datamodel = init_state.to_json + end + + def cmi_datamodel=(data) + new_data = JSON.parse(data) + + if self.terminated == true + raise "Terminated entries should not be updated" + end + + # set cmi.entry to resume if the session is in progress + if new_data['cmi.completion_status'] == 'incomplete' + new_data['cmi.entry'] = 'resume' + end + + # IMPORTANT: always sync any model attributes with cmi values here to ensure consistency! + # attributes derived from cmi keys: completion_status, success_status, score_scaled + self.completion_status = new_data['cmi.completion_status'] == 'completed' + self.success_status = new_data['cmi.success_status'] == 'passed' + self.score_scaled = new_data['cmi.score.scaled'] + + write_attribute(:cmi_datamodel, new_data.to_json) + end + + def resume + # check cmi.completion_status is not completed + # set cmi.entry to resume + end + + def review + # set cmi.entry to resume + # set cmi.mode to review + end + + def pass_override + # TODO: implement tutor override pass + end + end diff --git a/db/migrate/20231205011842_create_test_attempts.rb b/db/migrate/20231205011842_create_test_attempts.rb index fc112bcb2..dadc75084 100644 --- a/db/migrate/20231205011842_create_test_attempts.rb +++ b/db/migrate/20231205011842_create_test_attempts.rb @@ -2,15 +2,13 @@ class CreateTestAttempts < ActiveRecord::Migration[7.0] def change create_table :test_attempts do |t| t.references :task - t.string :name + t.datetime :attempted_time, null:false t.integer :attempt_number, default: 1, null: false - t.boolean :pass_status - t.text :suspend_data - t.boolean :completed, default: false - t.datetime :attempted_at - t.string :cmi_entry, default: "ab-initio" - t.string :exam_result - t.timestamps + t.boolean :terminated, default: false + t.boolean :completion_status, default: false + t.boolean :success_status, default: false + t.float :score_scaled, default: 0 + t.text :cmi_datamodel, default: "{}", null: false end end end diff --git a/db/migrate/20240322021829_add_scorm_config_to_task_def.rb b/db/migrate/20240322021829_add_scorm_config_to_task_def.rb new file mode 100644 index 000000000..5daa69c72 --- /dev/null +++ b/db/migrate/20240322021829_add_scorm_config_to_task_def.rb @@ -0,0 +1,19 @@ +class AddScormConfigToTaskDef < ActiveRecord::Migration[7.0] + def change + change_table :task_definitions do |t| + t.boolean :scorm_enabled, default: false + t.boolean :scorm_allow_review, default: false + t.boolean :scorm_time_delay_enabled, default: false + t.integer :scorm_attempt_limit + end + end + + def down + change_table :task_definitions do |t| + t.remove :scorm_enabled + t.boolean :scorm_allow_review + t.remove :scorm_time_delay_enabled + t.remove :scorm_attempt_limit + end + end +end diff --git a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb b/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb deleted file mode 100644 index 7fd3cd82a..000000000 --- a/db/migrate/20240322021829_modify_numbas_fields_in_task_def.rb +++ /dev/null @@ -1,17 +0,0 @@ -class ModifyNumbasFieldsInTaskDef < ActiveRecord::Migration[7.0] - def change - change_table :task_definitions do |t| - t.boolean :has_enabled_numbas_test, default: false - t.boolean :has_numbas_time_delay, default: false - t.integer :numbas_attempt_limit - end - end - - def down - change_table :task_definitions do |t| - t.remove :has_enabled_numbas_test - t.remove :has_numbas_time_delay - t.remove :numbas_attempt_limit - end - end -end diff --git a/db/schema.rb b/db/schema.rb index eb29b90d5..5d6c3ff34 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -250,9 +250,10 @@ t.bigint "overseer_image_id" t.string "tii_group_id" t.string "moss_language" - t.boolean "has_enabled_numbas_test", default: false - t.boolean "has_numbas_time_delay", default: false - t.integer "numbas_attempt_limit" + t.boolean "scorm_enabled", default: false + t.boolean "scorm_allow_review", default: false + t.boolean "scorm_time_delay_enabled", default: false + t.integer "scorm_attempt_limit" t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" t.index ["overseer_image_id"], name: "index_task_definitions_on_overseer_image_id" t.index ["tutorial_stream_id"], name: "index_task_definitions_on_tutorial_stream_id" @@ -349,16 +350,13 @@ create_table "test_attempts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.bigint "task_id" - t.string "name" + t.datetime "attempted_time", null: false t.integer "attempt_number", default: 1, null: false - t.boolean "pass_status" - t.text "suspend_data" - t.boolean "completed", default: false - t.datetime "attempted_at" - t.string "cmi_entry", default: "ab-initio" - t.string "exam_result" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.boolean "terminated", default: false + t.boolean "completion_status", default: false + t.boolean "success_status", default: false + t.float "score_scaled", default: 0.0 + t.text "cmi_datamodel", default: "{}", null: false t.index ["task_id"], name: "index_test_attempts_on_task_id" end diff --git a/test/api/units/task_definitions_api_test.rb b/test/api/units/task_definitions_api_test.rb index 2817d372c..9e0a816c6 100644 --- a/test/api/units/task_definitions_api_test.rb +++ b/test/api/units/task_definitions_api_test.rb @@ -50,9 +50,9 @@ def test_task_definition_cud plagiarism_warn_pct: 80, is_graded: false, max_quality_pts: 0, - has_enabled_numbas_test: false, - has_numbas_time_delay: true, - numbas_attempt_limit: 0 + scorm_enabled: false, + scorm_time_delay_enabled: true, + scorm_attempt_limit: 0 } } diff --git a/test/models/task_definition_test.rb b/test/models/task_definition_test.rb index 8c22317c1..2e0700fca 100644 --- a/test/models/task_definition_test.rb +++ b/test/models/task_definition_test.rb @@ -145,7 +145,7 @@ def test_export_task_definitions_csv task_defs_csv = CSV.parse unit.task_definitions_csv, headers: true task_defs_csv.each do |task_def_csv| task_def = unit.task_definitions.find_by(abbreviation: task_def_csv['abbreviation']) - keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'has_enabled_numbas_test', 'has_numbas_time_delay', 'numbas_attempt_limit'] + keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'scorm_enabled', 'scorm_time_delay_enabled', 'scorm_attempt_limit'] task_def_csv.each do |key, value| unless keys_to_ignore.include?(key) assert_equal(task_def[key].to_s, value) diff --git a/test_files/COS10001-ImportTasksWithTutorialStream.csv b/test_files/COS10001-ImportTasksWithTutorialStream.csv index dde8a9e07..d4e006389 100644 --- a/test_files/COS10001-ImportTasksWithTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithTutorialStream.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, diff --git a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv index aac958d5e..8fc35d36f 100644 --- a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, diff --git a/test_files/COS10001-Tasks.csv b/test_files/COS10001-Tasks.csv index c961c8e5b..2c734e56d 100644 --- a/test_files/COS10001-Tasks.csv +++ b/test_files/COS10001-Tasks.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks diff --git a/test_files/csv_test_files/COS10001-Tasks.csv b/test_files/csv_test_files/COS10001-Tasks.csv index 3560d3695..1173f0ac7 100644 --- a/test_files/csv_test_files/COS10001-Tasks.csv +++ b/test_files/csv_test_files/COS10001-Tasks.csv @@ -1,2 +1,2 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit Assignment 12,A12,rerum ut fugit saepe ipsa in quidem,2,0,FALSE,0,FALSE,50,[],,"[{""key"":""file0"",""name"":""Assumenda accusamus quas"",""type"":""image""}]",-1,Sat,1,Mon,13,Mon,,, diff --git a/test_files/unit_csv_imports/import_group_tasks.csv b/test_files/unit_csv_imports/import_group_tasks.csv index 2e9afa047..11cd48457 100644 --- a/test_files/unit_csv_imports/import_group_tasks.csv +++ b/test_files/unit_csv_imports/import_group_tasks.csv @@ -1,3 +1,3 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,tutorial_stream,has_enabled_numbas_test,has_numbas_time_delay,numbas_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit Group Import 1,1GI,Test Description - Import,16,0,FALSE,0,FALSE,80,[],Group Work,[],0,Mon,1,Sun,2,Wed,group-tasks-test,,, Missing Group,2GI,Test Description - Import FAIL,16,0,FALSE,0,FALSE,80,[],Group Work1,[],0,Mon,1,Sun,2,Wed,group-tasks-test,,, From 8047f4cead1f4ffff2e2b5244cfa5510b6a03146 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 14 May 2024 13:53:42 +1000 Subject: [PATCH 025/124] chore: address rubocop errors --- app/api/test_attempts_api.rb | 1 + app/models/task_definition.rb | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index cb54c256e..dac9c6f8c 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -78,6 +78,7 @@ class TestAttemptsApi < Grape::API error!({ message: 'Session ID is invalid' }, 404) return else + logger.debug "Request to review test session #{params[:session_id]}" # TODO: do review stuff # TODO: add review permission flag to taskdef end diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 6eaefe55d..11a67d023 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -349,9 +349,9 @@ def self.task_def_for_csv_row(unit, row) result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? result.due_date = due_date - result.scorm_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_enabled]}".strip - result.scorm_time_delay_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_time_delay_enabled]}".strip - result.scorm_attempt_limit = row[:scorm_attempt_limit].to_i + result.scorm_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_enabled]}".strip + result.scorm_time_delay_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_time_delay_enabled]}".strip + result.scorm_attempt_limit = row[:scorm_attempt_limit].to_i result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i From 3539d957022f0c6310a2939dd6eccad946cb6610 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 14 May 2024 14:22:07 +1000 Subject: [PATCH 026/124] fix: add allow review property to task def related files --- app/api/task_definitions_api.rb | 16 ++++++++++------ app/models/task_definition.rb | 16 +++++++++++----- test/api/units/task_definitions_api_test.rb | 7 ++++--- test/models/task_definition_test.rb | 2 +- .../COS10001-ImportTasksWithTutorialStream.csv | 2 +- ...COS10001-ImportTasksWithoutTutorialStream.csv | 2 +- test_files/COS10001-Tasks.csv | 2 +- test_files/csv_test_files/COS10001-Tasks.csv | 2 +- .../unit_csv_imports/import_group_tasks.csv | 2 +- 9 files changed, 31 insertions(+), 20 deletions(-) diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index eee95fb6d..db1f70b6b 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -28,9 +28,10 @@ class TaskDefinitionsApi < Grape::API requires :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' optional :upload_requirements, type: String, desc: 'Task file upload requirements' requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - requires :scorm_enabled, type: Boolean, desc: 'Whether SCORM assessment is enabled for this task' - requires :scorm_time_delay_enabled, type: Boolean, desc: 'Whether there is an incremental time delay between SCORM test attempts' - requires :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' + requires :scorm_enabled, type: Boolean, desc: 'Whether SCORM assessment is enabled for this task' + requires :scorm_allow_review, type: Boolean, desc: 'Whether a student is allowed to review their completed test attempts' + requires :scorm_time_delay_enabled, type: Boolean, desc: 'Whether there is an incremental time delay between SCORM test attempts' + requires :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' requires :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' @@ -61,6 +62,7 @@ class TaskDefinitionsApi < Grape::API :restrict_status_updates, :plagiarism_warn_pct, :scorm_enabled, + :scorm_allow_review, :scorm_time_delay_enabled, :scorm_attempt_limit, :is_graded, @@ -112,9 +114,10 @@ class TaskDefinitionsApi < Grape::API optional :restrict_status_updates, type: Boolean, desc: 'Restrict updating of the status to staff' optional :upload_requirements, type: String, desc: 'Task file upload requirements' optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' - optional :scorm_enabled, type: Boolean, desc: 'Whether or not SCORM test assessment is enabled for this task' - optional :scorm_time_delay_enabled, type: Boolean, desc: 'Whether or not there is an incremental time delay between SCORM test attempts' - optional :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' + optional :scorm_enabled, type: Boolean, desc: 'Whether or not SCORM test assessment is enabled for this task' + optional :scorm_allow_review, type: Boolean, desc: 'Whether a student is allowed to review their completed test attempts' + optional :scorm_time_delay_enabled, type: Boolean, desc: 'Whether or not there is an incremental time delay between SCORM test attempts' + optional :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' optional :max_quality_pts, type: Integer, desc: 'A range for quality points when quality is assessed' optional :assessment_enabled, type: Boolean, desc: 'Enable or disable assessment' @@ -144,6 +147,7 @@ class TaskDefinitionsApi < Grape::API :restrict_status_updates, :plagiarism_warn_pct, :scorm_enabled, + :scorm_allow_review, :scorm_time_delay_enabled, :scorm_attempt_limit, :is_graded, diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 11a67d023..88c907d4e 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -302,8 +302,8 @@ def to_csv_row def self.csv_columns [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :scorm_enabled, - :scorm_time_delay_enabled, :scorm_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, - :due_day, :tutorial_stream] + :scorm_allow_review, :scorm_time_delay_enabled, :scorm_attempt_limit, :start_week, :start_day, :target_week, + :target_day, :due_week, :due_day, :tutorial_stream] end def self.task_def_for_csv_row(unit, row) @@ -349,9 +349,10 @@ def self.task_def_for_csv_row(unit, row) result.upload_requirements = JSON.parse(row[:upload_requirements]) unless row[:upload_requirements].nil? result.due_date = due_date - result.scorm_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_enabled]}".strip - result.scorm_time_delay_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_time_delay_enabled]}".strip - result.scorm_attempt_limit = row[:scorm_attempt_limit].to_i + result.scorm_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_enabled]}".strip + result.scorm_allow_review = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_allow_review]}".strip + result.scorm_time_delay_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_time_delay_enabled]}".strip + result.scorm_attempt_limit = row[:scorm_attempt_limit].to_i result.plagiarism_warn_pct = row[:plagiarism_warn_pct].to_i @@ -407,6 +408,10 @@ def scorm_enabled? scorm_enabled end + def scorm_allow_review? + scorm_allow_review + end + def scorm_time_delay_enabled? scorm_time_delay_enabled end @@ -608,6 +613,7 @@ def task_scorm_data_with_abbreviation(abbr) def reset_scorm_config() self.scorm_enabled = false + self.scorm_allow_review = false self.scorm_time_delay_enabled = false self.scorm_attempt_limit = 0 end diff --git a/test/api/units/task_definitions_api_test.rb b/test/api/units/task_definitions_api_test.rb index 9e0a816c6..ea0826fe6 100644 --- a/test/api/units/task_definitions_api_test.rb +++ b/test/api/units/task_definitions_api_test.rb @@ -50,9 +50,10 @@ def test_task_definition_cud plagiarism_warn_pct: 80, is_graded: false, max_quality_pts: 0, - scorm_enabled: false, - scorm_time_delay_enabled: true, - scorm_attempt_limit: 0 + scorm_enabled: false, + scorm_allow_review: false, + scorm_time_delay_enabled: true, + scorm_attempt_limit: 0 } } diff --git a/test/models/task_definition_test.rb b/test/models/task_definition_test.rb index 2e0700fca..5210322ef 100644 --- a/test/models/task_definition_test.rb +++ b/test/models/task_definition_test.rb @@ -145,7 +145,7 @@ def test_export_task_definitions_csv task_defs_csv = CSV.parse unit.task_definitions_csv, headers: true task_defs_csv.each do |task_def_csv| task_def = unit.task_definitions.find_by(abbreviation: task_def_csv['abbreviation']) - keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'scorm_enabled', 'scorm_time_delay_enabled', 'scorm_attempt_limit'] + keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'scorm_enabled', 'scorm_allow_review', 'scorm_time_delay_enabled', 'scorm_attempt_limit'] task_def_csv.each do |key, value| unless keys_to_ignore.include?(key) assert_equal(task_def[key].to_s, value) diff --git a/test_files/COS10001-ImportTasksWithTutorialStream.csv b/test_files/COS10001-ImportTasksWithTutorialStream.csv index d4e006389..7e1df1062 100644 --- a/test_files/COS10001-ImportTasksWithTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithTutorialStream.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, diff --git a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv index 8fc35d36f..8ed8b6cb4 100644 --- a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, diff --git a/test_files/COS10001-Tasks.csv b/test_files/COS10001-Tasks.csv index 2c734e56d..d4e15b33a 100644 --- a/test_files/COS10001-Tasks.csv +++ b/test_files/COS10001-Tasks.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks diff --git a/test_files/csv_test_files/COS10001-Tasks.csv b/test_files/csv_test_files/COS10001-Tasks.csv index 1173f0ac7..25f7728ec 100644 --- a/test_files/csv_test_files/COS10001-Tasks.csv +++ b/test_files/csv_test_files/COS10001-Tasks.csv @@ -1,2 +1,2 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit Assignment 12,A12,rerum ut fugit saepe ipsa in quidem,2,0,FALSE,0,FALSE,50,[],,"[{""key"":""file0"",""name"":""Assumenda accusamus quas"",""type"":""image""}]",-1,Sat,1,Mon,13,Mon,,, diff --git a/test_files/unit_csv_imports/import_group_tasks.csv b/test_files/unit_csv_imports/import_group_tasks.csv index 11cd48457..60996825a 100644 --- a/test_files/unit_csv_imports/import_group_tasks.csv +++ b/test_files/unit_csv_imports/import_group_tasks.csv @@ -1,3 +1,3 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,tutorial_stream,scorm_enabled,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit Group Import 1,1GI,Test Description - Import,16,0,FALSE,0,FALSE,80,[],Group Work,[],0,Mon,1,Sun,2,Wed,group-tasks-test,,, Missing Group,2GI,Test Description - Import FAIL,16,0,FALSE,0,FALSE,80,[],Group Work1,[],0,Mon,1,Sun,2,Wed,group-tasks-test,,, From 0812e206a9dadcfe7d575feec04e49b15b412556 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 14 May 2024 14:40:59 +1000 Subject: [PATCH 027/124] fix: post scorm comment after test attempt termination --- app/api/test_attempts_api.rb | 13 ++++++++++--- app/models/task.rb | 2 +- app/models/test_attempt.rb | 15 ++++++++------- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index dac9c6f8c..5955b7191 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -79,7 +79,7 @@ class TestAttemptsApi < Grape::API return else logger.debug "Request to review test session #{params[:session_id]}" - # TODO: do review stuff + session.review # TODO: add review permission flag to taskdef end present test, with: Entities::TestAttemptEntity @@ -104,8 +104,15 @@ class TestAttemptsApi < Grape::API patch ':task_id/session/:id' do session_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) test = TestAttempt.find(params[:id]) - test.update!(session_data) - test.save! + + unless test.terminated + test.update!(session_data) + test.save! + if params[:terminated] + task = Task.find(test.task_id) + task.add_scorm_comment(test) + end + end present test, with: Entities::TestAttemptEntity end diff --git a/app/models/task.rb b/app/models/task.rb index 706ab1838..916f9ce76 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -672,7 +672,7 @@ def add_scorm_comment(test) comment = TaskComment.create comment.task = self comment.user = self.tutor - comment.comment = "Test Attempt #{test.attempt_number} completed with score: #{test.exam_result}" + comment.comment = "Test Attempt #{test.attempt_number} completed with score: #{format("%.2f", test.score_scaled * 100)}%" comment.content_type = 'scorm' comment.recipient = project.student comment.save! diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index a05dbd9ec..b8f990693 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -88,14 +88,15 @@ def cmi_datamodel=(data) write_attribute(:cmi_datamodel, new_data.to_json) end - def resume - # check cmi.completion_status is not completed - # set cmi.entry to resume - end - def review - # set cmi.entry to resume - # set cmi.mode to review + dm = JSON.parse(self.cmi_datamodel) + if dm['cmi.completion_status'] != 'completed' + raise "Cannot review incomplete attempts!" + end + + # when review is requested change the mode to review + dm['cmi.mode'] = 'review' + write_attribute(:cmi_datamodel, dm.to_json) end def pass_override From b4989242e37ccd046651bfc8db32934ee94e190a Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 14 May 2024 14:53:02 +1000 Subject: [PATCH 028/124] fix: rename entity file and add update fields in task spreadsheet --- .../{numbas_entity.rb => scorm_entity.rb} | 0 test_files/csv_test_files/COS10001-Tasks.xlsx | Bin 6646 -> 6673 bytes 2 files changed, 0 insertions(+), 0 deletions(-) rename app/api/entities/{numbas_entity.rb => scorm_entity.rb} (100%) diff --git a/app/api/entities/numbas_entity.rb b/app/api/entities/scorm_entity.rb similarity index 100% rename from app/api/entities/numbas_entity.rb rename to app/api/entities/scorm_entity.rb diff --git a/test_files/csv_test_files/COS10001-Tasks.xlsx b/test_files/csv_test_files/COS10001-Tasks.xlsx index 4ca8b1c63e9168a3ff159adaf95c318155a2e209..7d44f0e74e707b6681dd78cb68f7cbf3b3942b9a 100644 GIT binary patch delta 3180 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 delta 3143 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 Date: Tue, 14 May 2024 15:22:33 +1000 Subject: [PATCH 029/124] fix: enforce attempt limit --- app/api/test_attempts_api.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 5955b7191..49b849890 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -90,7 +90,24 @@ class TestAttemptsApi < Grape::API requires :task_id, type: Integer, desc: 'ID of the associated task' end post ':task_id/session' do - test = TestAttempt.create!(params) + task = Task.find(params[:task_id]) + if task.nil? + error!({ message: 'Task ID is invalid' }, 404) + return + else + attempts = TestAttempt.where("task_id = ?", params[:task_id]) + end + + # check attempt limit + test_count = attempts.count + limit = task.task_definition.scorm_attempt_limit + if test_count > limit && limit != 0 + error!({ message: 'Attempt limit has been reached' }, 400) + return + end + + metadata = params.merge(attempt_number: test_count + 1) + test = TestAttempt.create!(metadata) present test, with: Entities::TestAttemptEntity end From 910eecdc218f52e572d39059e64a0b28acb44dce Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 15 May 2024 17:37:44 +1000 Subject: [PATCH 030/124] fix: expose scorm configs to student --- app/api/entities/task_definition_entity.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index f6549d3d0..f99b2d73d 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -42,8 +42,8 @@ def staff?(my_role) expose :has_scorm_data?, as: :has_scorm_data expose :scorm_enabled expose :scorm_allow_review - expose :scorm_time_delay_enabled, if: ->(unit, options) { staff?(options[:my_role]) } - expose :scorm_attempt_limit, if: ->(unit, options) { staff?(options[:my_role]) } + expose :scorm_time_delay_enabled + expose :scorm_attempt_limit expose :is_graded expose :max_quality_pts expose :overseer_image_id, if: ->(unit, options) { staff?(options[:my_role]) } From 2a04a068282f69b11a6243a590bb25edcdd5c2c1 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 1 Jun 2024 20:16:20 +1000 Subject: [PATCH 031/124] fix: use project and task def to fix issue where task is undefined on launching scorm test --- app/api/test_attempts_api.rb | 213 +++++++++++++++++------------------ app/models/test_attempt.rb | 2 +- 2 files changed, 103 insertions(+), 112 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 49b849890..7196e6b62 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -22,128 +22,119 @@ class TestAttemptsApi < Grape::API error!({ errors: e.full_messages }, 400) end - resources :test_attempts do - desc 'Get all test results for a task' - params do - requires :task_id, type: Integer, desc: 'Task ID to fetch test attempts for' - end - get ':task_id' do - task = Task.find(params[:task_id]) - if task.nil? - error!({ message: 'Task ID is invalid' }, 404) - return - else - attempts = TestAttempt.where("task_id = ?", params[:task_id]) - end - tests = attempts.order(id: :desc) - present tests, with: Entities::TestAttemptEntity - end - - desc 'Get the latest test result' - params do - requires :task_id, type: Integer, desc: 'Task ID to fetch the latest test attempt for' - optional :completed, type: Boolean, desc: 'Get the latest completed test?' - end - get ':task_id/latest' do - # Ensure task exists - task = Task.find(params[:task_id]) - if task.nil? - error!({ message: 'Task ID is invalid' }, 404) - return - else - attempts = TestAttempt.where("task_id = ?", params[:task_id]) - end - - test = if params[:completed] - attempts.where(completion_status: true).order(id: :desc).first - else - attempts.order(id: :desc).first - end - - if test.nil? - error!({ message: 'No tests found for this task' }, 404) - else - present test, with: Entities::TestAttemptEntity - end - end + desc 'Get all test results for a task' + params do + requires :project_id, type: Integer, desc: 'The id of the project with the task' + requires :task_definition_id, type: Integer, desc: 'The id of the task definition related to the task' + end + get '/projects/:project_id/task_def_id/:task_definition_id/test_attempts' do + project = Project.find(params[:project_id]) + task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + task = project.task_for_task_definition(task_definition) + + attempts = TestAttempt.where("task_id = ?", task.id) + tests = attempts.order(id: :desc) + present tests, with: Entities::TestAttemptEntity + end - desc 'Review a completed session' - params do - requires :task_id, type: Integer, desc: 'Task ID to fetch the latest test attempt for' - requires :session_id, type: Integer, desc: 'Test attempt ID to review' - end - get ':task_id/review/:session_id' do - session = TestAttempt.find(params[:session_id]) - if session.nil? - error!({ message: 'Session ID is invalid' }, 404) - return - else - logger.debug "Request to review test session #{params[:session_id]}" - session.review - # TODO: add review permission flag to taskdef - end + desc 'Get the latest test result' + params do + requires :project_id, type: Integer, desc: 'The id of the project with the task' + requires :task_definition_id, type: Integer, desc: 'The id of the task definition related to the task' + optional :completed, type: Boolean, desc: 'Get the latest completed test?' + end + get '/projects/:project_id/task_def_id/:task_definition_id/test_attempts/latest' do + project = Project.find(params[:project_id]) + task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + task = project.task_for_task_definition(task_definition) + + attempts = TestAttempt.where("task_id = ?", task.id) + + test = if params[:completed] + attempts.where(completion_status: true).order(id: :desc).first + else + attempts.order(id: :desc).first + end + + if test.nil? + error!({ message: 'No tests found for this task' }, 404) + else present test, with: Entities::TestAttemptEntity end + end - desc 'Initiate a new test session' - params do - requires :task_id, type: Integer, desc: 'ID of the associated task' + desc 'Review a completed attempt' + params do + requires :id, type: Integer, desc: 'Test attempt ID to review' + end + get 'test_attempts/:id/review' do + attempt = TestAttempt.find(params[:id]) + if attempt.nil? + error!({ message: 'Test attempt ID is invalid' }, 404) + return + else + logger.debug "Request to review test attempt #{params[:id]}" + attempt.review + # TODO: add review permission flag to taskdef end - post ':task_id/session' do - task = Task.find(params[:task_id]) - if task.nil? - error!({ message: 'Task ID is invalid' }, 404) - return - else - attempts = TestAttempt.where("task_id = ?", params[:task_id]) - end - - # check attempt limit - test_count = attempts.count - limit = task.task_definition.scorm_attempt_limit - if test_count > limit && limit != 0 - error!({ message: 'Attempt limit has been reached' }, 400) - return - end + present test, with: Entities::TestAttemptEntity + end - metadata = params.merge(attempt_number: test_count + 1) - test = TestAttempt.create!(metadata) - present test, with: Entities::TestAttemptEntity + desc 'Initiate a new test attempt' + params do + requires :project_id, type: Integer, desc: 'The id of the project with the task' + requires :task_definition_id, type: Integer, desc: 'The id of the task definition related to the task' + end + post '/projects/:project_id/task_def_id/:task_definition_id/test_attempts' do + project = Project.find(params[:project_id]) + task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + task = project.task_for_task_definition(task_definition) + + attempts = TestAttempt.where("task_id = ?", task.id) + + # check attempt limit + test_count = attempts.count + limit = task.task_definition.scorm_attempt_limit + if test_count > limit && limit != 0 + error!({ message: 'Attempt limit has been reached' }, 400) + return end - desc 'Update an existing session' - params do - requires :task_id, type: Integer, desc: 'ID of the associated task' - requires :id, type: String, desc: 'ID of the test attempt' - optional :cmi_datamodel, type: String, desc: 'JSON CMI datamodel to update' - optional :terminated, type: Boolean, desc: 'Terminate the current session' - end - patch ':task_id/session/:id' do - session_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) - test = TestAttempt.find(params[:id]) - - unless test.terminated - test.update!(session_data) - test.save! - if params[:terminated] - task = Task.find(test.task_id) - task.add_scorm_comment(test) - end + metadata = params.merge(attempt_number: test_count + 1) + test = TestAttempt.create!(metadata) + present test, with: Entities::TestAttemptEntity + end + + desc 'Update an existing attempt' + params do + requires :id, type: String, desc: 'ID of the test attempt' + optional :cmi_datamodel, type: String, desc: 'JSON CMI datamodel to update' + optional :terminated, type: Boolean, desc: 'Terminate the current attempt' + end + patch 'test_attempts/:id' do + attempt_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) + test = TestAttempt.find(params[:id]) + + unless test.terminated + test.update!(attempt_data) + test.save! + if params[:terminated] + task = Task.find(test.task_id) + task.add_scorm_comment(test) end - present test, with: Entities::TestAttemptEntity end + present test, with: Entities::TestAttemptEntity + end - desc 'Delete a test attempt' - params do - requires :task_id, type: Integer, desc: 'ID of the associated task' - requires :id, type: String, desc: 'ID of the test attempt' - end - delete ':task_id/:id' do - raise NotImplementedError - # TODO: fix permissions before enabling this + desc 'Delete a test attempt' + params do + requires :id, type: String, desc: 'ID of the test attempt' + end + delete 'test_attempts/:id' do + raise NotImplementedError + # TODO: fix permissions before enabling this - # test = TestAttempt.find(params[:id]) - # test.destroy! - end + # test = TestAttempt.find(params[:id]) + # test.destroy! end end diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index b8f990693..7807de244 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -74,7 +74,7 @@ def cmi_datamodel=(data) raise "Terminated entries should not be updated" end - # set cmi.entry to resume if the session is in progress + # set cmi.entry to resume if the attempt is in progress if new_data['cmi.completion_status'] == 'incomplete' new_data['cmi.entry'] = 'resume' end From 8c9a68ba6b3914da24ba33ee62f6a5a00e101c76 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sun, 2 Jun 2024 02:04:36 +1000 Subject: [PATCH 032/124] feat: enable reviewing, passing, and deleting test attempts --- app/api/test_attempts_api.rb | 29 +++++++++------ app/models/comments/scorm_comment.rb | 16 ++++++++ app/models/task.rb | 13 +------ app/models/test_attempt.rb | 37 ++++++++++++++++++- ...103707_add_test_attempt_link_to_comment.rb | 7 ++++ db/schema.rb | 4 +- 6 files changed, 79 insertions(+), 27 deletions(-) create mode 100644 app/models/comments/scorm_comment.rb create mode 100644 db/migrate/20240601103707_add_test_attempt_link_to_comment.rb diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 7196e6b62..97988d857 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -77,7 +77,7 @@ class TestAttemptsApi < Grape::API attempt.review # TODO: add review permission flag to taskdef end - present test, with: Entities::TestAttemptEntity + present attempt, with: Entities::TestAttemptEntity end desc 'Initiate a new test attempt' @@ -100,7 +100,7 @@ class TestAttemptsApi < Grape::API return end - metadata = params.merge(attempt_number: test_count + 1) + metadata = { task_id: task.id, attempt_number: test_count + 1 } test = TestAttempt.create!(metadata) present test, with: Entities::TestAttemptEntity end @@ -110,19 +110,25 @@ class TestAttemptsApi < Grape::API requires :id, type: String, desc: 'ID of the test attempt' optional :cmi_datamodel, type: String, desc: 'JSON CMI datamodel to update' optional :terminated, type: Boolean, desc: 'Terminate the current attempt' + optional :success_status, type: Boolean, desc: 'Override the success status of the current attempt' end patch 'test_attempts/:id' do - attempt_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) test = TestAttempt.find(params[:id]) - unless test.terminated - test.update!(attempt_data) - test.save! - if params[:terminated] - task = Task.find(test.task_id) - task.add_scorm_comment(test) + if params[:success_status].present? + test.override_success_status(params[:success_status]) + else + attempt_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) + + unless test.terminated + test.update!(attempt_data) + test.save! + if params[:terminated] + test.add_scorm_comment + end end end + present test, with: Entities::TestAttemptEntity end @@ -131,10 +137,9 @@ class TestAttemptsApi < Grape::API requires :id, type: String, desc: 'ID of the test attempt' end delete 'test_attempts/:id' do - raise NotImplementedError # TODO: fix permissions before enabling this - # test = TestAttempt.find(params[:id]) - # test.destroy! + test = TestAttempt.find(params[:id]) + test.destroy! end end diff --git a/app/models/comments/scorm_comment.rb b/app/models/comments/scorm_comment.rb new file mode 100644 index 000000000..16502f50a --- /dev/null +++ b/app/models/comments/scorm_comment.rb @@ -0,0 +1,16 @@ +class ScormComment < TaskComment + belongs_to :test_attempt, optional: false + + before_create do + self.content_type = :scorm + end + + def serialize(user) + json = super(user) + json[:test_attempt] = { + id: self.test_attempt_id, + success_status: self.test_attempt.success_status + } + json + end +end diff --git a/app/models/task.rb b/app/models/task.rb index 916f9ce76..37077a5cd 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -123,6 +123,7 @@ def specific_permission_hash(role, perm_hash, _other) has_many :task_submissions, dependent: :destroy has_many :overseer_assessments, dependent: :destroy has_many :tii_submissions, dependent: :destroy + has_many :test_attempts, dependent: :destroy delegate :unit, to: :project delegate :student, to: :project @@ -668,18 +669,6 @@ def add_text_comment(user, text, reply_to_id = nil) comment end - def add_scorm_comment(test) - comment = TaskComment.create - comment.task = self - comment.user = self.tutor - comment.comment = "Test Attempt #{test.attempt_number} completed with score: #{format("%.2f", test.score_scaled * 100)}%" - comment.content_type = 'scorm' - comment.recipient = project.student - comment.save! - - comment - end - def individual_task_or_submitter_of_group_task? return true if !group_task? # its individual return true unless group.present? # no group yet... so individual diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index 7807de244..b55571214 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -2,6 +2,11 @@ require 'time' class TestAttempt < ApplicationRecord + belongs_to :task, optional: false + + has_one :scorm_comment, dependent: :destroy + + validates :task_id, presence: true def self.permissions # TODO: this is all wrong, students should not be able to delete test attempts @@ -99,8 +104,36 @@ def review write_attribute(:cmi_datamodel, dm.to_json) end - def pass_override - # TODO: implement tutor override pass + def override_success_status(new_success_status) + dm = JSON.parse(self.cmi_datamodel) + dm['cmi.success_status'] = (new_success_status ? 'passed' : 'failed') + write_attribute(:cmi_datamodel, dm.to_json) + self.success_status = dm['cmi.success_status'] == 'passed' + self.save! + self.update_scorm_comment end + def add_scorm_comment + comment = ScormComment.create + comment.task = task + comment.user = task.tutor + comment.comment = "Test attempt #{self.attempt_number} #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" + comment.recipient = task.student + comment.test_attempt = self + comment.save! + + comment + end + + def update_scorm_comment + if self.scorm_comment.present? + self.scorm_comment.comment = "Test attempt #{self.attempt_number} #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" + self.scorm_comment.save! + + return self.scorm_comment + end + + puts "WARN: Unexpected need to create scorm comment for test attempt: #{self.id}" + add_scorm_comment + end end diff --git a/db/migrate/20240601103707_add_test_attempt_link_to_comment.rb b/db/migrate/20240601103707_add_test_attempt_link_to_comment.rb new file mode 100644 index 000000000..51db18b9e --- /dev/null +++ b/db/migrate/20240601103707_add_test_attempt_link_to_comment.rb @@ -0,0 +1,7 @@ +class AddTestAttemptLinkToComment < ActiveRecord::Migration[7.1] + def change + # Link to corresponding SCORM test attempt for scorm comments + add_column :task_comments, :test_attempt_id, :integer + add_index :task_comments, :test_attempt_id + end +end diff --git a/db/schema.rb b/db/schema.rb index 5d6c3ff34..509ebb67a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_05_28_223908) do +ActiveRecord::Schema[7.1].define(version: 2024_06_01_103707) do create_table "activity_types", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t| t.string "name", null: false t.string "abbreviation", null: false @@ -215,6 +215,7 @@ t.string "extension_response" t.bigint "reply_to_id" t.bigint "overseer_assessment_id" + t.integer "test_attempt_id" t.index ["assessor_id"], name: "index_task_comments_on_assessor_id" t.index ["discussion_comment_id"], name: "index_task_comments_on_discussion_comment_id" t.index ["overseer_assessment_id"], name: "index_task_comments_on_overseer_assessment_id" @@ -222,6 +223,7 @@ t.index ["reply_to_id"], name: "index_task_comments_on_reply_to_id" t.index ["task_id"], name: "index_task_comments_on_task_id" t.index ["task_status_id"], name: "index_task_comments_on_task_status_id" + t.index ["test_attempt_id"], name: "index_task_comments_on_test_attempt_id" t.index ["user_id"], name: "index_task_comments_on_user_id" end From c5055b858c30ba693c535590e1ccff0e8e0b42da Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:18:20 +1000 Subject: [PATCH 033/124] feat: enable students to request extra scorm attempt --- app/api/api_root.rb | 2 + app/api/entities/task_entity.rb | 1 + app/api/scorm_extension_comments_api.rb | 49 +++++++++++++++++++ app/api/tasks_api.rb | 3 +- .../comments/scorm_extension_comment.rb | 45 +++++++++++++++++ app/models/project.rb | 1 + app/models/task.rb | 36 +++++++++++++- .../20240603020127_add_scorm_extensions.rb | 5 ++ db/schema.rb | 3 +- 9 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 app/api/scorm_extension_comments_api.rb create mode 100644 app/models/comments/scorm_extension_comment.rb create mode 100644 db/migrate/20240603020127_add_scorm_extensions.rb diff --git a/app/api/api_root.rb b/app/api/api_root.rb index 030bd313d..4ea753b8b 100644 --- a/app/api/api_root.rb +++ b/app/api/api_root.rb @@ -55,6 +55,7 @@ class ApiRoot < Grape::API mount BreaksApi mount DiscussionCommentApi mount ExtensionCommentsApi + mount ScormExtensionCommentsApi mount GroupSetsApi mount LearningOutcomesApi mount LearningAlignmentApi @@ -98,6 +99,7 @@ class ApiRoot < Grape::API AuthenticationHelpers.add_auth_to BreaksApi AuthenticationHelpers.add_auth_to DiscussionCommentApi AuthenticationHelpers.add_auth_to ExtensionCommentsApi + AuthenticationHelpers.add_auth_to ScormExtensionCommentsApi AuthenticationHelpers.add_auth_to GroupSetsApi AuthenticationHelpers.add_auth_to LearningOutcomesApi AuthenticationHelpers.add_auth_to LearningAlignmentApi diff --git a/app/api/entities/task_entity.rb b/app/api/entities/task_entity.rb index cd88b53eb..ffb53bd86 100644 --- a/app/api/entities/task_entity.rb +++ b/app/api/entities/task_entity.rb @@ -17,6 +17,7 @@ class TaskEntity < Grape::Entity end expose :extensions + expose :scorm_extensions expose :times_assessed expose :grade, expose_nil: false diff --git a/app/api/scorm_extension_comments_api.rb b/app/api/scorm_extension_comments_api.rb new file mode 100644 index 000000000..5d5d52b88 --- /dev/null +++ b/app/api/scorm_extension_comments_api.rb @@ -0,0 +1,49 @@ +require 'grape' + +class ScormExtensionCommentsApi < Grape::API + helpers AuthenticationHelpers + helpers AuthorisationHelpers + + desc 'Request a scorm extension for a task' + params do + requires :comment, type: String, desc: 'The details of the request' + end + post '/projects/:project_id/task_def_id/:task_definition_id/request_scorm_extension' do + project = Project.find(params[:project_id]) + task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + task = project.task_for_task_definition(task_definition) + + # check permissions using specific permission has with addition of request extension if allowed in unit + unless authorise? current_user, task, :request_scorm_extension + error!({ error: 'Not authorised to request a scorm extension for this task' }, 403) + end + + result = task.apply_for_scorm_extension(current_user, params[:comment]) + present result.serialize(current_user), Grape::Presenters::Presenter + end + + desc 'Assess a scorm extension for a task' + params do + requires :granted, type: Boolean, desc: 'Assess a scorm extension' + end + put '/projects/:project_id/task_def_id/:task_definition_id/assess_scorm_extension/:task_comment_id' do + project = Project.find(params[:project_id]) + task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + task = project.task_for_task_definition(task_definition) + + unless authorise? current_user, task, :assess_scorm_extension + error!({ error: 'Not authorised to assess a scorm extension for this task' }, 403) + end + + task_comment = task.all_comments.find(params[:task_comment_id]).becomes(ScormExtensionComment) + + unless task_comment.assess_scorm_extension(current_user, params[:granted]) + if task_comment.errors.count >= 1 + error!({ error: task_comment.errors.full_messages.first }, 403) + else + error!({ error: 'Error saving scorm extension' }, 403) + end + end + present task_comment.serialize(current_user), Grape::Presenters::Presenter + end +end diff --git a/app/api/tasks_api.rb b/app/api/tasks_api.rb index 10e45917e..d2720c22d 100644 --- a/app/api/tasks_api.rb +++ b/app/api/tasks_api.rb @@ -72,7 +72,8 @@ class TasksApi < Grape::API task_definition_id: task.task_definition_id, status: TaskStatus.id_to_key(task.task_status_id), due_date: task.due_date, - extensions: task.extensions + extensions: task.extensions, + scorm_extensions: task.scorm_extensions } end diff --git a/app/models/comments/scorm_extension_comment.rb b/app/models/comments/scorm_extension_comment.rb new file mode 100644 index 000000000..7e0ef7709 --- /dev/null +++ b/app/models/comments/scorm_extension_comment.rb @@ -0,0 +1,45 @@ +class ScormExtensionComment < TaskComment + belongs_to :assessor, class_name: 'User', optional: true + + def serialize(user) + json = super(user) + json[:granted] = extension_granted + json[:assessed] = date_extension_assessed.present? + json[:date_assessed] = date_extension_assessed + json + end + + def assessed? + self.date_extension_assessed.present? + end + + # Make sure we can access super's version of mark_as_read for assess extension + alias :super_mark_as_read :mark_as_read + + # Allow individual staff and the student to read this... but stop + # the main tutor reading without assessing. As only the main tutor + # propagates reads, this will work as required - other staff cant + # make it read for the main tutor. + def mark_as_read(user, unit = self.unit) + super if assessed? || user == project.student || user != recipient + end + + def assess_scorm_extension(user, granted) + if self.assessed? + self.errors[:scorm_extension] << 'has already been assessed' + return false + end + + self.assessor = user + self.date_extension_assessed = Time.zone.now + self.extension_granted = granted + + if self.extension_granted + self.task.grant_scorm_extension(user) + end + + # Now make sure to read it by the main tutor - even if assessed by someone else + super_mark_as_read(project.tutor_for(task.task_definition)) + save! + end +end diff --git a/app/models/project.rb b/app/models/project.rb index c0770cf87..82644c3d6 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -292,6 +292,7 @@ def task_details_for_shallow_serializer(user) num_new_comments: r.number_unread, similarity_flag: AuthorisationHelpers.authorise?(user, t, :view_plagiarism) ? r.similar_to_count > 0 : false, extensions: t.extensions, + scorm_extensions: t.scorm_extensions, due_date: t.due_date, submission_date: t.submission_date, completion_date: t.completion_date diff --git a/app/models/task.rb b/app/models/task.rb index 37077a5cd..406dd005f 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -18,6 +18,7 @@ def self.permissions :start_discussion, :get_discussion, :make_discussion_reply, + :request_scorm_extension, # :request_extension -- depends on settings in unit. See specific_permission_hash method ] # What can tutors do with tasks? @@ -34,7 +35,9 @@ def self.permissions :delete_discussion, :get_discussion, :assess_extension, - :request_extension + :assess_scorm_extension, + :request_extension, + :request_scorm_extension ] # What can convenors do with tasks? convenor_role_permissions = [ @@ -47,7 +50,9 @@ def self.permissions :delete_plagiarism, :get_discussion, :assess_extension, - :request_extension + :assess_scorm_extension, + :request_extension, + :request_scorm_extension ] # What can admins do with tasks? admin_role_permissions = [ @@ -312,6 +317,33 @@ def grant_extension(by_user, weeks) end end + # Applying for a scorm extension will create a scorm extension comment + def apply_for_scorm_extension(user, text) + extension = ScormExtensionComment.create + extension.task = self + extension.user = user + extension.content_type = :scorm_extension + extension.comment = text + extension.recipient = unit.main_convenor_user + extension.save! + + # Check and apply those requested by staff + if role_for(user) == :tutor + extension.assess_scorm_extension user, true + end + + extension + end + + # Add a scorm extension to the task + def grant_scorm_extension(by_user) + if update(scorm_extensions: self.scorm_extensions + 1) + return true + else + return false + end + end + def due_date return target_date if extensions == 0 diff --git a/db/migrate/20240603020127_add_scorm_extensions.rb b/db/migrate/20240603020127_add_scorm_extensions.rb new file mode 100644 index 000000000..0e549611d --- /dev/null +++ b/db/migrate/20240603020127_add_scorm_extensions.rb @@ -0,0 +1,5 @@ +class AddScormExtensions < ActiveRecord::Migration[7.1] + def change + add_column :tasks, :scorm_extensions, :integer, null: false, default: 0 + end +end diff --git a/db/schema.rb b/db/schema.rb index 509ebb67a..c823fd1d4 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_01_103707) do +ActiveRecord::Schema[7.1].define(version: 2024_06_03_020127) do create_table "activity_types", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t| t.string "name", null: false t.string "abbreviation", null: false @@ -334,6 +334,7 @@ t.integer "contribution_pts", default: 3 t.integer "quality_pts", default: -1 t.integer "extensions", default: 0, null: false + t.integer "scorm_extensions", default: 0, null: false t.index ["group_submission_id"], name: "index_tasks_on_group_submission_id" t.index ["project_id", "task_definition_id"], name: "tasks_uniq_proj_task_def", unique: true t.index ["project_id"], name: "index_tasks_on_project_id" From 1e00d41d9728b7c8ff34e8c7cda896fa3e3e1ff1 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:01:34 +1000 Subject: [PATCH 034/124] test: add sample numbas zip --- test_files/numbas.zip | Bin 0 -> 754023 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test_files/numbas.zip diff --git a/test_files/numbas.zip b/test_files/numbas.zip new file mode 100644 index 0000000000000000000000000000000000000000..2ea1ef5a98532218406af4e21dc0aaaceaaa93d8 GIT binary patch literal 754023 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�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

4;^9k~hom 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

xdpgeGl$@SjWZi-f!<1v>Xkx&xmTb&ayQj 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Ł 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 Date: Wed, 5 Jun 2024 23:41:32 +1000 Subject: [PATCH 035/124] fix: calculate attempt number and limit instead of using stored int --- app/api/entities/test_attempt_entity.rb | 1 - app/api/test_attempts_api.rb | 7 +++---- app/models/test_attempt.rb | 6 +++++- db/migrate/20231205011842_create_test_attempts.rb | 1 - db/schema.rb | 1 - 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/api/entities/test_attempt_entity.rb b/app/api/entities/test_attempt_entity.rb index 23f343790..d0d5ebc07 100644 --- a/app/api/entities/test_attempt_entity.rb +++ b/app/api/entities/test_attempt_entity.rb @@ -3,7 +3,6 @@ class TestAttemptEntity < Grape::Entity expose :id expose :task_id expose :attempted_time - expose :attempt_number expose :terminated expose :success_status expose :score_scaled diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 97988d857..12bb8d738 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -94,14 +94,13 @@ class TestAttemptsApi < Grape::API # check attempt limit test_count = attempts.count - limit = task.task_definition.scorm_attempt_limit - if test_count > limit && limit != 0 + limit = task.task_definition.scorm_attempt_limit + task.scorm_extensions + if limit != 0 && test_count == limit error!({ message: 'Attempt limit has been reached' }, 400) return end - metadata = { task_id: task.id, attempt_number: test_count + 1 } - test = TestAttempt.create!(metadata) + test = TestAttempt.create!({ task_id: task.id }) present test, with: Entities::TestAttemptEntity end diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index b55571214..e03aec023 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -43,7 +43,6 @@ def self.permissions # extra non-cmi metadata # t.datetime :attempted_time, null:false - # t.integer :attempt_number, default: 1, null: false # t.boolean :terminated, default: false # fields that must be synced from cmi data whenever it's updated @@ -93,6 +92,11 @@ def cmi_datamodel=(data) write_attribute(:cmi_datamodel, new_data.to_json) end + def attempt_number + attempts = TestAttempt.where("task_id = ?", self.task_id) + attempts.count + end + def review dm = JSON.parse(self.cmi_datamodel) if dm['cmi.completion_status'] != 'completed' diff --git a/db/migrate/20231205011842_create_test_attempts.rb b/db/migrate/20231205011842_create_test_attempts.rb index dadc75084..c09160615 100644 --- a/db/migrate/20231205011842_create_test_attempts.rb +++ b/db/migrate/20231205011842_create_test_attempts.rb @@ -3,7 +3,6 @@ def change create_table :test_attempts do |t| t.references :task t.datetime :attempted_time, null:false - t.integer :attempt_number, default: 1, null: false t.boolean :terminated, default: false t.boolean :completion_status, default: false t.boolean :success_status, default: false diff --git a/db/schema.rb b/db/schema.rb index c823fd1d4..ea4362886 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -354,7 +354,6 @@ create_table "test_attempts", charset: "utf8mb4", collation: "utf8mb4_general_ci", force: :cascade do |t| t.bigint "task_id" t.datetime "attempted_time", null: false - t.integer "attempt_number", default: 1, null: false t.boolean "terminated", default: false t.boolean "completion_status", default: false t.boolean "success_status", default: false From 7d31f7caaae6dc1efa24f78842873e9f55796279 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:49:43 +1000 Subject: [PATCH 036/124] feat: add test attempt auth --- app/api/test_attempts_api.rb | 55 ++++++++++++++++++++++++++++++------ app/models/task.rb | 6 +++- app/models/test_attempt.rb | 31 ++++++++++++++------ 3 files changed, 73 insertions(+), 19 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 12bb8d738..50cb06aa4 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -5,9 +5,9 @@ class TestAttemptsApi < Grape::API helpers AuthenticationHelpers - # before do - # authenticated? - # end + before do + authenticated? + end # Handle common exceptions rescue_from :all do |e| @@ -30,6 +30,11 @@ class TestAttemptsApi < Grape::API get '/projects/:project_id/task_def_id/:task_definition_id/test_attempts' do project = Project.find(params[:project_id]) task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + + unless authorise? current_user, project, :get_submission + error!({ error: "Not authorized to get scorm attempts for task" }, 403) + end + task = project.task_for_task_definition(task_definition) attempts = TestAttempt.where("task_id = ?", task.id) @@ -46,6 +51,11 @@ class TestAttemptsApi < Grape::API get '/projects/:project_id/task_def_id/:task_definition_id/test_attempts/latest' do project = Project.find(params[:project_id]) task_definition = project.unit.task_definitions.find(params[:task_definition_id]) + + unless authorise? current_user, project, :get_submission + error!({ error: "Not authorized to get latest scorm attempt for task" }, 403) + end + task = project.task_for_task_definition(task_definition) attempts = TestAttempt.where("task_id = ?", task.id) @@ -68,16 +78,27 @@ class TestAttemptsApi < Grape::API requires :id, type: Integer, desc: 'Test attempt ID to review' end get 'test_attempts/:id/review' do - attempt = TestAttempt.find(params[:id]) - if attempt.nil? + test = TestAttempt.find(params[:id]) + + key = if current_user == test.student + :review_own_attempt + else + :review_other_attempt + end + + unless authorise? current_user, test, key, ->(role, perm_hash, other) { test.specific_permission_hash(role, perm_hash, other) } + error!({ error: 'Not authorised to review this scorm attempt' }, 403) + end + + if test.nil? error!({ message: 'Test attempt ID is invalid' }, 404) return else logger.debug "Request to review test attempt #{params[:id]}" - attempt.review + test.review # TODO: add review permission flag to taskdef end - present attempt, with: Entities::TestAttemptEntity + present test, with: Entities::TestAttemptEntity end desc 'Initiate a new test attempt' @@ -90,6 +111,11 @@ class TestAttemptsApi < Grape::API task_definition = project.unit.task_definitions.find(params[:task_definition_id]) task = project.task_for_task_definition(task_definition) + # check permissions using specific permission has with addition of make scorm attempt if scorm is enabled in task def + unless authorise? current_user, task, :make_scorm_attempt, ->(role, perm_hash, other) { task.specific_permission_hash(role, perm_hash, other) } + error!({ error: 'Not authorised to make a scorm attempt for this task' }, 403) + end + attempts = TestAttempt.where("task_id = ?", task.id) # check attempt limit @@ -115,8 +141,16 @@ class TestAttemptsApi < Grape::API test = TestAttempt.find(params[:id]) if params[:success_status].present? + unless authorise? current_user, test, :override_success_status + error!({ error: 'Not authorised to override the success status of this scorm attempt' }, 403) + end + test.override_success_status(params[:success_status]) else + unless authorise? current_user, test, :update_attempt + error!({ error: 'Not authorised to update this scorm attempt' }, 403) + end + attempt_data = ActionController::Parameters.new(params).permit(:cmi_datamodel, :terminated) unless test.terminated @@ -136,9 +170,12 @@ class TestAttemptsApi < Grape::API requires :id, type: String, desc: 'ID of the test attempt' end delete 'test_attempts/:id' do - # TODO: fix permissions before enabling this - test = TestAttempt.find(params[:id]) + + unless authorise? current_user, test, :delete_attempt + error!({ error: 'Not authorised to delete this scorm attempt' }, 403) + end + test.destroy! end end diff --git a/app/models/task.rb b/app/models/task.rb index 406dd005f..a9a272585 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -20,6 +20,7 @@ def self.permissions :make_discussion_reply, :request_scorm_extension, # :request_extension -- depends on settings in unit. See specific_permission_hash method + # :make_scorm_attempt -- depends on task def settings. See specific_permission_hash method ] # What can tutors do with tasks? tutor_role_permissions = [ @@ -99,12 +100,15 @@ def role_for(user) end # Used to adjust the request extension permission in units that do not - # allow students to request extensions + # allow students to request extensions and the make scorm attempt permission def specific_permission_hash(role, perm_hash, _other) result = perm_hash[role] unless perm_hash.nil? if result && role == :student && unit.allow_student_extension_requests result << :request_extension end + if result && role == :student && task_definition.scorm_enabled + result << :make_scorm_attempt + end result end diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index e03aec023..0d73736c7 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -4,28 +4,32 @@ class TestAttempt < ApplicationRecord belongs_to :task, optional: false + has_one :task_definition, through: :task + has_one :scorm_comment, dependent: :destroy + delegate :role_for, to: :task + delegate :student, to: :task + validates :task_id, presence: true def self.permissions # TODO: this is all wrong, students should not be able to delete test attempts student_role_permissions = [ - :create, - :view_own, - :delete_own + :update_attempt + # :review_own_attempt -- depends on task def settings. See specific_permission_hash method ] tutor_role_permissions = [ - :create, - :view_own, - :delete_own + :review_other_attempt, + :override_success_status, + :delete_attempt ] convenor_role_permissions = [ - :create, - :view_own, - :delete_own + :review_other_attempt, + :override_success_status, + :delete_attempt ] nil_role_permissions = [] @@ -38,6 +42,15 @@ def self.permissions } end + # Used to adjust the review own attempt permission based on task def setting + def specific_permission_hash(role, perm_hash, _other) + result = perm_hash[role] unless perm_hash.nil? + if result && role == :student && task_definition.scorm_allow_review + result << :review_own_attempt + end + result + end + # task # t.references :task From 273b62e1acf6897f5d55430f41d75310e5f006ef Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 11 Jun 2024 14:52:15 +1000 Subject: [PATCH 037/124] refactor: remove attempt number in task comment text --- app/models/test_attempt.rb | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index 0d73736c7..690172d51 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -105,11 +105,6 @@ def cmi_datamodel=(data) write_attribute(:cmi_datamodel, new_data.to_json) end - def attempt_number - attempts = TestAttempt.where("task_id = ?", self.task_id) - attempts.count - end - def review dm = JSON.parse(self.cmi_datamodel) if dm['cmi.completion_status'] != 'completed' @@ -134,7 +129,7 @@ def add_scorm_comment comment = ScormComment.create comment.task = task comment.user = task.tutor - comment.comment = "Test attempt #{self.attempt_number} #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" + comment.comment = "Test attempt #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" comment.recipient = task.student comment.test_attempt = self comment.save! @@ -144,7 +139,7 @@ def add_scorm_comment def update_scorm_comment if self.scorm_comment.present? - self.scorm_comment.comment = "Test attempt #{self.attempt_number} #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" + self.scorm_comment.comment = "Test attempt #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" self.scorm_comment.save! return self.scorm_comment From 3d44ef2ea57829131cc3c70d1655ccd996154ee2 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:43:45 +1000 Subject: [PATCH 038/124] fix: grant same number of extra attempts as scorm limit --- app/models/task.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/task.rb b/app/models/task.rb index a9a272585..6978814c6 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -341,7 +341,7 @@ def apply_for_scorm_extension(user, text) # Add a scorm extension to the task def grant_scorm_extension(by_user) - if update(scorm_extensions: self.scorm_extensions + 1) + if update(scorm_extensions: self.scorm_extensions + task_definition.scorm_attempt_limit) return true else return false From 1240b3fa853d3a3f3fd1ad061f9cc6f6635c2c37 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 11 Jun 2024 23:39:41 +1000 Subject: [PATCH 039/124] fix: prevent new attempt if last is incomplete or passed --- app/api/test_attempts_api.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 50cb06aa4..4dc7a9c28 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -96,7 +96,6 @@ class TestAttemptsApi < Grape::API else logger.debug "Request to review test attempt #{params[:id]}" test.review - # TODO: add review permission flag to taskdef end present test, with: Entities::TestAttemptEntity end @@ -118,6 +117,18 @@ class TestAttemptsApi < Grape::API attempts = TestAttempt.where("task_id = ?", task.id) + # check if last attempt is complete + last_attempt = attempts.order(id: :desc).first + if last_attempt.completion_status == false + error!({ message: 'An attempt is still ongoing. Cannot initiate new attempt.' }, 400) + return + end + + # check if last attempt is a pass + if last_attempt.success_status == true + error!({ message: 'User has passed the SCORM test. Cannot initiate more attempts.' }, 400) + end + # check attempt limit test_count = attempts.count limit = task.task_definition.scorm_attempt_limit + task.scorm_extensions From 1ae03478bb2c55b5e281a876bae37f730206ac3e Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:34:29 +1000 Subject: [PATCH 040/124] fix: prevent scorm extensions if no attempt limit --- app/api/scorm_extension_comments_api.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/api/scorm_extension_comments_api.rb b/app/api/scorm_extension_comments_api.rb index 5d5d52b88..7a8626dc5 100644 --- a/app/api/scorm_extension_comments_api.rb +++ b/app/api/scorm_extension_comments_api.rb @@ -18,6 +18,11 @@ class ScormExtensionCommentsApi < Grape::API error!({ error: 'Not authorised to request a scorm extension for this task' }, 403) end + if task_definition.scorm_attempt_limit == 0 + error!({ message: 'This task allows unlimited attempts to complete the test' }, 400) + return + end + result = task.apply_for_scorm_extension(current_user, params[:comment]) present result.serialize(current_user), Grape::Presenters::Presenter end From 42553479eb2a018a9273931e033084e26b3d18d5 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:35:22 +1000 Subject: [PATCH 041/124] fix: check for attempts before accessing properties --- app/api/test_attempts_api.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 4dc7a9c28..9e8c91539 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -116,21 +116,22 @@ class TestAttemptsApi < Grape::API end attempts = TestAttempt.where("task_id = ?", task.id) + test_count = attempts.count # check if last attempt is complete last_attempt = attempts.order(id: :desc).first - if last_attempt.completion_status == false + if test_count > 0 && last_attempt.terminated == false error!({ message: 'An attempt is still ongoing. Cannot initiate new attempt.' }, 400) return end # check if last attempt is a pass - if last_attempt.success_status == true + if test_count > 0 && last_attempt.success_status == true error!({ message: 'User has passed the SCORM test. Cannot initiate more attempts.' }, 400) + return end # check attempt limit - test_count = attempts.count limit = task.task_definition.scorm_attempt_limit + task.scorm_extensions if limit != 0 && test_count == limit error!({ message: 'Attempt limit has been reached' }, 400) From fce7e7519bb9171726a030b409aee23de65f44fd Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:36:21 +1000 Subject: [PATCH 042/124] feat: add attribute to allow file upload before scorm is passed --- app/api/entities/task_definition_entity.rb | 1 + app/api/task_definitions_api.rb | 4 ++++ app/models/task_definition.rb | 10 ++++++++-- db/migrate/20231205011842_create_test_attempts.rb | 2 +- .../20240322021829_add_scorm_config_to_task_def.rb | 4 +++- db/schema.rb | 1 + test/api/units/task_definitions_api_test.rb | 1 + test/models/task_definition_test.rb | 2 +- test_files/COS10001-ImportTasksWithTutorialStream.csv | 2 +- .../COS10001-ImportTasksWithoutTutorialStream.csv | 2 +- test_files/COS10001-Tasks.csv | 2 +- test_files/csv_test_files/COS10001-Tasks.csv | 2 +- test_files/unit_csv_imports/import_group_tasks.csv | 2 +- 13 files changed, 25 insertions(+), 10 deletions(-) diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index f99b2d73d..efb69f591 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -42,6 +42,7 @@ def staff?(my_role) expose :has_scorm_data?, as: :has_scorm_data expose :scorm_enabled expose :scorm_allow_review + expose :scorm_bypass_test expose :scorm_time_delay_enabled expose :scorm_attempt_limit expose :is_graded diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index db1f70b6b..0f9d4fa69 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -30,6 +30,7 @@ class TaskDefinitionsApi < Grape::API requires :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' requires :scorm_enabled, type: Boolean, desc: 'Whether SCORM assessment is enabled for this task' requires :scorm_allow_review, type: Boolean, desc: 'Whether a student is allowed to review their completed test attempts' + requires :scorm_bypass_test, type: Boolean, desc: 'Whether a student is allowed to upload files before passing SCORM test' requires :scorm_time_delay_enabled, type: Boolean, desc: 'Whether there is an incremental time delay between SCORM test attempts' requires :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' requires :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' @@ -63,6 +64,7 @@ class TaskDefinitionsApi < Grape::API :plagiarism_warn_pct, :scorm_enabled, :scorm_allow_review, + :scorm_bypass_test, :scorm_time_delay_enabled, :scorm_attempt_limit, :is_graded, @@ -116,6 +118,7 @@ class TaskDefinitionsApi < Grape::API optional :plagiarism_warn_pct, type: Integer, desc: 'The percent at which to record and warn about plagiarism' optional :scorm_enabled, type: Boolean, desc: 'Whether or not SCORM test assessment is enabled for this task' optional :scorm_allow_review, type: Boolean, desc: 'Whether a student is allowed to review their completed test attempts' + optional :scorm_bypass_test, type: Boolean, desc: 'Whether a student is allowed to upload files before passing SCORM test' optional :scorm_time_delay_enabled, type: Boolean, desc: 'Whether or not there is an incremental time delay between SCORM test attempts' optional :scorm_attempt_limit, type: Integer, desc: 'The number of times a SCORM test can be attempted' optional :is_graded, type: Boolean, desc: 'Whether or not this task definition is a graded task' @@ -148,6 +151,7 @@ class TaskDefinitionsApi < Grape::API :plagiarism_warn_pct, :scorm_enabled, :scorm_allow_review, + :scorm_bypass_test, :scorm_time_delay_enabled, :scorm_attempt_limit, :is_graded, diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 88c907d4e..59c798505 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -301,8 +301,8 @@ def to_csv_row def self.csv_columns [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, - :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :scorm_enabled, - :scorm_allow_review, :scorm_time_delay_enabled, :scorm_attempt_limit, :start_week, :start_day, :target_week, + :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :scorm_enabled, :scorm_allow_review, + :scorm_bypass_test, :scorm_time_delay_enabled, :scorm_attempt_limit, :start_week, :start_day, :target_week, :target_day, :due_week, :due_day, :tutorial_stream] end @@ -351,6 +351,7 @@ def self.task_def_for_csv_row(unit, row) result.scorm_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_enabled]}".strip result.scorm_allow_review = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_allow_review]}".strip + result.scorm_bypass_test = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_bypass_test]}".strip result.scorm_time_delay_enabled = %w(Yes y Y yes true TRUE 1).include? "#{row[:scorm_time_delay_enabled]}".strip result.scorm_attempt_limit = row[:scorm_attempt_limit].to_i @@ -412,6 +413,10 @@ def scorm_allow_review? scorm_allow_review end + def scorm_bypass_test? + scorm_bypass_test + end + def scorm_time_delay_enabled? scorm_time_delay_enabled end @@ -614,6 +619,7 @@ def task_scorm_data_with_abbreviation(abbr) def reset_scorm_config() self.scorm_enabled = false self.scorm_allow_review = false + self.scorm_bypass_test = false self.scorm_time_delay_enabled = false self.scorm_attempt_limit = 0 end diff --git a/db/migrate/20231205011842_create_test_attempts.rb b/db/migrate/20231205011842_create_test_attempts.rb index c09160615..3f7004a81 100644 --- a/db/migrate/20231205011842_create_test_attempts.rb +++ b/db/migrate/20231205011842_create_test_attempts.rb @@ -2,7 +2,7 @@ class CreateTestAttempts < ActiveRecord::Migration[7.0] def change create_table :test_attempts do |t| t.references :task - t.datetime :attempted_time, null:false + t.datetime :attempted_time, null: false t.boolean :terminated, default: false t.boolean :completion_status, default: false t.boolean :success_status, default: false diff --git a/db/migrate/20240322021829_add_scorm_config_to_task_def.rb b/db/migrate/20240322021829_add_scorm_config_to_task_def.rb index 5daa69c72..99c7dcffb 100644 --- a/db/migrate/20240322021829_add_scorm_config_to_task_def.rb +++ b/db/migrate/20240322021829_add_scorm_config_to_task_def.rb @@ -3,6 +3,7 @@ def change change_table :task_definitions do |t| t.boolean :scorm_enabled, default: false t.boolean :scorm_allow_review, default: false + t.boolean :scorm_bypass_test, default: false t.boolean :scorm_time_delay_enabled, default: false t.integer :scorm_attempt_limit end @@ -11,7 +12,8 @@ def change def down change_table :task_definitions do |t| t.remove :scorm_enabled - t.boolean :scorm_allow_review + t.remove :scorm_allow_review + t.remove :scorm_bypass_test t.remove :scorm_time_delay_enabled t.remove :scorm_attempt_limit end diff --git a/db/schema.rb b/db/schema.rb index ea4362886..66319395c 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -254,6 +254,7 @@ t.string "moss_language" t.boolean "scorm_enabled", default: false t.boolean "scorm_allow_review", default: false + t.boolean "scorm_bypass_test", default: false t.boolean "scorm_time_delay_enabled", default: false t.integer "scorm_attempt_limit" t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" diff --git a/test/api/units/task_definitions_api_test.rb b/test/api/units/task_definitions_api_test.rb index ea0826fe6..663ba880f 100644 --- a/test/api/units/task_definitions_api_test.rb +++ b/test/api/units/task_definitions_api_test.rb @@ -52,6 +52,7 @@ def test_task_definition_cud max_quality_pts: 0, scorm_enabled: false, scorm_allow_review: false, + scorm_bypass_test: false, scorm_time_delay_enabled: true, scorm_attempt_limit: 0 } diff --git a/test/models/task_definition_test.rb b/test/models/task_definition_test.rb index 5210322ef..a292cd1cd 100644 --- a/test/models/task_definition_test.rb +++ b/test/models/task_definition_test.rb @@ -145,7 +145,7 @@ def test_export_task_definitions_csv task_defs_csv = CSV.parse unit.task_definitions_csv, headers: true task_defs_csv.each do |task_def_csv| task_def = unit.task_definitions.find_by(abbreviation: task_def_csv['abbreviation']) - keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'scorm_enabled', 'scorm_allow_review', 'scorm_time_delay_enabled', 'scorm_attempt_limit'] + keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'scorm_enabled', 'scorm_allow_review', 'scorm_bypass_test', 'scorm_time_delay_enabled', 'scorm_attempt_limit'] task_def_csv.each do |key, value| unless keys_to_ignore.include?(key) assert_equal(task_def[key].to_s, value) diff --git a/test_files/COS10001-ImportTasksWithTutorialStream.csv b/test_files/COS10001-ImportTasksWithTutorialStream.csv index 7e1df1062..b36339a21 100644 --- a/test_files/COS10001-ImportTasksWithTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithTutorialStream.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_bypass_test,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks,,, diff --git a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv index 8ed8b6cb4..d5f7eb1e8 100644 --- a/test_files/COS10001-ImportTasksWithoutTutorialStream.csv +++ b/test_files/COS10001-ImportTasksWithoutTutorialStream.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_bypass_test,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,,,, diff --git a/test_files/COS10001-Tasks.csv b/test_files/COS10001-Tasks.csv index d4e15b33a..ae03608c0 100644 --- a/test_files/COS10001-Tasks.csv +++ b/test_files/COS10001-Tasks.csv @@ -1,4 +1,4 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_bypass_test,scorm_time_delay_enabled,scorm_attempt_limit Pass Task 1.1 - Hello World,1.1P,"As a first step, create the classic 'Hello World' program. This will help ensure that you have all of the software installed correctly, and are ready to move on with creating other,,, programs.",1,0,FALSE,"[{""key"":""file0"",""name"":""HelloWorld.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.2 - Picture Drawing,1.2P,Create a program that calls procedures to draw a picture to a window (something other than a house which we use as the example).,2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks Pass Task 1.3 - Creating a Procedure,1.3P,"Now that you have created a program that uses procedures, you can learn how to create your own procedures. Creating procedures will allow you to group your program's actions into procedures that perform meaningful tasks.",2,0,FALSE,"[{""key"":""file0"",""name"":""PictureDrawing.pas"",""type"":""code""},{""key"":""file1"",""name"":""Screenshot"",""type"":""image""}]",1,Tue,2,Tue,5,Mon,0,FALSE,90,,,import-tasks diff --git a/test_files/csv_test_files/COS10001-Tasks.csv b/test_files/csv_test_files/COS10001-Tasks.csv index 25f7728ec..52a9ebe8d 100644 --- a/test_files/csv_test_files/COS10001-Tasks.csv +++ b/test_files/csv_test_files/COS10001-Tasks.csv @@ -1,2 +1,2 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,scorm_enabled,scorm_allow_review,scorm_bypass_test,scorm_time_delay_enabled,scorm_attempt_limit Assignment 12,A12,rerum ut fugit saepe ipsa in quidem,2,0,FALSE,0,FALSE,50,[],,"[{""key"":""file0"",""name"":""Assumenda accusamus quas"",""type"":""image""}]",-1,Sat,1,Mon,13,Mon,,, diff --git a/test_files/unit_csv_imports/import_group_tasks.csv b/test_files/unit_csv_imports/import_group_tasks.csv index 60996825a..e9782cf7e 100644 --- a/test_files/unit_csv_imports/import_group_tasks.csv +++ b/test_files/unit_csv_imports/import_group_tasks.csv @@ -1,3 +1,3 @@ -name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_time_delay_enabled,scorm_attempt_limit +name,abbreviation,description,weighting,target_grade,restrict_status_updates,max_quality_pts,is_graded,plagiarism_warn_pct,plagiarism_checks,group_set,upload_requirements,start_week,start_day,target_week,target_day,due_week,due_day,tutorial_stream,scorm_enabled,scorm_allow_review,scorm_bypass_test,scorm_time_delay_enabled,scorm_attempt_limit Group Import 1,1GI,Test Description - Import,16,0,FALSE,0,FALSE,80,[],Group Work,[],0,Mon,1,Sun,2,Wed,group-tasks-test,,, Missing Group,2GI,Test Description - Import FAIL,16,0,FALSE,0,FALSE,80,[],Group Work1,[],0,Mon,1,Sun,2,Wed,group-tasks-test,,, From 69053ee147503e7916e929aac5c834903c0087ba Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 18 Jun 2024 19:04:24 +1000 Subject: [PATCH 043/124] fix: change scorm comment text --- app/models/test_attempt.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index 690172d51..20dc8facd 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -129,7 +129,7 @@ def add_scorm_comment comment = ScormComment.create comment.task = task comment.user = task.tutor - comment.comment = "Test attempt #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" + comment.comment = success_status_description comment.recipient = task.student comment.test_attempt = self comment.save! @@ -139,7 +139,7 @@ def add_scorm_comment def update_scorm_comment if self.scorm_comment.present? - self.scorm_comment.comment = "Test attempt #{self.success_status ? 'passed' : 'failed'} with score: #{(self.score_scaled * 100).to_i}%" + self.scorm_comment.comment = success_status_description self.scorm_comment.save! return self.scorm_comment @@ -148,4 +148,14 @@ def update_scorm_comment puts "WARN: Unexpected need to create scorm comment for test attempt: #{self.id}" add_scorm_comment end + + def success_status_description + if self.success_status && self.score_scaled == 1 + "Passed without mistakes" + elsif self.success_status && self.score_scaled < 1 + "Passed" + else + "Unsuccessful" + end + end end From 413969069969316f6ea9c515e4ec9da6b332be0a Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 18 Jun 2024 23:28:33 +1000 Subject: [PATCH 044/124] fix: add scorm bypass to excel file --- test_files/csv_test_files/COS10001-Tasks.xlsx | Bin 6673 -> 8817 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/test_files/csv_test_files/COS10001-Tasks.xlsx b/test_files/csv_test_files/COS10001-Tasks.xlsx index 7d44f0e74e707b6681dd78cb68f7cbf3b3942b9a..5da9ad5ee59006dc17c33544cb3b45c11a24b2a8 100644 GIT binary patch literal 8817 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 literal 6673 zcmaJ_1zeMD*QZl@z)&QlLtvDkh=7Pv(xXFQm2uLYCm~^Lr0s_({ z9RlC*dA~;bdDDa3wi&`5WjTVg}VG$?k=MtHM`1u=N*S&#}bwpOQh-a80RhF-%;DZ~qr{)EK4JzFs&S>K$iU$wPtUJi;a5C6Pi z$b^}jxYs4l6=8v2eRNN)&kk4=S(U_c^i)ROY{q6)ODHHNlQ(Wkd&Rj-hMFQ zNMF)YlTXU<@S_^?g>+1_SF#8VCWohJs?84RkzL4s{58#J(iJSnvBOoySH&06o+^0d z1_bB4b9v70FY+GM2nfz^tGy@jlI;9)9;{pSbM<>IqpBi4LF2$(x>>Xr3a~IRRR61= z$o}%vRS!kQtHCA($lGTQxr*VTC@DH7M8segcyg?;>|nx?57k=Ea>|)G+<2OpvvSvt z3|{WzKDKo(dGYF%tMzB0lZ-U#=1`D8Wfx>}6W4pn4o}F$Kc_dxkp>q5YKH7Q^K?3o zz3Xn`Y7He{F+a<(TYQRTYO>_MqyhIHqNBz-a*;^g`*>sIGytdP z$Qvip{AA#oLh~bf?CvVE5m9R{^*Gyma1nGdCkQB;8yKIF zToGxMd8jTW0o4>XC|+^SaPzB5bkrF(t`@wz|Cz2}A5fM(j^*o(h|XP`a1jQU9C@$)n6ELv4Yq^_>NZ!Z;o ztar7Bap^$}sJYIMKb%Xncj&0ng(;K+V9CfkMJnTEm23&u8ssy3DAf)0^!W)vmFAQ^ zT3SN;?2nAB3C9eyYMGKlwBHeNg>89);+m;9f9`XgYo$APZE~ORCcnQOZh^&Hn#kp8 zC!o%x8_{%+$qR}zH(EEsA0XnJ3sTKw%pZQR=kR&mdd!>75NaPR$Iqm`{*gFgRAd4( z=;pkWyXyzi*!#yU20*!I*X~I+eZMiU(_%`qbwrQB39-5524t5cxwnonLdx->f|b|; zeuU{K(DHEP3;ZafJ(Q{{!>1Q7!wnd!@p+h$9@B8P>sN@Okr8g>7hWumctTlt>vLEVwP&@h~TiB#nsV z?6XT{u(T^AB~o%W_^n6MOkr_VpT*V^Ht%ii>Z&&RCd`9J01F_eQ(qqbZdSO7yn|j@ zvU{}E?!@E4j*OH59-Q7fR-&nn4pnkq+tsN!qJu!S7eV^6V?H*AA6KLnGBlP}QZrh(<$`kHZgD=6LI0EIuSH>exZ3!BImh zTTyoM>~GQ;m2wm9BK9X@_B4P8)o>T+W5k9sh=4}PuIrPxWtwFA`8n(LC$Ci$wxgej z&Fe$R`OaexhS~?dy=Q?p33V)QwbViOZ(Qb&Tr;Zs0-Zm%N&YQ=&|hBmDrXl@D8%_P zb2fAgRi*?0J~O3dKP3@~>LyMBK#jZxB`bjSP$hoC7h#(7Fet6M@7aQwast+rW^Rd+ z&wC%I{ss;Xx4GBpqv{#=1d?oD&K@zf5NPH)zgr}1Ojn*sH!;7dAx@F%ue~xK!vK^tl+PbKU=))TlaO^2y@5zo@e*4>oU2Ix8;SqrspjZPZT- z^g0S$Xdqsh1_6(62FdJlsW?c`nE{3jm+2{gQUHML0-l0L%M&I;U`6Z9(b{DoKGWL+ z%&(xhS&xNQq1%2^WWqj}1k3<8kpc32NtmSd@pQ!Rlt%%iD|aGfTN9T; z@RQGi2Kxq5+w|LmffD>=IhCe;{%RV0I5wvh5L`mAp7fJp)Y&aB`_F<5H}?sY%{08S zl}U4p=;x_}ocb2^K#qoNA52=XHZ#ahj7pjli8$%y3%>0R)jZWkaX3Czj31(Ie?^*H z7p-iKCu4A2a8ac*;}fKzM;nt@XoE)~X9S-jNuIE)eZmPn}ehuX9it}VWVL~zoT`8iSL09{O+e(o*I2zcp$U zS#NuxA`eW{DJu3SCtpnb?*Xq>>;@k|B)8s>zdOR)ZTfZUN z$j895wdR?*H(s50p;&!p{6K~uw9#J@KfW|M=v#OeVx8kNx=$)lJ3ftbsJajnK>2gx z4I(@pc88dcUi+CW0~KFoB9xkuk%S<$pK_pP8U8rs+LHthd15muNO!ce#B8Kr8{NoV zy6xyUbA|z(QXiw8?q&pK7gQy4v8_=J?%`iTpGjIPq8SZ+F!jGdANYIxaJGU#T%7rT zz5MDQ4cf}iQ=;SzhuRJfHe?hJ%qJW}%-iBh#KP&tlc@Ul@ZuB+&B(j4V$Dy-Ein`T zxK2Y#Q+rvMG-NPZ8139G-&0K|7`8eHKuCy>`9sS5wNSZI$M|Vy(Kt#YB?93Dh>f*W zU9daRuYYu$55|~;bAMDN)U`Hj_~G-iBqPV>IdxcGJT0eU;V8!UA?=qqDO1X9huKVG z`-)vS1$5ILZ@x8Wna~-SR`W?Or^sUErDUq|fD7(VX`E|#f6UQmPdfF`V>TM&Au;wC z`o^QnuJ$YwpDw9xpf*q9us^2nm^It44G`^3c*8=FdZV*z-SVlf`tgT%Mi3paW(DrN z(t|1N1mWtRHA6hWaVD5RXb>QghsoMtkgZ4BuVlTpv0c9wnsg?7;GQ}xX30iCmCTX( zq~p=iBC{X?@ll&ek)D}KiNif<-FMwtw@KORL^p2=l zMe#b5czj|sI9(nVteBG03zB%kXP_nGR04i{v>i7B=!t3%tjK;J0hReFCT!&*)vIh`t-g2;Iv6*V?Si?SfOp)Ul zVlZKx&7b#DknT&Ih3(t&FTvm?t4}-hvZeZK6*($|g#F>#f@)-mzSX+7rmNW_0+3eb zvL~=KIb>e}oeP3ATbld~EAQL1^=J2?1myNQtyt8-(`?DS!P(+>$h%ehe!Qc?QEc}2 zt;?&{YKgAHN{F22^1nUc6u)7x6l9H{^P`o!u?FUljT4^EkzR)>1>Hl{@!gV;i>wP< z20BhWx)wvBZHVdwnGQXQjHcMC3mY~=xzakiMIH@2s+W}WUcc2BL-EE7;4GVVAVseQ z^J0oFegkKUepkT|#C7aIf zsqn|weWkt^EC(;r8@4Wz&Q6TW{FdLx(08;mL?Pa%A4nnIH?G|E`mQ;(#6Xj`V`)ee zx=j`4$<0-SE;gRoJou)kdUh#VsVi@j7eK_gH>dru6ZIbx%Vt06aL&iX2 zjI>p3$<{hvj)kr}vh;NG2KOr^&X}nXQ6OSN@5@&mGst6>x!bC?yoVJpHxhcGfRNHw zfv}J~H2?xZQ7ScZrszAoR?1VFMcp9|FKC)69POLD)7;4MMLCr{)+5A}z2uO-X3iJa zv>H=hBJo;KbxdWDCTCTS5)}+-ec-{o6G}bYThY?ZW>>XM=OEcORDY1T(()-T{}r`j z$3RfE_O3~1nW@R{MxJ9y7m8^1doia}zyKBdC{oKT{rmCg;&xtA+v}zMU6!b`G2m{! zMR9NMhYjASv&900@2|o~)#DXdfrEizk3L%c_j4EEKRw^-nG?iZ!^O$k-tt%LPfJwk zrUH?NZuv&U26Ajv6Wwy1qWv+NYEOemrH#nIQd_GAaQ3i5)sB@!5u z1vXkI?zy6R0IdrA7S1ICE`#dJ+9y+s!`(G{3 z3_H|3CX;wU*g8>X*uxNH2|6Uni!||!;hYvJUEIABg-@jCT8^W;GEQ8gkdZkXx`s3; z)z5W3U5aPpSax`;A=lNN0ml zP5Y+mtCIe5)>a+&$MSpuB6OiLboWELXifZi7lS-LVAlvt4_~aVYByHb-_|ic#nN8l zqZINN;-y25Hz?6o+yR=baW@T{6L<>K+>E?n4kS2XZHvpR^>f-syx?%AqxL8qYMhm~ zdrr1W;clar=l!$Mv-qLV;+z&m70>-})8?QE%D}9Q5E+^^ukF2T($iyaPPOTq4hYe1 z>xsD5<4PaU?N>;6V7(`NoOZtL(o)lsTPyF{ z%wH(!^FUt$NM*25TkMN7isYqQ89#6zy^`y&BEW@>S;)|qo$bnY7{Y$+Hryb zO8!ccYTm*+dUPN|QK@cA)^PE2w^yJy*Mnm^HsS3+OJSk3$$&W&sPD1D`0B81g{D{N z?#tW3!V|A$fAHndb5^5`YTAP)nmMit@Bk!~EmSm=SjQwj0;_FwE>o>f+oxZ_)|8ma@xAJug1EA@a!Ujo`80QNV{shLxH9Oci0EHHU>{5%(8od9@mmM;l#9?xgqwfl9zCOjT?(k)HJMXwH&1?DG?52ym~4; zKWoSl1O#6cY2S(jda@Bb1qk(~i%21JQng|t)oVOI$r$J{*HEJ7!@)-(Zqqn}mba|~ zSzDWF*X(xo>W!H67QYMkT3Uk)X@%5j%)!1c%B9#ReGH`UPq|%&?%eF&9DR0ij4MIP z5*0kl+Ldn-%ir!d6MBxWVfX|Aid;!xG9+{%FC@#xvWGtdF|7$hxvZqY+GTRo>)V6xb*z6Lm#}r0YVgvkoX}4-=sPz&@Iopvcw` zSBr#)%v%Z9XQa~~_1N_3<2mC!XjTn*!1R$)yZxu}^7E4~{C1}r&t-F#k+?;IPmuPO zF}f4eVzDnx?l7mzl*tuA2fCwJ8hJgM3rm-*mf;i+)NoqrK%D*jHR| zJm)Fs#>s=+bhJD;xLaM!z_o-hzSi^rX4>; zB8rCKVg+U*L*$X!P1LmH2v=Zb_H!aP^X18h&ME*9gkJOy^yA;RrT-9S?*g%RG1l~SfH)goZmZ#?q6#)MAo%c%nyNZ?pjM!*r;?aa z(Jt#9Nz2AHnh!YkYe!qXJysgFjG}g5u5~tx&)lcQI{x4$sxO5`1v13DS#X=E>IVdw z{$}&!6;xvNy9y(wI{4n229i6=flXGOS}a)%Z@a2OBl4;G98i%WC#91Tb!_6m4DiBI z@v)Kk%-Q5$fY9%S(nROS_JHee{bzN4gA7fd;Nr-;UeD)9X#4D%4`jjjh?XR(1y%R6aUS z@}j3w&ND|#n8Mw}B)9r+C7qw%RqZ4=iOc%&z4J!-YC}=qubm?o4z#|RQ9(l|0=DV$#}2b&`5mr zs{>(T0Wf}Z=U3U{OYZ!i^52vj)mJHIr z7Vzi5_os!c{qJ%Z_$?pM_4UeV@TcO{8hzOwf6EN|_IG{xPqX|}{c5SYEabn%1s#gN z)&Eo0|J1%(5&jvuVze9n);9aQxczD1DmMRVAP`L;{6A$xRS_2*QVa}Y^o2yXrMtA3 GcmD%e5MHhT From fc8134ab6b734b7daf064a67ad15f3cefba1d7d6 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Thu, 27 Jun 2024 02:14:21 +1000 Subject: [PATCH 045/124] feat: create unique token for scorm asset retrieval --- app/api/authentication_api.rb | 18 ++++++++++++++++++ app/api/scorm_api.rb | 13 +++++++++---- app/api/test_attempts_api.rb | 1 + app/models/auth_token.rb | 3 ++- app/models/user.rb | 13 +++++++++++-- .../20240618135038_add_auth_token_type.rb | 5 +++++ db/schema.rb | 3 ++- 7 files changed, 48 insertions(+), 8 deletions(-) create mode 100644 db/migrate/20240618135038_add_auth_token_type.rb diff --git a/app/api/authentication_api.rb b/app/api/authentication_api.rb index 3b43b10cf..11dcddd15 100644 --- a/app/api/authentication_api.rb +++ b/app/api/authentication_api.rb @@ -11,6 +11,7 @@ class AuthenticationApi < Grape::API helpers LogHelper helpers AuthenticationHelpers + helpers AuthorisationHelpers # # Sign in - only mounted if AAF auth is NOT used @@ -368,4 +369,21 @@ class AuthenticationApi < Grape::API present nil end + + desc 'Get SCORM authentication token' + get '/auth/scorm' do + if authenticated? + unless authorise? current_user, User, :get_scorm_test + error!({ error: 'You cannot access SCORM tests' }, 403) + end + + token = current_user.auth_tokens.find_by(token_type: 'scorm') + if token.auth_token_expiry <= Time.zone.now + token.destroy! + token = current_user.generate_scorm_authentication_token! + end + + present :scorm_auth_token, token.authentication_token + end + end end diff --git a/app/api/scorm_api.rb b/app/api/scorm_api.rb index 89c7112cd..37321970c 100644 --- a/app/api/scorm_api.rb +++ b/app/api/scorm_api.rb @@ -4,10 +4,11 @@ class ScormApi < Grape::API # Include the AuthenticationHelpers for authentication functionality helpers AuthenticationHelpers + helpers AuthorisationHelpers - # before do - # authenticated? - # end + before do + authenticated? + end helpers do # Method to stream a file from a zip archive at the specified path @@ -51,7 +52,11 @@ def stream_file_from_zip(zip_path, file_path) params do requires :task_def_id, type: Integer, desc: 'Task Definition ID to get SCORM test data for' end - get '/scorm/:task_def_id/*file_path' do + get '/scorm/:task_def_id/:username/:auth_token/*file_path' do + unless authorise? current_user, User, :get_scorm_test + error!({ error: 'You cannot access SCORM tests' }, 403) + end + env['api.format'] = :txt task_def = TaskDefinition.find(params[:task_def_id]) if task_def.has_scorm_data? diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 9e8c91539..1bdfb02e3 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -4,6 +4,7 @@ class TestAttemptsApi < Grape::API format :json helpers AuthenticationHelpers + helpers AuthorisationHelpers before do authenticated? diff --git a/app/models/auth_token.rb b/app/models/auth_token.rb index 5ce9a48a7..ad470a3cd 100644 --- a/app/models/auth_token.rb +++ b/app/models/auth_token.rb @@ -6,7 +6,7 @@ class AuthToken < ApplicationRecord validates :authentication_token, presence: true validate :ensure_token_unique_for_user, on: :create - def self.generate(user, remember, expiry_time = Time.zone.now + 2.hours) + def self.generate(user, remember, expiry_time = Time.zone.now + 2.hours, token_type = 'general') # Loop until new unique auth token is found token = loop do token = Devise.friendly_token @@ -16,6 +16,7 @@ def self.generate(user, remember, expiry_time = Time.zone.now + 2.hours) # Create a new AuthToken with this value result = AuthToken.new(user_id: user.id) result.authentication_token = token + result.token_type = token_type result.extend_token(remember, expiry_time, false) result.save! result diff --git a/app/models/user.rb b/app/models/user.rb index 6e016badf..8e898b2e7 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -107,6 +107,15 @@ def generate_temporary_authentication_token! AuthToken.generate(self, false, Time.zone.now + 30.seconds) end + # + # Generate an authentication token for scorm asset retrieval + # + def generate_scorm_authentication_token! + # Ensure this user is saved... so it has an id + self.save unless self.persisted? + AuthToken.generate(self, false, Time.zone.now + 2.hours, 'scorm') + end + # # Returns whether the authentication token has expired # @@ -344,8 +353,8 @@ def self.permissions # What can students do with users? student_role_permissions = [ - :get_teaching_periods - + :get_teaching_periods, + :get_scorm_test ] # Return the permissions hash diff --git a/db/migrate/20240618135038_add_auth_token_type.rb b/db/migrate/20240618135038_add_auth_token_type.rb new file mode 100644 index 000000000..0183bda87 --- /dev/null +++ b/db/migrate/20240618135038_add_auth_token_type.rb @@ -0,0 +1,5 @@ +class AddAuthTokenType < ActiveRecord::Migration[7.1] + def change + add_column :auth_tokens, :token_type, :string, null: false + end +end diff --git a/db/schema.rb b/db/schema.rb index 66319395c..df555a8ef 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_06_03_020127) do +ActiveRecord::Schema[7.1].define(version: 2024_06_18_135038) do create_table "activity_types", charset: "utf8", collation: "utf8_unicode_ci", force: :cascade do |t| t.string "name", null: false t.string "abbreviation", null: false @@ -24,6 +24,7 @@ t.datetime "auth_token_expiry", null: false t.bigint "user_id" t.string "authentication_token", null: false + t.string "token_type", null: false t.index ["user_id"], name: "index_auth_tokens_on_user_id" end From c854fc10dd9f99f93b65f1449da095fd11db04d0 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:45:50 +1000 Subject: [PATCH 046/124] test: add scorm unit tests --- test/api/auth_test.rb | 51 ++ test/api/comments/scorm_extension_test.rb | 253 ++++++++++ test/api/scorm_api_test.rb | 79 ++++ test/api/test_attempts_test.rb | 492 ++++++++++++++++++++ test/api/units/task_definitions_api_test.rb | 21 +- 5 files changed, 895 insertions(+), 1 deletion(-) create mode 100644 test/api/comments/scorm_extension_test.rb create mode 100644 test/api/scorm_api_test.rb create mode 100644 test/api/test_attempts_test.rb diff --git a/test/api/auth_test.rb b/test/api/auth_test.rb index ec837e921..eb6b671de 100644 --- a/test/api/auth_test.rb +++ b/test/api/auth_test.rb @@ -265,4 +265,55 @@ def test_token_signout_works_with_multiple end # End DELETE tests # --------------------------------------------------------------------------- # + + # # --------------------------------------------------------------------------- # + # # SCORM auth test + + def test_scorm_auth + tutor = FactoryBot.create(:user, :tutor) + + add_auth_header_for(user: tutor) + + # When user is unauthorised + get "api/auth/scorm" + assert_equal 403, last_response.status + + student = FactoryBot.create(:user, :student) + + student.auth_tokens.where(token_type: 'scorm').destroy_all + + add_auth_header_for(user: student) + + # When user is authorised and no prior scorm tokens exist + get "api/auth/scorm" + assert_equal 200, last_response.status + assert last_response_body["scorm_auth_token"] + assert student.auth_tokens.where(token_type: 'scorm').count == 1 + + first_token = last_response_body["scorm_auth_token"] + + add_auth_header_for(user: student) + + # When previous valid scorm token exists + get "api/auth/scorm" + assert_equal 200, last_response.status + assert last_response_body["scorm_auth_token"] == first_token + + old_token = student.auth_tokens.find_by(token_type: 'scorm') + old_token.auth_token_expiry = Time.zone.now - 1.day + old_token.save! + + add_auth_header_for(user: student) + + # When previous expired scorm token exists + get "api/auth/scorm" + assert_equal 200, last_response.status + assert last_response_body["scorm_auth_token"] != first_token + assert_raises ActiveRecord::RecordNotFound do + student.auth_tokens.find(old_token.id) + end + end + + # End SCORM auth test + # --------------------------------------------------------------------------- # end diff --git a/test/api/comments/scorm_extension_test.rb b/test/api/comments/scorm_extension_test.rb new file mode 100644 index 000000000..f206b8f0f --- /dev/null +++ b/test/api/comments/scorm_extension_test.rb @@ -0,0 +1,253 @@ +require 'test_helper' + +class ScormExtensionTest < ActiveSupport::TestCase + include Rack::Test::Methods + include TestHelpers::AuthHelper + include TestHelpers::JsonHelper + + def app + Rails.application + end + + def test_scorm_extension_request + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Scorm extension request', + description: 'Scorm extension request', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'ScormExtensionRequest', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0 + } + ) + td.save! + + data_to_post = { + comment: 'I need more attempts please' + } + + add_auth_header_for(user: user) + + # When there is no attempt limit + post_json "/api/projects/#{project.id}/task_def_id/#{td.id}/request_scorm_extension", data_to_post + assert_equal 400, last_response.status + + td.scorm_attempt_limit = 1 + td.save! + + add_auth_header_for(user: user) + + # When there is an attempt limit + post_json "/api/projects/#{project.id}/task_def_id/#{td.id}/request_scorm_extension", data_to_post + assert_equal 201, last_response.status + assert last_response_body["type"] == "scorm_extension" + + admin = FactoryBot.create(:user, :admin) + + add_auth_header_for(user: admin) + + # When the user is unauthorised + post_json "/api/projects/#{project.id}/task_def_id/#{td.id}/request_scorm_extension", data_to_post + assert_equal 403, last_response.status + + td.destroy! + unit.destroy! + end + + # Test that extension requests are not read by main tutor until they are assessed + def test_read_by_main_tutor + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + other_tutor = unit.main_convenor_user + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Scorm extension request', + description: 'Scorm extension request', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'ScormExtensionRequest', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 1 + } + ) + td.save! + + main_tutor = project.tutor_for(td) + data_to_post = { + comment: 'I need more attempts please' + } + + add_auth_header_for(user: user) + + post_json "/api/projects/#{project.id}/task_def_id/#{td.id}/request_scorm_extension", data_to_post + assert_equal 201, last_response.status + assert last_response_body["type"] == "scorm_extension" + + tc = TaskComment.find(last_response_body["id"]) + + # Check it is not read by the main tutor + refute tc.read_by?(main_tutor), "Error: Should not be read by main tutor on create" + assert tc.read_by?(user), "Error: Should be read by student on create" + + # Check that reading by main tutor does not read the task + tc.read_by? main_tutor + refute tc.read_by?(main_tutor), "Error: Should not be read by main tutor even when they read it" + + # Check it is read after grant by another user + tc.assess_scorm_extension other_tutor, true + assert tc.read_by?(main_tutor), "Error: Should be read by main tutor after assess" + + td.destroy! + unit.destroy! + end + + def test_auto_grant_for_tutor + unit = FactoryBot.create(:unit) + project = unit.projects.first + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Scorm extension request', + description: 'Scorm extension request', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'ScormExtensionRequest', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 1 + } + ) + td.save! + + main_tutor = project.tutor_for(td) + data_to_post = { + comment: 'I need more attempts please' + } + + # Scorm extension request made by tutor + add_auth_header_for(user: main_tutor) + + post_json "/api/projects/#{project.id}/task_def_id/#{td.id}/request_scorm_extension", data_to_post + assert_equal 201, last_response.status + assert last_response_body["type"] == "scorm_extension" + + tc = ScormExtensionComment.find(last_response_body["id"]) + + # Check if it is granted automatically + assert tc.read_by?(main_tutor), "Error: Should be read by main tutor after assess" + assert tc.extension_granted, "Error: Should be granted" + + td.destroy! + unit.destroy! + end + + def test_scorm_extension_assessment + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Scorm extension', + description: 'Scorm extension', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'ScormExtension', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 2 + } + ) + td.save! + + main_tutor = project.tutor_for(td) + task = project.task_for_task_definition(td) + initial_extension_count = task.scorm_extensions + + tc = task.apply_for_scorm_extension(user, "I need more attempts please") + + data_to_put = { + granted: true + } + + add_auth_header_for(user: user) + + # When the user is unauthorised + put_json "/api/projects/#{project.id}/task_def_id/#{td.id}/assess_scorm_extension/#{tc.id}", data_to_put + assert_equal 403, last_response.status + + add_auth_header_for(user: main_tutor) + + # Grant extension + put_json "/api/projects/#{project.id}/task_def_id/#{td.id}/assess_scorm_extension/#{tc.id}", data_to_put + assert_equal 200, last_response.status + + tc = ScormExtensionComment.find(last_response_body["id"]) + task = project.task_for_task_definition(td) + + # Check scorm extension count + assert tc.extension_granted, "Error: Should be granted" + assert tc.assessed?, "Error: Should be assessed" + assert task.scorm_extensions == initial_extension_count + td.scorm_attempt_limit + + new_extension_count = task.scorm_extensions + + add_auth_header_for(user: main_tutor) + + # Duplicate assessment + put_json "/api/projects/#{project.id}/task_def_id/#{td.id}/assess_scorm_extension/#{tc.id}", data_to_put + assert_equal 403, last_response.status + + task = project.task_for_task_definition(td) + + assert task.scorm_extensions == new_extension_count + + td.destroy! + unit.destroy! + end +end diff --git a/test/api/scorm_api_test.rb b/test/api/scorm_api_test.rb new file mode 100644 index 000000000..54d1aeae0 --- /dev/null +++ b/test/api/scorm_api_test.rb @@ -0,0 +1,79 @@ +require 'test_helper' + +class ScormApiTest < ActiveSupport::TestCase + include Rack::Test::Methods + include TestHelpers::AuthHelper + include TestHelpers::TestFileHelper + + def app + Rails.application + end + + def test_serve_scorm_content + unit = FactoryBot.create(:unit) + user = unit.projects.first.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Task scorm', + description: 'Task with scorm test', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TaskScorm', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_allow_review: true, + scorm_bypass_test: false, + scorm_time_delay_enabled: false, + scorm_attempt_limit: 0 + } + ) + td.save! + + # When the task def does not have SCORM data + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/index.html" + assert_equal 404, last_response.status + + td.add_scorm_data(test_file_path('numbas.zip'), copy: true) + td.save! + + # When the file is missing + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/index1.html" + assert_equal 404, last_response.status + + # When the file is present - html + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/index.html" + assert_equal 200, last_response.status + assert_equal 'text/html', last_response.content_type + + # When the file is present - css + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/styles.css" + assert_equal 200, last_response.status + assert_equal 'text/css', last_response.content_type + + # When the file is present - js + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/scripts.js" + assert_equal 200, last_response.status + assert_equal 'text/javascript', last_response.content_type + + tutor = FactoryBot.create(:user, :tutor, username: :test_tutor) + unit.employ_staff(tutor, Role.tutor) + + # When the user is unauthorised + get "/api/scorm/#{td.id}/#{tutor.username}/#{auth_token(tutor)}/index.html" + assert_equal 403, last_response.status + + tutor.destroy! + td.destroy! + unit.destroy! + end +end diff --git a/test/api/test_attempts_test.rb b/test/api/test_attempts_test.rb new file mode 100644 index 000000000..c3c444c62 --- /dev/null +++ b/test/api/test_attempts_test.rb @@ -0,0 +1,492 @@ +require 'test_helper' + +class TestAttemptsTest < ActiveSupport::TestCase + include Rack::Test::Methods + include TestHelpers::AuthHelper + include TestHelpers::JsonHelper + + def app + Rails.application + end + + def test_get_task_attempts + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts', + description: 'Test attempts', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttempts', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0 + } + ) + td.save! + + add_auth_header_for(user: user) + + # When no attempts exist + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 200, last_response.status + assert_empty last_response_body + + task = project.task_for_task_definition(td) + attempt = TestAttempt.create({ task_id: task.id }) + + td1 = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts new', + description: 'Test attempts new', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttemptsNew', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0 + } + ) + td1.save! + + task1 = project.task_for_task_definition(td1) + attempt1 = TestAttempt.create({ task_id: task1.id }) + + add_auth_header_for(user: user) + + # When attempts exists + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 200, last_response.status + assert_json_equal last_response_body, [attempt] + + user1 = FactoryBot.create(:user, :student) + + add_auth_header_for(user: user1) + + # When user is unauthorised + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 403, last_response.status + + user1.destroy! + td.destroy! + td1.destroy! + unit.destroy! + end + + def test_get_latest + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts', + description: 'Test attempts', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttempts', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0 + } + ) + td.save! + + add_auth_header_for(user: user) + + # When no attempts exist + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts/latest" + assert_equal 404, last_response.status + + task = project.task_for_task_definition(td) + attempt = TestAttempt.create({ task_id: task.id }) + attempt.terminated = true + attempt.completion_status = true + attempt.save! + attempt1 = TestAttempt.create({ task_id: task.id }) + + add_auth_header_for(user: user) + + # When attempts exist + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts/latest" + assert_equal 200, last_response.status + assert_json_equal last_response_body, attempt1 + + add_auth_header_for(user: user) + + # Get completed latest + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts/latest?completed=true" + assert_equal 200, last_response.status + assert_json_equal last_response_body, attempt + + user1 = FactoryBot.create(:user, :student) + + add_auth_header_for(user: user1) + + # When user is unauthorised + get "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts/latest" + assert_equal 403, last_response.status + + td.destroy! + unit.destroy! + end + + def test_review_attempt + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts', + description: 'Test attempts', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttempts', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0, + scorm_allow_review: true + } + ) + td.save! + + add_auth_header_for(user: user) + + # When attempt id is invalid + get "api/test_attempts/0/review" + assert_equal 404, last_response.status + + task = project.task_for_task_definition(td) + attempt = TestAttempt.create({ task_id: task.id }) + + td.scorm_allow_review = false + td.save! + + add_auth_header_for(user: user) + + # When review is disabled + get "api/test_attempts/#{attempt.id}/review" + assert_equal 403, last_response.status + + td.scorm_allow_review = true + td.save! + + add_auth_header_for(user: user) + + # When attempt is incomplete + get "api/test_attempts/#{attempt.id}/review" + assert_equal 500, last_response.status + + dm = JSON.parse(attempt.cmi_datamodel) + dm['cmi.completion_status'] = 'completed' + attempt.cmi_datamodel = dm.to_json + attempt.completion_status = true + attempt.terminated = true + attempt.save! + + add_auth_header_for(user: user) + + # When attempt can be reviewed + get "api/test_attempts/#{attempt.id}/review" + assert_equal 200, last_response.status + + attempt.review + attempt.save! + + assert_json_equal last_response_body, attempt + + tutor = project.tutor_for(td) + + add_auth_header_for(user: tutor) + + # When user is tutor + get "api/test_attempts/#{attempt.id}/review" + assert_equal 200, last_response.status + assert_json_equal last_response_body, attempt + + user1 = FactoryBot.create(:user, :student) + + add_auth_header_for(user: user1) + + # When user is unauthorised + get "api/test_attempts/#{attempt.id}/review" + assert_equal 403, last_response.status + + td.destroy! + unit.destroy! + end + + def test_post_attempt + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts', + description: 'Test attempts', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttempts', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: false, + scorm_attempt_limit: 1 + } + ) + td.save! + + add_auth_header_for(user: user) + + # When scorm is disabled + post "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 403, last_response.status + + td.scorm_enabled = true + td.save! + + tutor = project.tutor_for(td) + + add_auth_header_for(user: tutor) + + # When user is unauthorised + post "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 403, last_response.status + + task = project.task_for_task_definition(td) + + add_auth_header_for(user: user) + + # When new attempt can be made + post "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 201, last_response.status + assert last_response_body["task_id"] == task.id + + attempt = TestAttempt.find(last_response_body["id"]) + + add_auth_header_for(user: user) + + # When last attempt is incomplete + post "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 400, last_response.status + + attempt.terminated = true + attempt.success_status = true + attempt.save! + + add_auth_header_for(user: user) + + # When last attempt is a pass + post "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 400, last_response.status + + attempt.success_status = false + attempt.save! + + add_auth_header_for(user: user) + + # When attempt limit is reached + post "api/projects/#{project.id}/task_def_id/#{td.id}/test_attempts" + assert_equal 400, last_response.status + + td.destroy! + unit.destroy! + end + + def test_update_attempt + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts', + description: 'Test attempts', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttempts', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0 + } + ) + td.save! + + tutor = project.tutor_for(td) + + task = project.task_for_task_definition(td) + attempt = TestAttempt.create({ task_id: task.id }) + + dm = JSON.parse(attempt.cmi_datamodel) + dm["cmi.completion_status"] = "completed" + dm["cmi.score.scaled"] = "0.1" + + data_to_patch = { + cmi_datamodel: dm.to_json, + terminated: true + } + + add_auth_header_for(user: tutor) + + # When user is unauthorised + patch "api/test_attempts/#{attempt.id}", data_to_patch + assert_equal 403, last_response.status + + add_auth_header_for(user: user) + + # When attempt is terminated + patch "api/test_attempts/#{attempt.id}", data_to_patch + assert_equal 200, last_response.status + + attempt = TestAttempt.find(attempt.id) + + assert attempt.terminated == true + assert JSON.parse(attempt.cmi_datamodel)["cmi.completion_status"] == "completed" + + tc = ScormComment.find_by(test_attempt_id: attempt.id) + + assert_not_nil tc + + add_auth_header_for(user: user) + + # When unauthorised user tries to override pass status + patch "api/test_attempts/#{attempt.id}", { success_status: true } + assert_equal 403, last_response.status + + add_auth_header_for(user: tutor) + + # When authorised user tries to override pass status + patch "api/test_attempts/#{attempt.id}", { success_status: true } + assert_equal 200, last_response.status + + attempt = TestAttempt.find(attempt.id) + + assert attempt.success_status == true + assert JSON.parse(attempt.cmi_datamodel)["cmi.success_status"] == "passed" + + tc = ScormComment.find_by(test_attempt_id: attempt.id) + + assert tc.comment == attempt.success_status_description + + add_auth_header_for(user: tutor) + + # When attempt id is invalid + patch "api/test_attempts/0", { success_status: true } + assert_equal 404, last_response.status + + td.destroy! + unit.destroy! + end + + def test_delete_attempt + unit = FactoryBot.create(:unit) + project = unit.projects.first + user = project.student + + td = TaskDefinition.new( + { + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Test attempts', + description: 'Test attempts', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now - 1.week, + due_date: Time.zone.now + 1.week, + abbreviation: 'TestAttempts', + restrict_status_updates: false, + upload_requirements: [], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0, + scorm_enabled: true, + scorm_attempt_limit: 0 + } + ) + td.save! + + task = project.task_for_task_definition(td) + attempt = TestAttempt.create({ task_id: task.id }) + + add_auth_header_for(user: user) + + # When user is unauthorised + delete "api/test_attempts/#{attempt.id}" + assert_equal 403, last_response.status + + tutor = project.tutor_for(td) + + add_auth_header_for(user: tutor) + + # When user is authorised + delete "api/test_attempts/#{attempt.id}" + assert_equal 200, last_response.status + + add_auth_header_for(user: tutor) + + # When attempt id is invalid + delete "api/test_attempts/0" + assert_equal 404, last_response.status + + td.destroy! + unit.destroy! + end +end diff --git a/test/api/units/task_definitions_api_test.rb b/test/api/units/task_definitions_api_test.rb index 663ba880f..3bf539dc3 100644 --- a/test/api/units/task_definitions_api_test.rb +++ b/test/api/units/task_definitions_api_test.rb @@ -53,7 +53,7 @@ def test_task_definition_cud scorm_enabled: false, scorm_allow_review: false, scorm_bypass_test: false, - scorm_time_delay_enabled: true, + scorm_time_delay_enabled: false, scorm_attempt_limit: 0 } } @@ -223,6 +223,25 @@ def test_post_task_resources assert_requested delete_stub, times: 1 end + def test_post_scorm + test_unit = Unit.first + test_task_definition = TaskDefinition.first + + data_to_post = { + file: upload_file('test_files/numbas.zip', 'application/zip') + } + + # Add auth_token and username to header + add_auth_header_for(user: Unit.first.main_convenor_user) + + post "/api/units/#{test_unit.id}/task_definitions/#{test_task_definition.id}/scorm_data", data_to_post + + assert_equal 201, last_response.status + assert test_task_definition.task_scorm_data + + assert_equal File.size(data_to_post[:file]), File.size(TaskDefinition.first.task_scorm_data) + end + def test_submission_creates_folders unit = Unit.first td = TaskDefinition.new({ From 6108b52bc04d7866548c8738b39d37c30d24f602 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:46:22 +1000 Subject: [PATCH 047/124] fix: check if no old scorm tokens exist --- app/api/authentication_api.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/authentication_api.rb b/app/api/authentication_api.rb index 11dcddd15..460edd2a1 100644 --- a/app/api/authentication_api.rb +++ b/app/api/authentication_api.rb @@ -378,8 +378,8 @@ class AuthenticationApi < Grape::API end token = current_user.auth_tokens.find_by(token_type: 'scorm') - if token.auth_token_expiry <= Time.zone.now - token.destroy! + if token.nil? || token.auth_token_expiry <= Time.zone.now + token&.destroy token = current_user.generate_scorm_authentication_token! end From 3d86d04b03fb39168d65c377a5422295d82d3222 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:46:42 +1000 Subject: [PATCH 048/124] refactor: remove stale todo comment --- app/models/test_attempt.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index 20dc8facd..78a4808ac 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -14,7 +14,6 @@ class TestAttempt < ApplicationRecord validates :task_id, presence: true def self.permissions - # TODO: this is all wrong, students should not be able to delete test attempts student_role_permissions = [ :update_attempt # :review_own_attempt -- depends on task def settings. See specific_permission_hash method From c5240d8da378b84deb3ac64e1584808b07d5e671 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 2 Jul 2024 23:47:16 +1000 Subject: [PATCH 049/124] fix: validate attempt id --- app/api/test_attempts_api.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 1bdfb02e3..51fa6ef21 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -93,7 +93,6 @@ class TestAttemptsApi < Grape::API if test.nil? error!({ message: 'Test attempt ID is invalid' }, 404) - return else logger.debug "Request to review test attempt #{params[:id]}" test.review @@ -153,6 +152,10 @@ class TestAttemptsApi < Grape::API patch 'test_attempts/:id' do test = TestAttempt.find(params[:id]) + if test.nil? + error!({ message: 'Test attempt ID is invalid' }, 404) + end + if params[:success_status].present? unless authorise? current_user, test, :override_success_status error!({ error: 'Not authorised to override the success status of this scorm attempt' }, 403) @@ -189,6 +192,10 @@ class TestAttemptsApi < Grape::API error!({ error: 'Not authorised to delete this scorm attempt' }, 403) end - test.destroy! + if test.nil? + error!({ message: 'Test attempt ID is invalid' }, 404) + else + test.destroy! + end end end From 5db5f35dc6cc1874c50f5891ca7bbd752ea32b55 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 01:41:05 +1000 Subject: [PATCH 050/124] fix: reorder columns for csv export --- app/models/task_definition.rb | 6 +++--- db/migrate/20240322021829_add_scorm_config_to_task_def.rb | 2 +- db/schema.rb | 2 +- test/models/task_definition_test.rb | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 59c798505..7debed36f 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -301,9 +301,9 @@ def to_csv_row def self.csv_columns [:name, :abbreviation, :description, :weighting, :target_grade, :restrict_status_updates, :max_quality_pts, - :is_graded, :plagiarism_warn_pct, :group_set, :upload_requirements, :scorm_enabled, :scorm_allow_review, - :scorm_bypass_test, :scorm_time_delay_enabled, :scorm_attempt_limit, :start_week, :start_day, :target_week, - :target_day, :due_week, :due_day, :tutorial_stream] + :is_graded, :plagiarism_warn_pct, :scorm_enabled, :scorm_allow_review, :scorm_bypass_test, :scorm_time_delay_enabled, + :scorm_attempt_limit, :group_set, :upload_requirements, :start_week, :start_day, :target_week, :target_day, + :due_week, :due_day, :tutorial_stream] end def self.task_def_for_csv_row(unit, row) diff --git a/db/migrate/20240322021829_add_scorm_config_to_task_def.rb b/db/migrate/20240322021829_add_scorm_config_to_task_def.rb index 99c7dcffb..04847cb9b 100644 --- a/db/migrate/20240322021829_add_scorm_config_to_task_def.rb +++ b/db/migrate/20240322021829_add_scorm_config_to_task_def.rb @@ -5,7 +5,7 @@ def change t.boolean :scorm_allow_review, default: false t.boolean :scorm_bypass_test, default: false t.boolean :scorm_time_delay_enabled, default: false - t.integer :scorm_attempt_limit + t.integer :scorm_attempt_limit, default: 0 end end diff --git a/db/schema.rb b/db/schema.rb index df555a8ef..d240af3af 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -257,7 +257,7 @@ t.boolean "scorm_allow_review", default: false t.boolean "scorm_bypass_test", default: false t.boolean "scorm_time_delay_enabled", default: false - t.integer "scorm_attempt_limit" + t.integer "scorm_attempt_limit", default: 0 t.index ["group_set_id"], name: "index_task_definitions_on_group_set_id" t.index ["overseer_image_id"], name: "index_task_definitions_on_overseer_image_id" t.index ["tutorial_stream_id"], name: "index_task_definitions_on_tutorial_stream_id" diff --git a/test/models/task_definition_test.rb b/test/models/task_definition_test.rb index a292cd1cd..d20634d8c 100644 --- a/test/models/task_definition_test.rb +++ b/test/models/task_definition_test.rb @@ -145,7 +145,7 @@ def test_export_task_definitions_csv task_defs_csv = CSV.parse unit.task_definitions_csv, headers: true task_defs_csv.each do |task_def_csv| task_def = unit.task_definitions.find_by(abbreviation: task_def_csv['abbreviation']) - keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day', 'scorm_enabled', 'scorm_allow_review', 'scorm_bypass_test', 'scorm_time_delay_enabled', 'scorm_attempt_limit'] + keys_to_ignore = ['tutorial_stream', 'start_week', 'start_day', 'target_week', 'target_day', 'due_week', 'due_day'] task_def_csv.each do |key, value| unless keys_to_ignore.include?(key) assert_equal(task_def[key].to_s, value) From 08a00906019ce0c2706c34cf053a511b6e5ddca2 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 02:44:32 +1000 Subject: [PATCH 051/124] fix: use unique perms for scorm test retrieval --- app/api/authentication_api.rb | 4 ++-- app/api/scorm_api.rb | 7 ++++--- app/models/user.rb | 8 +++++--- test/api/auth_test.rb | 4 ++-- test/api/scorm_api_test.rb | 1 - 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/app/api/authentication_api.rb b/app/api/authentication_api.rb index 460edd2a1..80701731d 100644 --- a/app/api/authentication_api.rb +++ b/app/api/authentication_api.rb @@ -373,8 +373,8 @@ class AuthenticationApi < Grape::API desc 'Get SCORM authentication token' get '/auth/scorm' do if authenticated? - unless authorise? current_user, User, :get_scorm_test - error!({ error: 'You cannot access SCORM tests' }, 403) + unless authorise? current_user, User, :get_scorm_token + error!({ error: 'You cannot get SCORM tokens' }, 403) end token = current_user.auth_tokens.find_by(token_type: 'scorm') diff --git a/app/api/scorm_api.rb b/app/api/scorm_api.rb index 37321970c..737460bde 100644 --- a/app/api/scorm_api.rb +++ b/app/api/scorm_api.rb @@ -53,12 +53,13 @@ def stream_file_from_zip(zip_path, file_path) requires :task_def_id, type: Integer, desc: 'Task Definition ID to get SCORM test data for' end get '/scorm/:task_def_id/:username/:auth_token/*file_path' do - unless authorise? current_user, User, :get_scorm_test - error!({ error: 'You cannot access SCORM tests' }, 403) + task_def = TaskDefinition.find(params[:task_def_id]) + + unless authorise? current_user, task_def.unit, :get_unit + error!({ error: 'You cannot access SCORM tests of unit' }, 403) end env['api.format'] = :txt - task_def = TaskDefinition.find(params[:task_def_id]) if task_def.has_scorm_data? zip_path = task_def.task_scorm_data content_type 'application/octet-stream' diff --git a/app/models/user.rb b/app/models/user.rb index 8e898b2e7..95ff3cbc9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -341,20 +341,22 @@ def self.permissions :convene_units, :get_staff_list, :get_teaching_periods, - :use_overseer + :use_overseer, + :get_scorm_token ] # What can tutors do with users? tutor_role_permissions = [ :get_unit_roles, :download_unit_csv, - :get_teaching_periods + :get_teaching_periods, + :get_scorm_token ] # What can students do with users? student_role_permissions = [ :get_teaching_periods, - :get_scorm_test + :get_scorm_token ] # Return the permissions hash diff --git a/test/api/auth_test.rb b/test/api/auth_test.rb index eb6b671de..670a50eea 100644 --- a/test/api/auth_test.rb +++ b/test/api/auth_test.rb @@ -270,9 +270,9 @@ def test_token_signout_works_with_multiple # # SCORM auth test def test_scorm_auth - tutor = FactoryBot.create(:user, :tutor) + admin = FactoryBot.create(:user, :admin) - add_auth_header_for(user: tutor) + add_auth_header_for(user: admin) # When user is unauthorised get "api/auth/scorm" diff --git a/test/api/scorm_api_test.rb b/test/api/scorm_api_test.rb index 54d1aeae0..b4837d3f5 100644 --- a/test/api/scorm_api_test.rb +++ b/test/api/scorm_api_test.rb @@ -66,7 +66,6 @@ def test_serve_scorm_content assert_equal 'text/javascript', last_response.content_type tutor = FactoryBot.create(:user, :tutor, username: :test_tutor) - unit.employ_staff(tutor, Role.tutor) # When the user is unauthorised get "/api/scorm/#{td.id}/#{tutor.username}/#{auth_token(tutor)}/index.html" From 52450bec9039fda80f6f8a6d3a742adc8def8d77 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 3 Jul 2024 15:52:17 +1000 Subject: [PATCH 052/124] fix: ensure main convenor validation on change only --- app/models/unit.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/unit.rb b/app/models/unit.rb index be1f90974..5fd8a2536 100644 --- a/app/models/unit.rb +++ b/app/models/unit.rb @@ -161,7 +161,7 @@ def role_for(user) validate :validate_end_date_after_start_date validate :ensure_teaching_period_dates_match, if: :has_teaching_period? - validate :ensure_main_convenor_is_appropriate + validate :ensure_main_convenor_is_appropriate, if: :main_convenor_id_changed? # Portfolio autogen date validations, must be after start date and before or equal to end date validate :autogen_date_within_unit_active_period, if: -> { start_date_changed? || end_date_changed? || teaching_period_id_changed? || portfolio_auto_generation_date_changed? } From e740d8218478b6ef27795fc15093082c07e0c69a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 3 Jul 2024 15:53:19 +1000 Subject: [PATCH 053/124] fix: streamline archiving units in maintenance task --- lib/tasks/maintenance.rake | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/tasks/maintenance.rake b/lib/tasks/maintenance.rake index 7efd1b94c..3c6d69143 100644 --- a/lib/tasks/maintenance.rake +++ b/lib/tasks/maintenance.rake @@ -30,14 +30,36 @@ namespace :maintenance do desc 'Remove PDFs from old submissions and archive units' task archive_submissions: [:environment] do archive_period = Doubtfire::Application.config.unit_archive_after_period - return if archive_period <= 1.year + # Next returns from rake tasks + next if archive_period <= 1.year - Unit.where(archived: false).where('end_date < :archive_before', archive_before: DateTime.now - archive_period).find_each do |unit| - puts "Are you sure you want to archive #{unit.detailed_name}? (Yes to confirm): " + units = Unit.where(archived: false).where('end_date < :archive_before', archive_before: DateTime.now - archive_period) + unit_ids = units.pluck(:id) + + loop do + puts "Are you happy to archive the following units?" + units.find_each do |unit| + puts("#{unit.id}: #{unit.detailed_name}") if unit_ids.include?(unit.id) + end + + puts "Please enter any unit IDs you would like to remove from the list, separated by commas" response = $stdin.gets.chomp + break if response.blank? + unit_ids_to_exclude = response.split(',').map(&:to_i) + + unit_ids = unit_ids.excluding(unit_ids_to_exclude) + + break if unit_ids.empty? + end + + # Next returns from rake tasks + next if unit_ids.empty? - next unless response == 'Yes' + puts "Proceed? (Yes/No): " + response = $stdin.gets.chomp + next unless response == 'Yes' + Unit.where(id: unit_ids).preload(projects: [:user, { tasks: :task_definition }]).find_each do |unit| unit.archive_submissions($stdout) unit.update(archived: true) end From eacbac1f659e09252ab24a4fc9e0d5a02d811a00 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 3 Jul 2024 17:06:18 +1000 Subject: [PATCH 054/124] fix: remove rollover teaching period --- app/api/teaching_periods_authenticated_api.rb | 17 -- app/models/teaching_period.rb | 31 ---- test/models/teaching_period_test.rb | 155 ------------------ 3 files changed, 203 deletions(-) diff --git a/app/api/teaching_periods_authenticated_api.rb b/app/api/teaching_periods_authenticated_api.rb index d39260cfa..4670cf998 100644 --- a/app/api/teaching_periods_authenticated_api.rb +++ b/app/api/teaching_periods_authenticated_api.rb @@ -77,21 +77,4 @@ class TeachingPeriodsAuthenticatedApi < Grape::API TeachingPeriod.find(teaching_period_id).destroy end - desc 'Rollover a Teaching Period' - params do - requires :new_teaching_period_id, type: Integer, desc: 'The id of the rolled over teaching period' - optional :rollover_inactive, type: Boolean, default: false, desc: 'Are in active units included in the roll over' - optional :search_forward, type: Boolean, default: true, desc: 'When rolling over units, ensure that latest version is rolled over to new teaching period' - end - post '/teaching_periods/:existing_teaching_period_id/rollover' do - unless authorise? current_user, User, :rollover - error!({ error: 'Not authorised to rollover a teaching period' }, 403) - end - - new_teaching_period_id = params[:new_teaching_period_id] - new_teaching_period = TeachingPeriod.find(new_teaching_period_id) - - existing_teaching_period = TeachingPeriod.find(params[:existing_teaching_period_id]) - error!({ error: existing_teaching_period.errors.full_messages.first }, 403) unless existing_teaching_period.rollover(new_teaching_period, params[:search_forward], params[:rollover_inactive]) - end end diff --git a/app/models/teaching_period.rb b/app/models/teaching_period.rb index 965ef5f4b..eaf5d6b2c 100644 --- a/app/models/teaching_period.rb +++ b/app/models/teaching_period.rb @@ -132,37 +132,6 @@ def future_teaching_periods TeachingPeriod.where("start_date > :end_date", end_date: end_date) end - def rollover(rollover_to, search_forward = true, rollover_inactive = false) - if rollover_to.start_date < Time.zone.now || rollover_to.start_date <= start_date - self.errors.add(:base, "Units can only be rolled over to future teaching periods") - - false - else - units_to_rollover = units - - unless rollover_inactive - units_to_rollover = units_to_rollover.where(active: true) - end - - if search_forward - ftp = future_teaching_periods.where("start_date < :date", date: rollover_to.start_date).order(start_date: "desc") - - units_to_rollover = units_to_rollover.map do |u| - ftp.map { |tp| tp.units.where(code: u.code).first }.select { |u| u.present? }.first || u - end - end - - for unit in units_to_rollover do - # skip if the unit already exists in the teaching period - next if rollover_to.units.where(code: unit.code).count > 0 - - unit.rollover(rollover_to, nil, nil) - end - - true - end - end - private def can_destroy? diff --git a/test/models/teaching_period_test.rb b/test/models/teaching_period_test.rb index fc1115e2d..863507e2e 100644 --- a/test/models/teaching_period_test.rb +++ b/test/models/teaching_period_test.rb @@ -220,159 +220,4 @@ def test_create_teaching_period_with_invalid_dates tp.destroy assert tp.destroyed? end - - test 'cannot roll over to past teaching periods' do - tp = TeachingPeriod.first - tp2 = TeachingPeriod.last - - assert_not tp.rollover(tp2) - assert_equal 1, tp.errors.count - end - - test 'can roll over to future teaching periods' do - tp = TeachingPeriod.first - - data = { - year: 2019, - period: 'TN', - start_date: Time.zone.now + 1.week, - end_date: Time.zone.now + 13.week, - active_until: Time.zone.now + 15.week - } - - tp2 = TeachingPeriod.create!(data) - - assert tp.rollover(tp2) - assert_equal 0, tp.errors.count - end - - test 'can update teaching period dates' do - data = { - year: 2019, - period: 'T1', - start_date: Date.parse('2018-01-01'), - end_date: Date.parse('2018-02-01'), - active_until: Date.parse('2018-03-01') - } - - tp = TeachingPeriod.create(data) - assert tp.valid? - - unit_data = { - name: 'Unit with TP - to update', - code: 'TEST113', - teaching_period: tp, - description: 'Unit in TP to update dates', - } - - unit = Unit.create(unit_data) - - assert unit.valid? - - tp.update!(start_date: Date.parse('2018-01-02')) - - assert tp.valid? - - unit = Unit.includes(:teaching_period).find(unit.id) - assert unit.valid?, unit.errors.inspect - - tp.update(end_date: Date.parse('2018-02-02')) - - assert tp.valid? - unit.reload - assert unit.valid? - end - - def test_search_forward_occurs_in_rollover - tp1 = FactoryBot.create :teaching_period, start_date: Time.zone.now - tp2 = FactoryBot.create :teaching_period, start_date: Time.zone.now + 20.weeks - tp3 = FactoryBot.create :teaching_period, start_date: Time.zone.now + 40.weeks - - u1 = FactoryBot.create :unit, with_students: false, code: 'SIT111', task_count: 1, teaching_period: tp1 - - assert_equal 1, tp1.units.count - assert_equal 0, tp2.units.count - - tp1.rollover tp2, false - - assert_equal 1, tp2.units.count - assert_equal 0, tp3.units.count - - u1.reload - - u2 = tp2.units.first - u2.reload - u2.task_definitions.first.update(name: u2.task_definitions.first.name + "A") - u1.reload - - refute_equal u1.task_definitions.first.name, u2.task_definitions.first.name - - tp1.rollover tp3, true - - assert_equal 1, tp3.units.count - - u3 = tp3.units.first - - u1.reload - u2.reload - u3.reload - - u1.task_definitions.reload - u2.task_definitions.reload - u3.task_definitions.reload - - assert_equal u2.task_definitions.first.name, u3.task_definitions.first.name - refute_equal u1.task_definitions.first.name, u3.task_definitions.first.name - end - - def test_rollover_active_only - tp1 = FactoryBot.create :teaching_period, start_date: Time.zone.now - tp2 = FactoryBot.create :teaching_period, start_date: Time.zone.now + 20.weeks - - u1 = FactoryBot.create :unit, with_students: false, code: 'SIT111', task_count: 0, teaching_period: tp1 - u2 = FactoryBot.create :unit, with_students: false, code: 'SIT112', task_count: 0, teaching_period: tp1 - - u1.active = false - u1.save - - assert_equal 2, tp1.units.count - assert_equal 0, tp2.units.count - - tp1.rollover tp2, false - - assert_equal 1, tp2.units.count - end - - def test_can_opt_to_rollover_inactive - tp1 = FactoryBot.create :teaching_period, start_date: Time.zone.now - tp2 = FactoryBot.create :teaching_period, start_date: Time.zone.now + 20.weeks - - u1 = FactoryBot.create :unit, with_students: false, code: 'SIT111', task_count: 0, teaching_period: tp1 - u2 = FactoryBot.create :unit, with_students: false, code: 'SIT112', task_count: 0, teaching_period: tp1 - - u1.active = false - u1.save - - assert_equal 2, tp1.units.count - assert_equal 0, tp2.units.count - - tp1.rollover tp2, false, true - - assert_equal 2, tp2.units.count - end - - def test_rollover_detects_existing_units - tp1 = FactoryBot.create :teaching_period, start_date: Time.zone.now - tp2 = FactoryBot.create :teaching_period, start_date: Time.zone.now + 20.weeks - - u1 = FactoryBot.create :unit, with_students: false, code: 'SIT111', task_count: 0, teaching_period: tp1 - u2 = FactoryBot.create :unit, with_students: false, code: 'SIT111', task_count: 0, teaching_period: tp2 - - assert_equal 1, tp1.units.count - assert_equal 1, tp2.units.count - - tp1.rollover tp2 - - assert_equal 1, tp2.units.count - end end From 7f3b7529a9c8ee0a8800e28aa1504f221f80bc5d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 3 Jul 2024 17:09:44 +1000 Subject: [PATCH 055/124] feat: allow new unit code to be provided to rollover --- app/api/units_api.rb | 11 ++--- app/models/unit.rb | 5 ++- test/models/unit_model_test.rb | 79 ++++++++++++++++++++++++++++++---- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/app/api/units_api.rb b/app/api/units_api.rb index 5cc93a88d..1dd92a3d1 100644 --- a/app/api/units_api.rb +++ b/app/api/units_api.rb @@ -235,9 +235,10 @@ class UnitsApi < Grape::API desc 'Rollover unit' params do - optional :teaching_period_id - optional :start_date - optional :end_date + optional :teaching_period_id, type: Integer, desc: 'The teaching period to rollover to' + optional :start_date, type: Date, desc: 'The start date of the new unit' + optional :end_date, type: Date, desc: 'The end date of the new unit' + optional :new_unit_code, type: String, desc: 'The unit code for the new unit' exactly_one_of :teaching_period_id, :start_date all_or_none_of :start_date, :end_date @@ -253,9 +254,9 @@ class UnitsApi < Grape::API if teaching_period_id.present? tp = TeachingPeriod.find(teaching_period_id) - result = unit.rollover(tp, nil, nil) + result = unit.rollover(tp, nil, nil, params[:new_unit_code]) else - result = unit.rollover(nil, params[:start_date], params[:end_date]) + result = unit.rollover(nil, params[:start_date], params[:end_date], params[:new_unit_code]) end my_role = result.role_for(current_user) diff --git a/app/models/unit.rb b/app/models/unit.rb index 5fd8a2536..802601be7 100644 --- a/app/models/unit.rb +++ b/app/models/unit.rb @@ -271,12 +271,15 @@ def autogen_date_within_unit_active_period end end - def rollover(teaching_period, start_date, end_date) + def rollover(teaching_period, start_date, end_date, new_code) new_unit = self.dup + new_unit.code = new_code if new_code.present? + if teaching_period.present? new_unit.teaching_period = teaching_period else + new_unit.teaching_period = nil new_unit.start_date = start_date new_unit.end_date = end_date end diff --git a/test/models/unit_model_test.rb b/test/models/unit_model_test.rb index 18c13567f..ba1bcb781 100644 --- a/test/models/unit_model_test.rb +++ b/test/models/unit_model_test.rb @@ -113,7 +113,7 @@ def test_rollover_of_task_files @unit.import_tasks_from_csv File.open(Rails.root.join('test_files', "#{@unit.code}-Tasks.csv")) @unit.import_task_files_from_zip Rails.root.join('test_files', "#{@unit.code}-Tasks.zip") - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil unit2.task_definitions.each do |td| assert File.exist?(td.task_sheet), 'task sheet is absent' @@ -130,7 +130,7 @@ def test_rollover_of_learning_summary @unit.draft_task_definition = lsr @unit.save - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil assert_not_nil unit2.draft_task_definition refute_equal lsr, unit2.draft_task_definition @@ -139,7 +139,7 @@ def test_rollover_of_learning_summary end def test_rollover_of_portfolio_generation - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil assert unit2.portfolio_auto_generation_date.present? assert unit2.portfolio_auto_generation_date > unit2.start_date && unit2.portfolio_auto_generation_date < unit2.end_date @@ -157,7 +157,7 @@ def test_rollover_of_group_tasks groups: [ { gs: 0, students: 2} ], group_tasks: [ { idx: 0, gs: 0 }] ) - unit2 = unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = unit.rollover TeachingPeriod.find(2), nil, nil, nil assert_equal 1, unit2.group_sets.count assert_not_equal unit2.group_sets.first, unit.group_sets.first @@ -172,7 +172,7 @@ def test_rollover_of_task_ilo_links @unit.import_outcomes_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Outcomes.csv")) @unit.import_task_alignment_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Alignment.csv")), nil - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil assert @unit.task_outcome_alignments.count > 0 assert_equal @unit.task_outcome_alignments.count, unit2.task_outcome_alignments.count @@ -192,7 +192,7 @@ def test_rollover_of_task_ilo_links def test_rollover_of_tasks_have_same_start_week_and_day @unit.import_tasks_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Tasks.csv")) - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil assert_equal 3, @unit.teaching_period_id assert_equal 2, unit2.teaching_period_id @@ -210,7 +210,7 @@ def test_rollover_of_tasks_have_same_start_week_and_day def test_rollover_of_tasks_have_same_target_week_and_day @unit.import_tasks_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Tasks.csv")) - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil @unit.task_definitions.each do |td| td2 = unit2.task_definitions.find_by_abbreviation(td.abbreviation) @@ -247,7 +247,7 @@ def test_updating_unit_dates_propogates_to_tasks test 'rollover of tasks have same due week and day' do @unit.import_tasks_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Tasks.csv")) - unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil + unit2 = @unit.rollover TeachingPeriod.find(2), nil, nil, nil @unit.task_definitions.each do |td| td2 = unit2.task_definitions.find_by_abbreviation(td.abbreviation) @@ -256,7 +256,6 @@ def test_updating_unit_dates_propogates_to_tasks end end - test 'ensure valid response from unit ilo data' do @unit.import_tasks_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Tasks.csv")) @unit.import_outcomes_from_csv File.open(Rails.root.join('test_files',"#{@unit.code}-Outcomes.csv")) @@ -758,4 +757,66 @@ def test_change_unit_code_moves_files unit.destroy! end + test 'rollover to set dates' do + start_date = Time.zone.now + end_date = start_date + 14.weeks + + unit2 = @unit.rollover(nil, start_date, end_date, nil) + + assert_equal @unit.code, unit2.code + assert_in_delta start_date, unit2.start_date, 1.hour + assert_in_delta end_date, unit2.end_date, 1.hour + + unit2.destroy + end + + test 'rollover to new code with dates' do + start_date = Time.zone.now + end_date = start_date + 14.weeks + + unit2 = @unit.rollover(nil, start_date, end_date, 'NEWCODE-1') + + assert_not_equal @unit.code, unit2.code + assert_equal 'NEWCODE-1', unit2.code + assert_in_delta start_date, unit2.start_date, 1.hour + assert_in_delta end_date, unit2.end_date, 1.hour + + unit2.destroy + end + + test 'rollover to new code with teaching period' do + @unit.import_tasks_from_csv File.open(Rails.root.join('test_files', "#{@unit.code}-Tasks.csv")) + @unit.import_task_files_from_zip Rails.root.join('test_files', "#{@unit.code}-Tasks.zip") + + tp = TeachingPeriod.find(2) + + unit2 = @unit.rollover(tp, nil, nil, 'NEWCODE-1') + + assert_not_equal @unit.code, unit2.code + assert_equal 'NEWCODE-1', unit2.code + assert_equal tp, unit2.teaching_period + + unit2.task_definitions.each do |td| + assert File.exist?(td.task_sheet), 'task sheet is absent' + end + + assert File.exist?(unit2.task_definitions.first.task_resources), 'task resource is absent' + + # can rollover in the same teaching period with a new code + unit3 = unit2.rollover(tp, nil, nil, 'NEWCODE-2') + + assert_not_equal unit2.code, unit3.code + assert_equal 'NEWCODE-2', unit3.code + assert_equal tp, unit3.teaching_period + + unit3.task_definitions.each do |td| + assert File.exist?(td.task_sheet), 'task sheet is absent' + end + + assert File.exist?(unit3.task_definitions.first.task_resources), 'task resource is absent' + + unit2.destroy + unit3.destroy + end + end From 9bdbe0e7ebda3834d390c70927a7997f496063a5 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 3 Jul 2024 17:19:08 +1000 Subject: [PATCH 056/124] chore(release): 8.0.9 --- CHANGELOG.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cd0ad39a..4f3d8550d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.9](https://github.com/macite/doubtfire-deploy/compare/v8.0.8...v8.0.9) (2024-07-03) + + +### Features + +* allow new unit code to be provided to rollover ([7f3b752](https://github.com/macite/doubtfire-deploy/commit/7f3b7529a9c8ee0a8800e28aa1504f221f80bc5d)) + + +### Bug Fixes + +* ensure main convenor validation on change only ([52450be](https://github.com/macite/doubtfire-deploy/commit/52450bec9039fda80f6f8a6d3a742adc8def8d77)) +* remove rollover teaching period ([eacbac1](https://github.com/macite/doubtfire-deploy/commit/eacbac1f659e09252ab24a4fc9e0d5a02d811a00)) +* streamline archiving units in maintenance task ([e740d82](https://github.com/macite/doubtfire-deploy/commit/e740d8218478b6ef27795fc15093082c07e0c69a)) + ### [8.0.8](https://github.com/doubtfire-lms/doubtfire-deploy/compare/v8.0.7...v8.0.8) (2024-07-01) From 6373eee8ab38f5b1c79be5e88302c1880e36cc90 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 4 Jul 2024 22:27:59 +1000 Subject: [PATCH 057/124] fix: ensure task definitions render when upload requirements are nil --- app/api/entities/task_definition_entity.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/entities/task_definition_entity.rb b/app/api/entities/task_definition_entity.rb index 3dc309f28..5909bddae 100644 --- a/app/api/entities/task_definition_entity.rb +++ b/app/api/entities/task_definition_entity.rb @@ -26,7 +26,7 @@ def staff?(my_role) task_definition.upload_requirements else # Filter out turn it in details - task_definition.upload_requirements.map { |r| r.except('tii_check', 'tii_pct') } + task_definition.upload_requirements.map { |r| r.except('tii_check', 'tii_pct') } unless task_definition.upload_requirements.nil? end end From 4359cf2587c09a6405f50d104ce30d61eaae3c1f Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:42:46 +1000 Subject: [PATCH 058/124] refactor: correct syntax for rubocop --- app/api/task_definitions_api.rb | 4 ++-- app/models/comments/scorm_extension_comment.rb | 2 +- app/models/test_attempt.rb | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index 775b53875..b581fad7b 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -647,7 +647,7 @@ class TaskDefinitionsApi < Grape::API task_def = unit.task_definitions.find(params[:task_def_id]) - unless params[:file].present? + if params[:file].blank? error!({ error: "No file uploaded" }, 403) end @@ -678,7 +678,7 @@ class TaskDefinitionsApi < Grape::API content_type 'application/octet-stream' header['Content-Disposition'] = "attachment; filename=#{task_def.abbreviation}-scorm.zip" else - path = Rails.root.join('public', 'resources', 'FileNotFound.pdf') + path = Rails.root.join('public/resources/FileNotFound.pdf') content_type 'application/pdf' header['Content-Disposition'] = 'attachment; filename=FileNotFound.pdf' end diff --git a/app/models/comments/scorm_extension_comment.rb b/app/models/comments/scorm_extension_comment.rb index 7e0ef7709..74bc9d0c8 100644 --- a/app/models/comments/scorm_extension_comment.rb +++ b/app/models/comments/scorm_extension_comment.rb @@ -14,7 +14,7 @@ def assessed? end # Make sure we can access super's version of mark_as_read for assess extension - alias :super_mark_as_read :mark_as_read + alias super_mark_as_read mark_as_read # Allow individual staff and the student to read this... but stop # the main tutor reading without assessing. As only the main tutor diff --git a/app/models/test_attempt.rb b/app/models/test_attempt.rb index 78a4808ac..88d9761d0 100644 --- a/app/models/test_attempt.rb +++ b/app/models/test_attempt.rb @@ -66,7 +66,7 @@ def specific_permission_hash(role, perm_hash, _other) # t.text :cmi_datamodel, default: "{}", null: false after_initialize if: :new_record? do - self.attempted_time = Time.now + self.attempted_time = Time.zone.now task = Task.find(self.task_id) learner_name = task.project.student.name learner_id = task.project.student.student_id @@ -112,13 +112,13 @@ def review # when review is requested change the mode to review dm['cmi.mode'] = 'review' - write_attribute(:cmi_datamodel, dm.to_json) + self[:cmi_datamodel] = dm.to_json end def override_success_status(new_success_status) dm = JSON.parse(self.cmi_datamodel) dm['cmi.success_status'] = (new_success_status ? 'passed' : 'failed') - write_attribute(:cmi_datamodel, dm.to_json) + self[:cmi_datamodel] = dm.to_json self.success_status = dm['cmi.success_status'] == 'passed' self.save! self.update_scorm_comment @@ -144,7 +144,7 @@ def update_scorm_comment return self.scorm_comment end - puts "WARN: Unexpected need to create scorm comment for test attempt: #{self.id}" + logger.warn "WARN: Unexpected need to create scorm comment for test attempt: #{self.id}" add_scorm_comment end From a49fc8c042d608f109706278f933071e0f058ed2 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 17:05:33 +1000 Subject: [PATCH 059/124] fix: turn it in enabled property --- app/helpers/turn_it_in.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/app/helpers/turn_it_in.rb b/app/helpers/turn_it_in.rb index b5b2a0c05..2ab737917 100644 --- a/app/helpers/turn_it_in.rb +++ b/app/helpers/turn_it_in.rb @@ -11,6 +11,10 @@ class TurnItIn cattr_reader :x_turnitin_integration_name, :x_turnitin_integration_version + def self.enabled? + Doubtfire::Application.config.tii_enabled + end + def self.load_config(config) config.tii_enabled = ENV['TII_ENABLED'].present? && (ENV['TII_ENABLED'].to_s.downcase == "true" || ENV['TII_ENABLED'].to_i == 1) @@ -58,7 +62,7 @@ def self.load_tii_features # A global error indicates that tii is not configured correctly or a change in the # environment requires that the configuration is updated def self.global_error - return nil unless Doubtfire::Application.config.tii_enabled + return nil unless TurnItIn.enabled? Rails.cache.fetch("tii.global_error") do @@global_error @@ -67,7 +71,7 @@ def self.global_error # Update the global error, when present this will block calls to tii until resolved def self.global_error=(value) - return unless Doubtfire::Application.config.tii_enabled + return unless TurnItIn.enabled? @@global_error = value @@ -80,7 +84,7 @@ def self.global_error=(value) # Indicates if there is a global error that indicates that things should not call tii until resolved def self.global_error? - return false unless Doubtfire::Application.config.tii_enabled + return false unless TurnItIn.enabled? Rails.cache.exist?("tii.global_error") || @@global_error.present? end @@ -118,7 +122,7 @@ def self.handle_tii_error(action, error) # Get the current eula - value is refreshed every 24 hours def self.eula_version - return nil unless Doubtfire::Application.config.tii_enabled + return nil unless TurnItIn.enabled? action = TiiActionFetchEula.last || TiiActionFetchEula.create action.fetch_eula_version unless action.eula? @@ -130,7 +134,7 @@ def self.eula_version # Return the html for the eula def self.eula_html - return nil unless Doubtfire::Application.config.tii_enabled + return nil unless TurnItIn.enabled? Rails.cache.fetch("tii.eula_html.#{TurnItIn.eula_version}") end From bb29f84c8c4808886cf84b89069a622308d7b859 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 17:06:13 +1000 Subject: [PATCH 060/124] fix: ensure sidekiq moves to Rails root before task pdf creation --- app/sidekiq/accept_submission_job.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/sidekiq/accept_submission_job.rb b/app/sidekiq/accept_submission_job.rb index 86235f2c2..8584424d2 100644 --- a/app/sidekiq/accept_submission_job.rb +++ b/app/sidekiq/accept_submission_job.rb @@ -3,6 +3,13 @@ class AcceptSubmissionJob include LogHelper def perform(task_id, user_id, accepted_tii_eula) + begin + # Ensure cwd is valid... + FileUtils.cd(Rails.root) + rescue StandardError => e + logger.error e + end + task = Task.find(task_id) user = User.find(user_id) From 5b8f5d35f520f7e59ddfe53d795200f45882c517 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 17:06:37 +1000 Subject: [PATCH 061/124] fix: ensure turn it in actions only occur when tii enabled --- app/sidekiq/tii_check_progress_job.rb | 2 ++ app/sidekiq/tii_register_web_hook_job.rb | 2 ++ 2 files changed, 4 insertions(+) diff --git a/app/sidekiq/tii_check_progress_job.rb b/app/sidekiq/tii_check_progress_job.rb index 9754f3950..5b7b02cf5 100644 --- a/app/sidekiq/tii_check_progress_job.rb +++ b/app/sidekiq/tii_check_progress_job.rb @@ -7,6 +7,8 @@ class TiiCheckProgressJob include Sidekiq::Job def perform + return unless TurnItIn.enabled? + run_waiting_actions TurnItIn.check_and_update_eula TurnItIn.check_and_update_features diff --git a/app/sidekiq/tii_register_web_hook_job.rb b/app/sidekiq/tii_register_web_hook_job.rb index f2149bfcd..f61de7bea 100644 --- a/app/sidekiq/tii_register_web_hook_job.rb +++ b/app/sidekiq/tii_register_web_hook_job.rb @@ -6,6 +6,8 @@ class TiiRegisterWebHookJob include Sidekiq::Job def perform + return unless TurnItIn.enabled? + (TiiActionRegisterWebhook.last || TiiActionRegisterWebhook.create).perform end end From e3fab0d897bac82dcc14d3ff4b3948245a203b1c Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 21:22:58 +1000 Subject: [PATCH 062/124] fix: ensure logger only logs to stdout in development --- config/initializers/log_initializer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/initializers/log_initializer.rb b/config/initializers/log_initializer.rb index 9748142b7..38b524645 100644 --- a/config/initializers/log_initializer.rb +++ b/config/initializers/log_initializer.rb @@ -1,6 +1,6 @@ -# Ensure log outputs to stdout in all but test environments -unless Rails.env.test? - Rails.logger.broadcast_to(ActiveSupport::Logger.new($stdout)) +# Ensure log outputs to stdout in development +if Rails.env.development? + Rails.logger.broadcast_to(ActiveSupport::Logger.new($stdout, level: Rails.logger.level)) end class FormatifFormatter < Logger::Formatter From 58d828193ee4448df15d4fcc391d2a1a22338efc Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 21:23:27 +1000 Subject: [PATCH 063/124] fix: guard access of pwd incase pwd is invalid --- app/helpers/file_helper.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/helpers/file_helper.rb b/app/helpers/file_helper.rb index e313a9d4e..480506199 100644 --- a/app/helpers/file_helper.rb +++ b/app/helpers/file_helper.rb @@ -361,7 +361,13 @@ def qpdf(path) # - only_before = date for files to move (only if retain from is true) def move_files(from_path, to_path, retain_from = false, only_before = nil) # move into the new dir - and mv files to the in_process_dir - pwd = FileUtils.pwd + begin + pwd = FileUtils.pwd + rescue + # if no pwd, reset to the root + pwd = Rails.root + end + begin FileUtils.mkdir_p(to_path) Dir.chdir(from_path) From 32b1d9f94c225e326ed7fbc111565fa75de3ec00 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 21:50:36 +1000 Subject: [PATCH 064/124] fix: ensure failure to send email is handled --- app/models/portfolio_evidence.rb | 10 +++++++--- app/models/project.rb | 6 +++++- app/models/unit_role.rb | 6 +++++- lib/tasks/generate_pdfs.rake | 14 +++++++++----- 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/app/models/portfolio_evidence.rb b/app/models/portfolio_evidence.rb index 5e0790593..2a5d57adc 100644 --- a/app/models/portfolio_evidence.rb +++ b/app/models/portfolio_evidence.rb @@ -83,10 +83,14 @@ def self.process_new_to_pdf(my_source) # end errors.each do |project, tasks| - logger.info "checking email for project #{project.id}" - if project.student.receive_task_notifications - logger.info "emailing task notification to #{project.student.name}" + logger.debug "checking email for project #{project.id}" + next unless project.student.receive_task_notifications + + logger.info "emailing task notification to #{project.student.name}" + begin PortfolioEvidenceMailer.task_pdf_failed(project, tasks).deliver + rescue StandardError => e + logger.error "Failed to send task pdf failed email for project #{project.id}!\n#{e.message}" end end end diff --git a/app/models/project.rb b/app/models/project.rb index 706a60b58..4cab26e97 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -656,7 +656,11 @@ def send_weekly_status_email(summary_stats, middle_of_unit) return unless student.receive_feedback_notifications return if portfolio_exists? && !middle_of_unit - NotificationsMailer.weekly_student_summary(self, summary_stats, did_revert_to_pass).deliver_now + begin + NotificationsMailer.weekly_student_summary(self, summary_stats, did_revert_to_pass).deliver_now + rescue StandardError => e + logger.error "Failed to send weekly status email for project #{id}!\n#{e.message}" + end end def archive_submissions(out) diff --git a/app/models/unit_role.rb b/app/models/unit_role.rb index e458ca8d8..b0e7fad92 100644 --- a/app/models/unit_role.rb +++ b/app/models/unit_role.rb @@ -145,7 +145,11 @@ def populate_summary_stats(summary_stats) def send_weekly_status_email(summary_stats) return unless user.receive_feedback_notifications - NotificationsMailer.weekly_staff_summary(self, summary_stats).deliver_now + begin + NotificationsMailer.weekly_staff_summary(self, summary_stats).deliver_now + rescue StandardError => e + Rails.logger.error "Failed to send weekly staff summary email to #{user.email} - #{e.message}" + end end def ensure_valid_user_for_role diff --git a/lib/tasks/generate_pdfs.rake b/lib/tasks/generate_pdfs.rake index 697e3b74f..a5dab5fc4 100644 --- a/lib/tasks/generate_pdfs.rake +++ b/lib/tasks/generate_pdfs.rake @@ -144,10 +144,14 @@ namespace :submission do logger.info "emailing portfolio notification to #{project.student.name}" - if success - PortfolioEvidenceMailer.portfolio_ready(project).deliver_now - else - PortfolioEvidenceMailer.portfolio_failed(project).deliver_now + begin + if success + PortfolioEvidenceMailer.portfolio_ready(project).deliver_now + else + PortfolioEvidenceMailer.portfolio_failed(project).deliver_now + end + rescue StandardError => e + logger.error "Failed to send portfolio email for project #{project.id}!\n#{e.message}" end end ensure @@ -158,7 +162,7 @@ namespace :submission do # Remove the processing directory if Dir.entries(my_source).count == 2 # . and .. - FileUtils.rmdir my_source + FileUtils.rmdir(my_source) end logger.info "Ending generate pdf - #{Process.pid}" From 460681aaa39a91df66fcfbf7db474991f92cf645 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 22:12:19 +1000 Subject: [PATCH 065/124] chore(release): 8.0.10 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f3d8550d..d3f87f5c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.10](https://github.com/doubtfire-lms/doubtfire-deploy/compare/v8.0.9...v8.0.10) (2024-07-10) + + +### Bug Fixes + +* ensure failure to send email is handled ([32b1d9f](https://github.com/doubtfire-lms/doubtfire-deploy/commit/32b1d9f94c225e326ed7fbc111565fa75de3ec00)) +* ensure logger only logs to stdout in development ([e3fab0d](https://github.com/doubtfire-lms/doubtfire-deploy/commit/e3fab0d897bac82dcc14d3ff4b3948245a203b1c)) +* ensure sidekiq moves to Rails root before task pdf creation ([bb29f84](https://github.com/doubtfire-lms/doubtfire-deploy/commit/bb29f84c8c4808886cf84b89069a622308d7b859)) +* ensure task definitions render when upload requirements are nil ([6373eee](https://github.com/doubtfire-lms/doubtfire-deploy/commit/6373eee8ab38f5b1c79be5e88302c1880e36cc90)) +* ensure turn it in actions only occur when tii enabled ([5b8f5d3](https://github.com/doubtfire-lms/doubtfire-deploy/commit/5b8f5d35f520f7e59ddfe53d795200f45882c517)) +* guard access of pwd incase pwd is invalid ([58d8281](https://github.com/doubtfire-lms/doubtfire-deploy/commit/58d828193ee4448df15d4fcc391d2a1a22338efc)) +* turn it in enabled property ([a49fc8c](https://github.com/doubtfire-lms/doubtfire-deploy/commit/a49fc8c042d608f109706278f933071e0f058ed2)) + ### [8.0.9](https://github.com/macite/doubtfire-deploy/compare/v8.0.8...v8.0.9) (2024-07-03) From 210c3f431ff8b8cbf5cfece2c8ace5c96c5a808d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 12 Jul 2024 16:47:44 +1000 Subject: [PATCH 066/124] test: add tests for multi unit sync and connection errors in sync --- test/config/deakin_config_test.rb | 79 ++++++++++++++++++++++++++++ test_files/deakin/enrol_multi_1.json | 43 +++++++++++++++ test_files/deakin/enrol_multi_2.json | 43 +++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 test_files/deakin/enrol_multi_1.json create mode 100644 test_files/deakin/enrol_multi_2.json diff --git a/test/config/deakin_config_test.rb b/test/config/deakin_config_test.rb index 41baafd7a..25da492ee 100644 --- a/test/config/deakin_config_test.rb +++ b/test/config/deakin_config_test.rb @@ -85,6 +85,85 @@ def test_sync_deakin_unit_without_timetable unit.destroy end + def test_sync_deakin_retry_requests + WebMock.reset_executed_requests! + + # Setup enrolments stubs + raw_enrolment_file = File.new(test_file_path("deakin/enrolment_sample.json")) + enrolment_stub = stub_request(:get, /#{ENV['DF_INSTITUTION_SETTINGS_SYNC_BASE_URL']}.*/) + .to_return([ + { body: "Too many requests", status: 429 }, + { body: "Internal server error", status: 500 }, + { body: raw_enrolment_file, status: 200 } + ]) + + raw_timetable_file = File.new(test_file_path("deakin/timetable_sample.json")) + timetable_stub = stub_request(:post, /#{ENV['DF_INSTITUTION_SETTINGS_SYNC_STAR_URL']}.*allocated$/). + to_return([ + { body: "Too many requests", status: 429 }, + { body: "Internal server error", status: 500 }, + { body: raw_timetable_file, status: 200 } + ]) + + raw_timetable_cls_activity_file = File.new(test_file_path("deakin/timetable_activity_sample.json")) + timetable_activity_stub = stub_request(:post, /#{ENV['DF_INSTITUTION_SETTINGS_SYNC_STAR_URL']}.*activities$/). + to_return([ + { body: "Too many requests", status: 429 }, + { body: "Internal server error", status: 500 }, + { body: raw_timetable_cls_activity_file, status: 200 } + ]) + + tp = FactoryBot.create(:teaching_period, period: 'T2', year: 2020) + unit = FactoryBot.create(:unit, code: 'SIT999', name: 'Test Sync', teaching_period: tp, with_students: false, stream_count: 0, tutorials: 0) + + unit.sync_enrolments + + assert_requested enrolment_stub, times: 3 + assert_requested timetable_stub, times: 3 + assert_requested timetable_activity_stub, times: 3 + + unit.destroy + end + + def test_sync_deakin_multi_unit + WebMock.reset_executed_requests! + + # Setup enrolments stubs + raw_enrolment_file_1 = File.new(test_file_path("deakin/enrol_multi_1.json")) + raw_enrolment_file_2 = File.new(test_file_path("deakin/enrol_multi_2.json")) + raw_enrolment_file_3 = File.new(test_file_path("deakin/enrol_multi_1.json")) + raw_enrolment_file_4 = File.new(test_file_path("deakin/enrol_multi_2.json")) + + enrolment_stub = stub_request(:get, /#{ENV['DF_INSTITUTION_SETTINGS_SYNC_BASE_URL']}.*/). + to_return([ + { body: raw_enrolment_file_1, status: 200 }, + { body: raw_enrolment_file_2, status: 200 }, + { body: raw_enrolment_file_3, status: 200 }, + { body: raw_enrolment_file_4, status: 200 } + ]) + + tp = FactoryBot.create(:teaching_period, period: 'T2', year: 2024) + unit = FactoryBot.create(:unit, code: 'SIT724/SIT746', name: 'Test Sync', teaching_period: tp, with_students: false, stream_count: 0, tutorials: 0) + + unit.enable_sync_timetable = false + unit.save + + result = unit.sync_enrolments + + assert_equal 2, unit.tutorials.count # none created + + assert_requested enrolment_stub, times: 2 + + assert_equal 2, unit.active_projects.count + + unit.reload + result = unit.sync_enrolments + + assert_equal 2, unit.active_projects.count + + unit.destroy + end + def test_sync_deakin_unit_disabled WebMock.reset_executed_requests! diff --git a/test_files/deakin/enrol_multi_1.json b/test_files/deakin/enrol_multi_1.json new file mode 100644 index 000000000..3a2cfe189 --- /dev/null +++ b/test_files/deakin/enrol_multi_1.json @@ -0,0 +1,43 @@ +{ + "unitEnrolments": [ + { + "unitCode": "SIT724", + "unitTitle": "RESEARCH PROJECT", + "teachingPeriod": { + "type": "trimester", + "period": "2", + "year": "2024" + }, + "locations": [ + { + "name": "Test Sync Campus", + "enrolments": [ + { + "studentId": 11111000, + "title": "MR", + "surname": "TEST", + "givenNames": "TEST", + "preferredName": "TEST", + "email": "test@deakin.edu.au", + "courseCode": "S464", + "unitClass": "X", + "status": "Discontinued" + }, + { + "studentId": 222220000, + "title": "MR", + "surname": "TEST", + "givenNames": "TEST", + "preferredName": "TEST", + "email": "test1@deakin.edu.au", + "courseCode": "S464", + "unitClass": "X", + "status": "Enrolled" + } + ] + } + ] + } + ] +} + diff --git a/test_files/deakin/enrol_multi_2.json b/test_files/deakin/enrol_multi_2.json new file mode 100644 index 000000000..04a021f12 --- /dev/null +++ b/test_files/deakin/enrol_multi_2.json @@ -0,0 +1,43 @@ +{ + "unitEnrolments": [ + { + "unitCode": "SIT746", + "unitTitle": "RESEARCH PROJECT", + "teachingPeriod": { + "type": "trimester", + "period": "2", + "year": "2024" + }, + "locations": [ + { + "name": "Test Sync Campus", + "enrolments": [ + { + "studentId": 11111000, + "title": "MR", + "surname": "TEST", + "givenNames": "TEST", + "preferredName": "TEST", + "email": "test@deakin.edu.au", + "courseCode": "S464", + "unitClass": "X", + "status": "Enrolled" + }, + { + "studentId": 222220000, + "title": "MR", + "surname": "TEST", + "givenNames": "TEST", + "preferredName": "TEST", + "email": "test1@deakin.edu.au", + "courseCode": "S464", + "unitClass": "X", + "status": "Discontinued" + } + ] + } + ] + } + ] +} + From d4808b0f9d2653a02e56f868a9f0d9bec6e53826 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 12 Jul 2024 16:48:19 +1000 Subject: [PATCH 067/124] feat: ensure deakin sync retries failed connections --- config/deakin.rb | 64 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/config/deakin.rb b/config/deakin.rb index 419254ae1..dedab6494 100644 --- a/config/deakin.rb +++ b/config/deakin.rb @@ -131,7 +131,19 @@ def sync_streams_from_star(unit) url = "#{@star_url}/#{server}/rest/activities" logger.info("Fetching #{unit.name} timetable from #{url}") - response = RestClient.post(url, { username: @star_user, password: @star_secret, where_clause: "subject_code LIKE '#{unit.code}%_#{tp.period.last}'" }) + + # Try to contact the server up to 3 times... + for i in 0..2 do + begin + response = RestClient.post(url, { username: @star_user, password: @star_secret, where_clause: "subject_code LIKE '#{unit.code}%_#{tp.period.last}'" }) + break if response.code == 200 + logger.error "Error in sync #{unit.code} - #{response.code}" + rescue StandardError => e + logger.error "Error in sync #{unit.code} - #{e.message}" + end + + sleep(5 + (5 * i)) # wait 5+ seconds before retrying + end if response.code == 200 jsonData = JSON.parse(response.body) @@ -350,13 +362,28 @@ def sync_enrolments(unit) timetable_data = {} end + # Get the list of students + student_list = [] + for code in codes do # Get URL to enrolment data for this code url = "#{@base_url}?academicYear=#{tp.year}&periodType=trimester&period=#{tp.period.last}&unitCode=#{code}" logger.info("Requesting #{url}") # Get json from enrolment server - response = RestClient.get(url, headers = { "client_id" => @client_id, "client_secret" => @client_secret }) + + # Try to contact the server up to 3 times... + for i in 0..2 do + begin + response = RestClient.get(url, headers = { "client_id" => @client_id, "client_secret" => @client_secret }) + break if response.code == 200 + logger.error "Error in sync #{unit.code} - #{response.code}" + sleep(5 + (5 * i)) # wait 5+ seconds before retrying + rescue StandardError => e + logger.error "Error in sync #{unit.code} - #{e.message}" + sleep(5) + end + end # Check we get a valid response if response.code == 200 @@ -381,9 +408,6 @@ def sync_enrolments(unit) logger.info "Syncing enrolment for #{code} - #{tp.year} #{tp.period}" - # Get the list of students - student_list = [] - # Get the timetable data () if multi_unit # We just enrol people in a "tutorial" associated with the unit code @@ -493,6 +517,11 @@ def sync_enrolments(unit) # Record details for students already enrolled to work with multi-units if row_data[:enrolled] already_enrolled[row_data[:username]] = true + + if multi_unit + # Ensure student list does not already contain this student as a withdrawal + student_list.delete_if { |student| student[:username] == row_data[:username] } + end elsif already_enrolled[row_data[:username]] # skip to the next enrolment... this person was enrolled in an earlier unit nested within this unit... so skip this row as it would result in withdrawal next @@ -517,16 +546,17 @@ def sync_enrolments(unit) end end - import_settings = { - replace_existing_tutorial: false - } - - # Now get unit to sync - unit.sync_enrolment_with(student_list, import_settings, result) else logger.error "Failed to sync #{unit.code} - #{response}" end # if response 200 end # for each code + + import_settings = { + replace_existing_tutorial: false + } + + # Now get unit to sync + unit.sync_enrolment_with(student_list, import_settings, result) rescue Exception => e logger.error "Failed to sync unit: #{e.message}" end @@ -551,7 +581,17 @@ def fetch_timetable_data(unit) unit.tutorial_streams.each do |tutorial_stream| logger.info("Fetching #{tutorial_stream.abbreviation} from #{url}") - response = RestClient.post(url, { username: @star_user, password: @star_secret, where_clause: "subject_code LIKE '#{unit.code}%' AND activity_group_code LIKE '#{tutorial_stream.abbreviation}'" }) + for i in 0..2 do + begin + response = RestClient.post(url, { username: @star_user, password: @star_secret, where_clause: "subject_code LIKE '#{unit.code}%' AND activity_group_code LIKE '#{tutorial_stream.abbreviation}'" }) + break if response.code == 200 + logger.error "Error in sync #{unit.code} - #{response.code}" + rescue StandardError => e + logger.error "Error in sync #{unit.code} - #{e.message}" + end + + sleep(5 + (5 * i)) # wait 5+ seconds before retrying + end if response.code == 200 jsonData = JSON.parse(response.body) From 439669add23145b7bc05df7bd7b8bba75610bf39 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 12 Jul 2024 16:56:20 +1000 Subject: [PATCH 068/124] chore(release): 8.0.11 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3f87f5c8..0d2776a00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.11](https://github.com/macite/doubtfire-deploy/compare/v8.0.10...v8.0.11) (2024-07-12) + + +### Features + +* ensure deakin sync retries failed connections ([d4808b0](https://github.com/macite/doubtfire-deploy/commit/d4808b0f9d2653a02e56f868a9f0d9bec6e53826)) + ### [8.0.10](https://github.com/doubtfire-lms/doubtfire-deploy/compare/v8.0.9...v8.0.10) (2024-07-10) From 2fcb4771cb597589a5e1c8f9672f4cc3f4b93325 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 16:08:14 +1000 Subject: [PATCH 069/124] quality: ensure tii enabled always through class --- app/api/entities/user_entity.rb | 2 +- app/api/settings_api.rb | 2 +- app/helpers/turn_it_in.rb | 2 +- app/models/turn_it_in/task_definition_tii_module.rb | 4 ++-- app/models/turn_it_in/user_tii_module.rb | 2 +- test/models/tii_model_test.rb | 8 ++++---- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/api/entities/user_entity.rb b/app/api/entities/user_entity.rb index 9ede2faf8..1a1155e10 100644 --- a/app/api/entities/user_entity.rb +++ b/app/api/entities/user_entity.rb @@ -13,7 +13,7 @@ class UserEntity < Grape::Entity expose :opt_in_to_research, unless: :minimal expose :has_run_first_time_setup, unless: :minimal - expose :accepted_tii_eula, unless: :minimal, if: ->(user, options) { Doubtfire::Application.config.tii_enabled } do |user, options| + expose :accepted_tii_eula, unless: :minimal, if: ->(user, options) { TurnItIn.enabled? } do |user, options| if TiiActionFetchFeaturesEnabled.eula_required? TurnItIn.eula_version == user.tii_eula_version else diff --git a/app/api/settings_api.rb b/app/api/settings_api.rb index 39be2d292..b787c7d53 100644 --- a/app/api/settings_api.rb +++ b/app/api/settings_api.rb @@ -9,7 +9,7 @@ class SettingsApi < Grape::API response = { externalName: Doubtfire::Application.config.institution[:product_name], overseerEnabled: Doubtfire::Application.config.overseer_enabled, - tiiEnabled: Doubtfire::Application.config.tii_enabled + tiiEnabled: TurnItIn.enabled? } present response, with: Grape::Presenters::Presenter diff --git a/app/helpers/turn_it_in.rb b/app/helpers/turn_it_in.rb index 2ab737917..869d393f6 100644 --- a/app/helpers/turn_it_in.rb +++ b/app/helpers/turn_it_in.rb @@ -91,7 +91,7 @@ def self.global_error? # Indicates that tii can be called, that it is configured and there are no global errors def self.functional? - Doubtfire::Application.config.tii_enabled && !TurnItIn.global_error? + TurnItIn.enabled? && !TurnItIn.global_error? end # Indicates that the service is rate limited diff --git a/app/models/turn_it_in/task_definition_tii_module.rb b/app/models/turn_it_in/task_definition_tii_module.rb index 50a9c72f2..8e9d9e309 100644 --- a/app/models/turn_it_in/task_definition_tii_module.rb +++ b/app/models/turn_it_in/task_definition_tii_module.rb @@ -19,13 +19,13 @@ def tii_match_pct(idx) # # @return [Boolean] true if there are any Turnitin checks def tii_checks? - Doubtfire::Application.config.tii_enabled && + TurnItIn.enabled? && !upload_requirements.empty? && ((0..upload_requirements.length - 1).map { |i| use_tii?(i) }.inject(:|) || false) end def had_tii_checks_before_last_save? - Doubtfire::Application.config.tii_enabled && + TurnItIn.enabled? && upload_requirements_before_last_save.present? && !upload_requirements_before_last_save.empty? && ((0..upload_requirements_before_last_save.length - 1).map { |i| use_tii?(i, upload_requirements_before_last_save) }.inject(:|) || false) diff --git a/app/models/turn_it_in/user_tii_module.rb b/app/models/turn_it_in/user_tii_module.rb index bb183f4f4..59fcb5c56 100644 --- a/app/models/turn_it_in/user_tii_module.rb +++ b/app/models/turn_it_in/user_tii_module.rb @@ -18,7 +18,7 @@ def accept_tii_eula(eula_version = TurnItIn.eula_version) end def accepted_tii_eula? - return false unless Doubtfire::Application.config.tii_enabled + return false unless TurnItIn.enabled? return true unless TiiActionFetchFeaturesEnabled.eula_required? tii_eula_version == TurnItIn.eula_version diff --git a/test/models/tii_model_test.rb b/test/models/tii_model_test.rb index b6c8a4565..8cc79d3a7 100644 --- a/test/models/tii_model_test.rb +++ b/test/models/tii_model_test.rb @@ -7,7 +7,7 @@ class TiiModelTest < ActiveSupport::TestCase include TestHelpers::TestFileHelper def test_fetch_eula - skip "TurnItIn Integration Tests Skipped" unless Doubtfire::Application.config.tii_enabled + skip "TurnItIn Integration Tests Skipped" unless TurnItIn.enabled? clear_tii_eula refute Rails.cache.fetch('tii.eula_version').present? @@ -85,7 +85,7 @@ def test_fetch_eula end def test_fetch_eula_error_handling - skip "TurnItIn Integration Tests Skipped" unless Doubtfire::Application.config.tii_enabled + skip "TurnItIn Integration Tests Skipped" unless TurnItIn.enabled? clear_tii_eula eula_version_stub = stub_request(:get, "https://#{ENV['TCA_HOST']}/api/v1/eula/latest"). @@ -104,7 +104,7 @@ def test_fetch_eula_error_handling end def test_tii_features_enabled - skip "TurnItIn Integration Tests Skipped" unless Doubtfire::Application.config.tii_enabled + skip "TurnItIn Integration Tests Skipped" unless TurnItIn.enabled? clear_tii_festures_enabled body = '{ @@ -167,7 +167,7 @@ def test_tii_features_enabled end def test_tii_process - skip "TurnItIn Integration Tests Skipped" unless Doubtfire::Application.config.tii_enabled + skip "TurnItIn Integration Tests Skipped" unless TurnItIn.enabled? setup_tii_features_enabled From e01ed1940ecc7f91c66ea9d22ebbacae04ce7b70 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 16:08:49 +1000 Subject: [PATCH 070/124] feat: allow register webhooks to be controlled via config Also adds ability to reset global error. --- app/helpers/turn_it_in.rb | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/app/helpers/turn_it_in.rb b/app/helpers/turn_it_in.rb index 869d393f6..651f87801 100644 --- a/app/helpers/turn_it_in.rb +++ b/app/helpers/turn_it_in.rb @@ -15,12 +15,17 @@ def self.enabled? Doubtfire::Application.config.tii_enabled end + def self.register_webhooks? + Doubtfire::Application.config.tii_register_webhook + end + def self.load_config(config) config.tii_enabled = ENV['TII_ENABLED'].present? && (ENV['TII_ENABLED'].to_s.downcase == "true" || ENV['TII_ENABLED'].to_i == 1) - config.tii_add_submissions_to_index = ENV['TII_INDEX_SUBMISSIONS'].present? && (ENV['TII_INDEX_SUBMISSIONS'].to_s.downcase == "true" || ENV['TII_INDEX_SUBMISSIONS'].to_i == 1) - if config.tii_enabled + config.tii_add_submissions_to_index = ENV['TII_INDEX_SUBMISSIONS'].present? && (ENV['TII_INDEX_SUBMISSIONS'].to_s.downcase == "true" || ENV['TII_INDEX_SUBMISSIONS'].to_i == 1) + config.tii_register_webhook = ENV['TII_REGISTER_WEBHOOK'].present? && (ENV['TII_REGISTER_WEBHOOK'].to_s.downcase == "true" || ENV['TII_REGISTER_WEBHOOK'].to_i == 1) + # Turn-it-in TII configuration require 'tca_client' @@ -40,7 +45,7 @@ def self.load_config(config) # Launch the tii background jobs def self.launch_tii(with_webhooks: true) - TiiRegisterWebHookJob.perform_async if with_webhooks + TiiRegisterWebHookJob.perform_async if with_webhooks && TurnItIn.register_webhooks? load_tii_features load_tii_eula rescue StandardError => e @@ -89,6 +94,12 @@ def self.global_error? Rails.cache.exist?("tii.global_error") || @@global_error.present? end + # Clear a global error + def self.clear_global_error + @@global_error = nil + Rails.cache.delete("tii.global_error") + end + # Indicates that tii can be called, that it is configured and there are no global errors def self.functional? TurnItIn.enabled? && !TurnItIn.global_error? From 61f2f49905b3ab19534ac998444a15e3cb1e7a2d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 16:40:22 +1000 Subject: [PATCH 071/124] chore(release): 8.0.12 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d2776a00..da2c1e3ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.12](https://github.com/macite/doubtfire-deploy/compare/v8.0.11...v8.0.12) (2024-07-15) + + +### Features + +* allow register webhooks to be controlled via config ([e01ed19](https://github.com/macite/doubtfire-deploy/commit/e01ed1940ecc7f91c66ea9d22ebbacae04ce7b70)) + ### [8.0.11](https://github.com/macite/doubtfire-deploy/compare/v8.0.10...v8.0.11) (2024-07-12) From ebbacb90cd1602b04489d2d41ee9723d13a75852 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 17:20:52 +1000 Subject: [PATCH 072/124] fix: check need to register webhooks in tii action --- app/models/turn_it_in/tii_action_register_webhook.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/turn_it_in/tii_action_register_webhook.rb b/app/models/turn_it_in/tii_action_register_webhook.rb index b004125f6..f1b2e70ae 100644 --- a/app/models/turn_it_in/tii_action_register_webhook.rb +++ b/app/models/turn_it_in/tii_action_register_webhook.rb @@ -9,7 +9,7 @@ def description private def run - register_webhook if need_to_register_webhook? + register_webhook if TurnItIn.register_webhooks? && need_to_register_webhook? self.complete = true end From 4dae884dd29bf443d64654e36134e09e570ce31e Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 20:13:24 +1000 Subject: [PATCH 073/124] fix: ensure tii module looks for appropriate user On submit it should use submitted by which will identify the right user to send as submitter. --- app/models/turn_it_in/task_tii_module.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/turn_it_in/task_tii_module.rb b/app/models/turn_it_in/task_tii_module.rb index b88e318d8..3589d9a99 100644 --- a/app/models/turn_it_in/task_tii_module.rb +++ b/app/models/turn_it_in/task_tii_module.rb @@ -21,7 +21,7 @@ def send_documents_to_tii(submitter, accepted_tii_eula: false) filename: filename_for_upload(idx), submitted_at: Time.zone.now, status: :created, - submitted_by_user: submitter + submitted_by: submitter ) # and start its processing From 0bf29eb79824cfab89a6f4ce5ce15d89f1a77ca5 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 20:17:48 +1000 Subject: [PATCH 074/124] feat: add env var to configure log to stdout --- config/application.rb | 2 ++ lib/shell/generate_pdfs.sh | 4 ++-- lib/shell/sync_enrolments.sh | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/application.rb b/config/application.rb index a054a5064..88996a2a1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -42,6 +42,8 @@ class Application < Rails::Application config.student_import_weeks_before = ENV.fetch('DF_IMPORT_STUDENTS_WEEKS_BEFPRE', 1).to_f * 1.week + config.log_to_stdout = ENV['DF_LOG_TO_STDOUT'].present? && (ENV['DF_LOG_TO_STDOUT'].to_s.downcase == "true" || ENV['DF_LOG_TO_STDOUT'].to_i == 1) + # ==> Load credentials from env credentials.secret_key_base = ENV.fetch('DF_SECRET_KEY_BASE', Rails.env.production? ? nil : '9e010ee2f52af762916406fd2ac488c5694a6cc784777136e657511f8bbc7a73f96d59c0a9a778a0d7cf6406f8ecbf77efe4701dfbd63d8248fc7cc7f32dea97') credentials.secret_key_attr = ENV.fetch('DF_SECRET_KEY_ATTR', Rails.env.production? ? nil : 'e69fc5960ca0e8700844a3a25fe80373b41c0a265d342eba06950113f3766fd983bad9ec51bf36eb615d9711bfe1dd90b8e35f01841b323f604ffee857e32055') diff --git a/lib/shell/generate_pdfs.sh b/lib/shell/generate_pdfs.sh index a3a95cc84..8212177f4 100755 --- a/lib/shell/generate_pdfs.sh +++ b/lib/shell/generate_pdfs.sh @@ -7,8 +7,8 @@ APP_PATH=`cd "$APP_PATH"; pwd` ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -TERM=xterm-256color bundle exec rake submission:generate_pdfs -bundle exec rake maintenance:cleanup +DF_LOG_TO_STDOUT=true TERM=xterm-256color bundle exec rake submission:generate_pdfs +DF_LOG_TO_STDOUT=true bundle exec rake maintenance:cleanup #Delete tmp files that may not be cleaned up by image magick and ghostscript find /tmp -maxdepth 1 -name magick* -type f -delete diff --git a/lib/shell/sync_enrolments.sh b/lib/shell/sync_enrolments.sh index 696914f1b..bd2af116c 100755 --- a/lib/shell/sync_enrolments.sh +++ b/lib/shell/sync_enrolments.sh @@ -6,4 +6,4 @@ ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -bundle exec rake db:sync_enrolments +DF_LOG_TO_STDOUT=true bundle exec rake db:sync_enrolments From 6b08013b423ae990c34224fdd6c358b08026e9f0 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 16 Jul 2024 13:38:59 +1000 Subject: [PATCH 075/124] feat: check that old tii submissions upload when eula accepted --- app/helpers/turn_it_in.rb | 10 + app/models/turn_it_in/tii_action.rb | 1 + .../tii_action_upload_submission.rb | 26 ++- app/sidekiq/tii_check_progress_job.rb | 2 + test/sidekiq/tii_check_progress_job_test.rb | 215 +++++++++++++++++- 5 files changed, 251 insertions(+), 3 deletions(-) diff --git a/app/helpers/turn_it_in.rb b/app/helpers/turn_it_in.rb index 2ab737917..62df4e3f7 100644 --- a/app/helpers/turn_it_in.rb +++ b/app/helpers/turn_it_in.rb @@ -205,6 +205,16 @@ def self.tii_role_for(task, user) end end + # Check and retry any failed tii submissions, where it was due to no accepted EULA + def self.check_and_retry_submissions_with_updated_eula + TiiActionUploadSubmission + .where( + complete: false, + custom_error_message: TiiActionUploadSubmission::NO_USER_ACCEPTED_EULA_ERROR + ) + .find_each(&:attempt_retry_on_no_eula) + end + private def logger diff --git a/app/models/turn_it_in/tii_action.rb b/app/models/turn_it_in/tii_action.rb index 93a30792f..2573ddee0 100644 --- a/app/models/turn_it_in/tii_action.rb +++ b/app/models/turn_it_in/tii_action.rb @@ -124,6 +124,7 @@ def error? def save_and_reschedule(reset_retry: true) self.retries = 0 if reset_retry + self.error_code = nil # reset error code self.retry = true save end diff --git a/app/models/turn_it_in/tii_action_upload_submission.rb b/app/models/turn_it_in/tii_action_upload_submission.rb index bdd3403a0..e8281c0c1 100644 --- a/app/models/turn_it_in/tii_action_upload_submission.rb +++ b/app/models/turn_it_in/tii_action_upload_submission.rb @@ -4,6 +4,8 @@ class TiiActionUploadSubmission < TiiAction delegate :status_sym, :status, :submission_id, :submitted_by_user, :task, :idx, :similarity_pdf_id, :similarity_pdf_path, :filename, to: :entity + NO_USER_ACCEPTED_EULA_ERROR = 'None of the student, tutor, or unit lead have accepted the EULA for Turnitin'.freeze + def description "Upload #{self.filename} for #{self.task.student.username} from #{self.task.task_definition.abbreviation} (#{self.status} - #{self.next_step})" end @@ -214,7 +216,7 @@ def tii_submission_data result.submitter = submitted_by_user.username unless submitted_by_user.accepted_tii_eula? || (params.key?("accepted_tii_eula") && params["accepted_tii_eula"]) - save_and_log_custom_error "None of the student, tutor, or unit lead have accepted the EULA for Turnitin" + save_and_log_custom_error NO_USER_ACCEPTED_EULA_ERROR return nil end @@ -443,4 +445,26 @@ def fetch_tii_similarity_pdf_status result.status end end + + # If this submission is not progressing due to a user not accepting the EULA, then + # check if the user has accepted the EULA now and retry + def attempt_retry_on_no_eula + if self.retry == false && status_sym == :created && error_message == NO_USER_ACCEPTED_EULA_ERROR + # If the student has now submitted the eula... + unless entity.submitted_by.accepted_tii_eula? + # Try reassigning the submitted_by so that it checks for tutor + # or convenor eula + entity.submitted_by = entity.submitted_by_user + end + + # If we can submit from someone... + if submitted_by_user.accepted_tii_eula? + # Save any changes to the entity + entity.save + save_and_reschedule + end + + end + end + end diff --git a/app/sidekiq/tii_check_progress_job.rb b/app/sidekiq/tii_check_progress_job.rb index 5b7b02cf5..ca8084bee 100644 --- a/app/sidekiq/tii_check_progress_job.rb +++ b/app/sidekiq/tii_check_progress_job.rb @@ -9,6 +9,8 @@ class TiiCheckProgressJob def perform return unless TurnItIn.enabled? + TurnItIn.check_and_retry_submissions_with_updated_eula + run_waiting_actions TurnItIn.check_and_update_eula TurnItIn.check_and_update_features diff --git a/test/sidekiq/tii_check_progress_job_test.rb b/test/sidekiq/tii_check_progress_job_test.rb index e3b960b4c..f030a98da 100644 --- a/test/sidekiq/tii_check_progress_job_test.rb +++ b/test/sidekiq/tii_check_progress_job_test.rb @@ -4,6 +4,217 @@ class TiiCheckProgressJobTest < ActiveSupport::TestCase include TestHelpers::TiiTestHelper + def test_check_eula_change + TiiAction.delete_all + + setup_tii_eula + + # Create a task definition with two attachments + unit = FactoryBot.create(:unit, with_students: false, task_count: 0, stream_count: 0) + + task_def = FactoryBot.create(:task_definition, unit: unit, upload_requirements: [ + { + 'key' => 'file0', + 'name' => 'My document', + 'type' => 'document', + 'tii_check' => 'true', + 'tii_pct' => '10' + } + ]) + + # Setup users + convenor = unit.main_convenor_user + tutor = FactoryBot.create(:user, :tutor) + student = FactoryBot.create(:user, :student) + + # Add users to unit + tutor_unit_role = unit.employ_staff(tutor, Role.tutor) + project = unit.enrol_student(student, Campus.first) + + # Create tutorial and enrol + tutorial = FactoryBot.create(:tutorial, unit: unit, campus: Campus.first, unit_role: tutor_unit_role) + + project.enrol_in tutorial + + task = project.task_for_task_definition(task_def) + + # Create a submission + sub1 = TiiSubmission.create( + task: task, + idx: 0, + filename: 'test.doc', + status: :created, + submitted_by_user: student + ) + sub2 = TiiSubmission.create( + task: task, + idx: 0, + filename: 'test.doc', + status: :created, + submitted_by_user: student + ) + sub3 = TiiSubmission.create( + task: task, + idx: 0, + filename: 'test.doc', + status: :created, + submitted_by_user: student + ) + + action = TiiActionUploadSubmission.find_or_create_by(entity: sub1) + + # Test fail as not EULA accepted + action.perform + + assert_not action.retry + assert_not action.complete + assert_equal TiiActionUploadSubmission::NO_USER_ACCEPTED_EULA_ERROR, action.custom_error_message + + # Now have convenor accept EULA + convenor.tii_eula_date = DateTime.now + convenor.tii_eula_version = TurnItIn.eula_version + convenor.save + + # Check the convenor has accepted + assert convenor.accepted_tii_eula? + + # See if we can retry + action.attempt_retry_on_no_eula + + assert action.retry + assert_not action.complete + assert_equal convenor, sub1.submitted_by + + convenor.tii_eula_version = nil + convenor.tii_eula_date = nil + convenor.save + assert_not convenor.accepted_tii_eula? + + # Reset... to try with tutor + action = TiiActionUploadSubmission.find_or_create_by(entity: sub2) + action.perform + + # Tutor accepts eula + tutor.tii_eula_date = DateTime.now + tutor.tii_eula_version = TurnItIn.eula_version + tutor.save + + # Check the tutor has accepted + assert tutor.accepted_tii_eula? + + # See if we can retry + action.attempt_retry_on_no_eula + + assert action.retry + assert_not action.complete + assert_equal tutor, sub2.submitted_by + + tutor.tii_eula_version = nil + tutor.tii_eula_date = nil + tutor.save + assert_not tutor.accepted_tii_eula? + + # Reset... to try with student + action = TiiActionUploadSubmission.find_or_create_by(entity: sub3) + action.perform + + # Student accepts eula + student.tii_eula_date = DateTime.now + student.tii_eula_version = TurnItIn.eula_version + student.save + + # Check the student has accepted + assert student.accepted_tii_eula? + + # See if we can retry + action.attempt_retry_on_no_eula + + assert action.retry + assert_not action.complete + assert_equal student, sub3.submitted_by + ensure + unit.destroy + end + + def test_that_progress_checks_eula_change + TiiAction.delete_all + + setup_tii_eula + setup_tii_features_enabled + + # Create a task definition with two attachments + unit = FactoryBot.create(:unit, with_students: false, task_count: 0, stream_count: 0) + + task_def = FactoryBot.create(:task_definition, unit: unit, upload_requirements: [ + { + 'key' => 'file0', + 'name' => 'My document', + 'type' => 'document', + 'tii_check' => 'true', + 'tii_pct' => '10' + } + ]) + + # Setup users + convenor = unit.main_convenor_user + tutor = FactoryBot.create(:user, :tutor) + student = FactoryBot.create(:user, :student) + + # Add users to unit + tutor_unit_role = unit.employ_staff(tutor, Role.tutor) + project = unit.enrol_student(student, Campus.first) + + # Create tutorial and enrol + tutorial = FactoryBot.create(:tutorial, unit: unit, campus: Campus.first, unit_role: tutor_unit_role) + + project.enrol_in tutorial + + task = project.task_for_task_definition(task_def) + + # Create a submission + sub1 = TiiSubmission.create( + task: task, + idx: 0, + filename: 'test.doc', + status: :created, + submitted_by_user: student + ) + + action = TiiActionUploadSubmission.find_or_create_by(entity: sub1) + + # Test fail as not EULA accepted + action.perform + + assert_not action.retry + assert_not action.complete + assert_equal TiiActionUploadSubmission::NO_USER_ACCEPTED_EULA_ERROR, action.custom_error_message + + # Get the job + job = TiiCheckProgressJob.new + + # Performing the job does not chaange the action - no eula change + job.perform + + action.reload + assert_not action.retry + assert_not action.complete + + # Now have convenor accept EULA + convenor.tii_eula_date = DateTime.now + convenor.tii_eula_version = TurnItIn.eula_version + convenor.save + + # Perform progress check job + job.perform + + # Will trigger retry of action, but wont perform as it is not old + action.reload + assert action.retry + assert_not action.complete + + unit.destroy + end + def test_waits_to_process_action setup_tii_eula @@ -76,7 +287,7 @@ def test_waits_to_process_action assert_requested accept_request, times: 2 assert action.reload.retry - refute action.complete + assert_not action.complete action.update(last_run: DateTime.now - 31.minutes) job.perform # attempt 3 - but rate limited @@ -92,7 +303,7 @@ def test_waits_to_process_action # Check it was all success assert action.reload.complete - refute action.retry + assert_not action.retry assert user.reload.accepted_tii_eula? assert user.tii_eula_version_confirmed From 03e9214182e07561100b051cbed6e82191cc8750 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 16 Jul 2024 14:27:39 +1000 Subject: [PATCH 076/124] fix: limit tii action log to 25 entries --- app/models/turn_it_in/tii_action.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/models/turn_it_in/tii_action.rb b/app/models/turn_it_in/tii_action.rb index 93a30792f..ffe0edc10 100644 --- a/app/models/turn_it_in/tii_action.rb +++ b/app/models/turn_it_in/tii_action.rb @@ -60,6 +60,12 @@ def perform result = run self.log << { date: Time.zone.now, message: "#{type} Ended" } + + # Ensure log does not get too long! + if self.log.size > 25 + self.log = self.log.last(25) + end + save result From be21763e2b486df0181da1a87ffbddcfb7407388 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 16 Jul 2024 14:28:02 +1000 Subject: [PATCH 077/124] fix: ensure webhook test will register hooks --- test/sidekiq/tii_webhooks_job_test.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/sidekiq/tii_webhooks_job_test.rb b/test/sidekiq/tii_webhooks_job_test.rb index 217878dac..e431676ca 100644 --- a/test/sidekiq/tii_webhooks_job_test.rb +++ b/test/sidekiq/tii_webhooks_job_test.rb @@ -5,6 +5,8 @@ class TiiCWebhooksJobTest < ActiveSupport::TestCase include TestHelpers::TiiTestHelper def test_register_webhooks + Doubtfire::Application.config.tii_register_webhook = true + # Will ask for current webhooks list_webhooks_stub = stub_request(:get, "https://#{ENV['TCA_HOST']}/api/v1/webhooks"). with(tii_headers). @@ -58,6 +60,8 @@ def test_register_webhooks end def test_do_not_register_if_registered + Doubtfire::Application.config.tii_register_webhook = true + # Will ask for current webhooks list_webhooks_stub = stub_request(:get, "https://#{ENV['TCA_HOST']}/api/v1/webhooks"). with(tii_headers). From 789fbada30f8d91cfaff732a4392ecb12d346e3f Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 16 Jul 2024 14:32:47 +1000 Subject: [PATCH 078/124] fix: tii action retry resets retries --- app/api/tii/tii_action_api.rb | 3 +-- app/models/turn_it_in/tii_action.rb | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/api/tii/tii_action_api.rb b/app/api/tii/tii_action_api.rb index 979eae9ef..af7d2e2cc 100644 --- a/app/api/tii/tii_action_api.rb +++ b/app/api/tii/tii_action_api.rb @@ -52,8 +52,7 @@ class TiiActionApi < Grape::API case params[:action] when 'retry' error!({ error: 'Retry in progress. Please wait.' }, 403) if action.retry - action.update(retry: true) - action.perform_async + action.perform_retry else error!({ error: 'Invalid action' }, 400) end diff --git a/app/models/turn_it_in/tii_action.rb b/app/models/turn_it_in/tii_action.rb index ffe0edc10..1f5928cda 100644 --- a/app/models/turn_it_in/tii_action.rb +++ b/app/models/turn_it_in/tii_action.rb @@ -128,6 +128,11 @@ def error? error_code.present? end + def perform_retry + save_and_reschedule + perform_async + end + def save_and_reschedule(reset_retry: true) self.retries = 0 if reset_retry self.retry = true From 4f3979ba4c00a0040f4899e33e48cd950cb6e833 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 17 Jul 2024 13:09:34 +1000 Subject: [PATCH 079/124] fix: merge student records for deakin students --- config/deakin.rb | 53 ++++++++++++++++++++++++------------------------ 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/config/deakin.rb b/config/deakin.rb index dedab6494..1185bcd00 100644 --- a/config/deakin.rb +++ b/config/deakin.rb @@ -273,37 +273,36 @@ def sync_student_user_from_callista(row_data) username_user elsif username_user.present? && student_id_user.present? + + # Check if the username user student id contains the student id + unless username_user.student_id.blank? || username_user.student_id.include?(student_id_user.student_id) + logger.error("Unable to fix user #{row_data} - username user has an unrelated student id. Cannot merge records - Need manual fix.") + return nil + end + # Both present, but different... - # Most likely updated username with existing student id - if username_user.projects.count == 0 && student_id_user.projects.count > 0 - # Change the student id user to use the new username and email - student_id_user.username = username_user.username - student_id_user.email = username_user.email - student_id_user.login_id = nil - student_id_user.auth_tokens.destroy_all - - # Correct the new username user record - so we mark this as a duplicate and move to the old record - username_user.username = "OLD-#{username_user.username}" - username_user.email = "DUP-#{username_user.email}" - username_user.login_id = nil - - unless username_user.save - logger.error("Unable to fix user #{row_data} - username_user.save failed") - return nil - end - username_user.auth_tokens.destroy_all + # Merge them into the username user, as the student id user does not have the new username - unless student_id_user.save - logger.error("Unable to fix user #{row_data} - student_id_user.save failed") - return nil - end + # Change the username user... + username_user.student_id = student_id_user.student_id - # We keep the student id user... so return this - student_id_user - else - logger.error("Unable to fix user #{row_data} - both username and student id users present. Need manual fix.") - nil + # Correct the older student id record + student_id_user.student_id = "DUP-#{student_id_user.student_id}" + + # Save student id user first - free student id from duplicate error + unless student_id_user.save + logger.error("Unable to fix user #{row_data} - student_id_user.save failed") + return nil + end + + # Update the username user + unless username_user.save + logger.error("Unable to fix user #{row_data} - username_user.save failed") + return nil end + + # We keep the student id user... so return this + username_user else logger.error("Unable to fix user #{row_data} - Need manual fix.") nil From 6c74d7d15207b630539b71b0d8810dd09c4491e1 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 17 Jul 2024 13:10:04 +1000 Subject: [PATCH 080/124] chore(release): 8.0.13 --- CHANGELOG.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da2c1e3ee..401c5d77d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,24 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.13](https://github.com/macite/doubtfire-deploy/compare/v8.0.12...v8.0.13) (2024-07-17) + + +### Features + +* add env var to configure log to stdout ([0bf29eb](https://github.com/macite/doubtfire-deploy/commit/0bf29eb79824cfab89a6f4ce5ce15d89f1a77ca5)) +* check that old tii submissions upload when eula accepted ([6b08013](https://github.com/macite/doubtfire-deploy/commit/6b08013b423ae990c34224fdd6c358b08026e9f0)) + + +### Bug Fixes + +* check need to register webhooks in tii action ([ebbacb9](https://github.com/macite/doubtfire-deploy/commit/ebbacb90cd1602b04489d2d41ee9723d13a75852)) +* ensure tii module looks for appropriate user ([4dae884](https://github.com/macite/doubtfire-deploy/commit/4dae884dd29bf443d64654e36134e09e570ce31e)) +* ensure webhook test will register hooks ([be21763](https://github.com/macite/doubtfire-deploy/commit/be21763e2b486df0181da1a87ffbddcfb7407388)) +* limit tii action log to 25 entries ([03e9214](https://github.com/macite/doubtfire-deploy/commit/03e9214182e07561100b051cbed6e82191cc8750)) +* merge student records for deakin students ([4f3979b](https://github.com/macite/doubtfire-deploy/commit/4f3979ba4c00a0040f4899e33e48cd950cb6e833)) +* tii action retry resets retries ([789fbad](https://github.com/macite/doubtfire-deploy/commit/789fbada30f8d91cfaff732a4392ecb12d346e3f)) + ### [8.0.12](https://github.com/macite/doubtfire-deploy/compare/v8.0.11...v8.0.12) (2024-07-15) From de3ec392612470a1103f6a04c737775965e58ccf Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 18 Jul 2024 11:41:31 +1000 Subject: [PATCH 081/124] fix: add logging info to debug hmac issues --- app/api/tii/turn_it_in_hooks_api.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/api/tii/turn_it_in_hooks_api.rb b/app/api/tii/turn_it_in_hooks_api.rb index 694099c26..879005e5a 100644 --- a/app/api/tii/turn_it_in_hooks_api.rb +++ b/app/api/tii/turn_it_in_hooks_api.rb @@ -20,11 +20,11 @@ class TurnItInHooksApi < Grape::API data = JSON.parse(env['api.request.input']) digest = OpenSSL::Digest.new('sha256') - # puts data + logger.info("TII_HOOK_DEBUG:#{data}") hmac = OpenSSL::HMAC.hexdigest(digest, ENV.fetch('TCA_SIGNING_KEY', nil), data.to_json) - # puts hmac - # puts headers['x-turnitin-signature'] + logger.info("TII_HOOK_DEBUG:#{hmac}") + logger.info("TII_HOOK_DEBUG:#{headers['x-turnitin-signature']}") if hmac != headers["x-turnitin-signature"] logger.error("TII: HMAC does not match") From 7d47eda6affafb6056d391a101c39670e3a1b7f6 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 18 Jul 2024 11:41:50 +1000 Subject: [PATCH 082/124] feat: allow logging to stdout using env var --- config/initializers/log_initializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/log_initializer.rb b/config/initializers/log_initializer.rb index 38b524645..1ee180e30 100644 --- a/config/initializers/log_initializer.rb +++ b/config/initializers/log_initializer.rb @@ -1,5 +1,5 @@ # Ensure log outputs to stdout in development -if Rails.env.development? +if Rails.env.development? || Doubtfire::Application.config.log_to_stdout Rails.logger.broadcast_to(ActiveSupport::Logger.new($stdout, level: Rails.logger.level)) end From cc2f6749f386091f0c7fa1a9e41bf366c5cff58c Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 18 Jul 2024 13:01:03 +1000 Subject: [PATCH 083/124] chore: fix test to use assert_not and ensure actions are destroyed --- test/models/tii_user_accept_eula_test.rb | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/test/models/tii_user_accept_eula_test.rb b/test/models/tii_user_accept_eula_test.rb index 6d156a053..df11250a4 100644 --- a/test/models/tii_user_accept_eula_test.rb +++ b/test/models/tii_user_accept_eula_test.rb @@ -15,7 +15,7 @@ def test_can_accept_tii_eula assert user.tii_eula_date.present? assert_equal TurnItIn.eula_version, user.tii_eula_version - refute user.tii_eula_version_confirmed + assert_not user.tii_eula_version_confirmed assert_equal 1, TiiActionJob.jobs.count @@ -35,6 +35,7 @@ def test_can_accept_tii_eula end def test_eula_accept_will_retry + TiiAction.destroy_all setup_tii_eula user = FactoryBot.create(:user) @@ -45,10 +46,10 @@ def test_eula_accept_will_retry # Get the action tracking this progress... action = TiiActionAcceptEula.last - refute action.complete + assert_not action.complete assert action.retry - refute user.tii_eula_version_confirmed + assert_not user.tii_eula_version_confirmed assert_equal 1, TiiActionJob.jobs.count assert_equal user, action.entity @@ -67,7 +68,7 @@ def test_eula_accept_will_retry action.reload assert_requested accept_stub, times: 1 - refute action.complete + assert_not action.complete assert action.retry # Reset to retry with check progress sweep @@ -77,11 +78,11 @@ def test_eula_accept_will_retry check_job.perform # Second fails action.reload - refute user.reload.tii_eula_version_confirmed + assert_not user.reload.tii_eula_version_confirmed assert_requested accept_stub, times: 2 - refute action.complete - refute action.retry + assert_not action.complete + assert_not action.retry # Reset to retry with check progress sweep action.update(last_run: DateTime.now - 31.minutes, retry: true) @@ -91,7 +92,7 @@ def test_eula_accept_will_retry assert_requested accept_stub, times: 3 assert action.complete - refute action.retry + assert_not action.retry # Reload our copy of user user.reload @@ -160,9 +161,9 @@ def test_eula_respects_global_errors action.perform assert_requested accept_stub, times: 1 - refute TurnItIn.functional? + assert_not TurnItIn.functional? - refute action.retry + assert_not action.retry action.perform # Call does not go to tii as limit applied From 72b4c697bc3f103e1959b3d18902259417ec1651 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 18 Jul 2024 13:21:05 +1000 Subject: [PATCH 084/124] chore: switch bundle exec to rails in shell scripts --- lib/shell/check_plagiarism.sh | 2 +- lib/shell/generate_pdfs.sh | 4 ++-- lib/shell/send_weekly_emails.sh | 2 +- lib/shell/sync_enrolments.sh | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/shell/check_plagiarism.sh b/lib/shell/check_plagiarism.sh index 43847f2f8..c64035dd9 100755 --- a/lib/shell/check_plagiarism.sh +++ b/lib/shell/check_plagiarism.sh @@ -8,4 +8,4 @@ ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -bundle exec rake submission:check_plagiarism +DF_LOG_TO_STDOUT=true rails submission:check_plagiarism diff --git a/lib/shell/generate_pdfs.sh b/lib/shell/generate_pdfs.sh index 8212177f4..6daa5592b 100755 --- a/lib/shell/generate_pdfs.sh +++ b/lib/shell/generate_pdfs.sh @@ -7,8 +7,8 @@ APP_PATH=`cd "$APP_PATH"; pwd` ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -DF_LOG_TO_STDOUT=true TERM=xterm-256color bundle exec rake submission:generate_pdfs -DF_LOG_TO_STDOUT=true bundle exec rake maintenance:cleanup +DF_LOG_TO_STDOUT=true TERM=xterm-256color rails submission:generate_pdfs +DF_LOG_TO_STDOUT=true rails maintenance:cleanup #Delete tmp files that may not be cleaned up by image magick and ghostscript find /tmp -maxdepth 1 -name magick* -type f -delete diff --git a/lib/shell/send_weekly_emails.sh b/lib/shell/send_weekly_emails.sh index 5237ccd3b..d56ab71b6 100755 --- a/lib/shell/send_weekly_emails.sh +++ b/lib/shell/send_weekly_emails.sh @@ -8,4 +8,4 @@ ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -bundle exec rake mailer:send_status_emails +DF_LOG_TO_STDOUT=true rails mailer:send_status_emails diff --git a/lib/shell/sync_enrolments.sh b/lib/shell/sync_enrolments.sh index bd2af116c..3e5610855 100755 --- a/lib/shell/sync_enrolments.sh +++ b/lib/shell/sync_enrolments.sh @@ -6,4 +6,4 @@ ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -DF_LOG_TO_STDOUT=true bundle exec rake db:sync_enrolments +DF_LOG_TO_STDOUT=true rails db:sync_enrolments From 15ca645023c2ef969500c5185d20cf58c288233a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 18 Jul 2024 20:00:44 +1000 Subject: [PATCH 085/124] chore: update portfolio autogen shell script --- lib/shell/portfolio_autogen_check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/shell/portfolio_autogen_check.sh b/lib/shell/portfolio_autogen_check.sh index 1ad011282..73e1b04d2 100755 --- a/lib/shell/portfolio_autogen_check.sh +++ b/lib/shell/portfolio_autogen_check.sh @@ -7,4 +7,4 @@ ROOT_PATH=`cd "$APP_PATH"/../..; pwd` cd "$ROOT_PATH" -bundle exec rake submission:portfolio_autogen_check +DF_LOG_TO_STDOUT=true rails submission:portfolio_autogen_check From 68a724850540ac66e33c476783dd6030f688e222 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 18 Jul 2024 20:18:19 +1000 Subject: [PATCH 086/124] chore(release): 8.0.14 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 401c5d77d..77b72adc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.14](https://github.com/macite/doubtfire-deploy/compare/v8.0.13...v8.0.14) (2024-07-18) + + +### Features + +* allow logging to stdout using env var ([7d47eda](https://github.com/macite/doubtfire-deploy/commit/7d47eda6affafb6056d391a101c39670e3a1b7f6)) + + +### Bug Fixes + +* add logging info to debug hmac issues ([de3ec39](https://github.com/macite/doubtfire-deploy/commit/de3ec392612470a1103f6a04c737775965e58ccf)) + ### [8.0.13](https://github.com/macite/doubtfire-deploy/compare/v8.0.12...v8.0.13) (2024-07-17) From a249662d6866a80cf03c5793bc4816a766ad2b97 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sat, 20 Jul 2024 16:50:53 +1000 Subject: [PATCH 087/124] fix: correct turn it in hmac calculation --- app/api/tii/turn_it_in_hooks_api.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/api/tii/turn_it_in_hooks_api.rb b/app/api/tii/turn_it_in_hooks_api.rb index 879005e5a..99e2a512b 100644 --- a/app/api/tii/turn_it_in_hooks_api.rb +++ b/app/api/tii/turn_it_in_hooks_api.rb @@ -17,11 +17,12 @@ class TurnItInHooksApi < Grape::API } } post 'tii_hook' do - data = JSON.parse(env['api.request.input']) + raw_data = env['api.request.input'] + data = JSON.parse(raw_data) digest = OpenSSL::Digest.new('sha256') - logger.info("TII_HOOK_DEBUG:#{data}") - hmac = OpenSSL::HMAC.hexdigest(digest, ENV.fetch('TCA_SIGNING_KEY', nil), data.to_json) + logger.info("TII_HOOK_DEBUG:#{raw_data}") + hmac = OpenSSL::HMAC.hexdigest(digest, ENV.fetch('TCA_SIGNING_KEY', nil), raw_data) logger.info("TII_HOOK_DEBUG:#{hmac}") logger.info("TII_HOOK_DEBUG:#{headers['x-turnitin-signature']}") From 1b2a43c0bfe45019b69bbf1952373709c09b67c5 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 13:38:09 +1000 Subject: [PATCH 088/124] fix: ensure pax header is not included in tex on 2nd pass --- app/views/layouts/application.pdf.erbtex | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/application.pdf.erbtex b/app/views/layouts/application.pdf.erbtex index ab70189c8..982bcda26 100644 --- a/app/views/layouts/application.pdf.erbtex +++ b/app/views/layouts/application.pdf.erbtex @@ -33,12 +33,16 @@ filecolor=black, urlcolor=blue, citecolor=black} - +<% +if @include_pax +%> \usepackage{newpax} \newpaxsetup{usefileattributes=true, addannots=true} \directlua{require("newpax")} <%= yield :preamble_newpax %> - +<% +end +%> \epstopdfDeclareGraphicsRule{.tif}{png}{.png}{convert #1 \OutputFile} \AppendGraphicsExtensions{.tif} \epstopdfDeclareGraphicsRule{.tiff}{png}{.png}{convert #1 \OutputFile} From 38a6922d203aa16b80643a7d3eb8ee7ba099a420 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 14:16:17 +1000 Subject: [PATCH 089/124] chore(release): 8.0.15 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77b72adc7..77457387e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.15](https://github.com/macite/doubtfire-deploy/compare/v8.0.14...v8.0.15) (2024-07-22) + + +### Bug Fixes + +* correct turn it in hmac calculation ([a249662](https://github.com/macite/doubtfire-deploy/commit/a249662d6866a80cf03c5793bc4816a766ad2b97)) +* ensure pax header is not included in tex on 2nd pass ([1b2a43c](https://github.com/macite/doubtfire-deploy/commit/1b2a43c0bfe45019b69bbf1952373709c09b67c5)) + ### [8.0.14](https://github.com/macite/doubtfire-deploy/compare/v8.0.13...v8.0.14) (2024-07-18) From 232dcaa7c5ea11109d35bc3bd7cd9d3c737259cd Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 16:50:05 +1000 Subject: [PATCH 090/124] fix: ensure comment added on task pdf convert fail --- app/models/portfolio_evidence.rb | 14 +--- app/models/task.rb | 6 +- app/sidekiq/accept_submission_job.rb | 18 ++++- test/api/tasks_api_test.rb | 2 +- test/api/units/task_definitions_api_test.rb | 2 +- test/models/task_test.rb | 78 +++++++++++++++++---- 6 files changed, 85 insertions(+), 35 deletions(-) diff --git a/app/models/portfolio_evidence.rb b/app/models/portfolio_evidence.rb index 2a5d57adc..e5a39e80a 100644 --- a/app/models/portfolio_evidence.rb +++ b/app/models/portfolio_evidence.rb @@ -50,9 +50,6 @@ def self.process_new_to_pdf(my_source) logger.error "Failed to process folder_id = #{folder_id}. #{message}" if task - task.add_text_comment task.project.tutor_for(task.task_definition), "**Automated Comment**: Something went wrong with your submission. Check the files and resubmit this task. #{message}" - task.trigger_transition trigger: 'fix', by_user: task.project.tutor_for(task.task_definition) - errors[task.project] = [] if errors[task.project].nil? errors[task.project] << task end @@ -60,7 +57,7 @@ def self.process_new_to_pdf(my_source) begin logger.info "creating pdf for task #{task.id}" - success = task.convert_submission_to_pdf(my_source) + success = task.convert_submission_to_pdf(source_folder: my_source, log_to_stdout: true) if success done[task.project] = [] if done[task.project].nil? @@ -73,15 +70,6 @@ def self.process_new_to_pdf(my_source) end end - # Remove email of task notification success - only email on fail - # done.each do |project, tasks| - # logger.info "checking email for project #{project.id}" - # if project.student.receive_task_notifications - # logger.info "emailing task notification to #{project.student.name}" - # PortfolioEvidenceMailer.task_pdf_ready_message(project, tasks).deliver - # end - # end - errors.each do |project, tasks| logger.debug "checking email for project #{project.id}" next unless project.student.receive_task_notifications diff --git a/app/models/task.rb b/app/models/task.rb index 22992041d..d40ff2933 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1078,7 +1078,7 @@ def final_pdf_path end # Convert a submission to pdf - the source folder is the root folder in which the submission folder will be found (not the submission folder itself) - def convert_submission_to_pdf(source_folder = FileHelper.student_work_dir(:new)) + def convert_submission_to_pdf(source_folder: FileHelper.student_work_dir(:new), log_to_stdout: true) return false unless move_files_to_in_process(source_folder) begin @@ -1100,7 +1100,7 @@ def convert_submission_to_pdf(source_folder = FileHelper.student_work_dir(:new)) log_file = e.message.scan(/\/.*\.log/).first # puts "log file is ... #{log_file}" - if log_file && File.exist?(log_file) + if log_to_stdout && log_file && File.exist?(log_file) # puts "exists" begin # rubocop:disable Rails/Output @@ -1148,8 +1148,8 @@ def convert_submission_to_pdf(source_folder = FileHelper.student_work_dir(:new)) return true rescue => e clear_in_process - trigger_transition trigger: 'fix', by_user: project.tutor_for(task_definition) + add_text_comment project.tutor_for(task_definition), "**Automated Comment**: Something went wrong with your submission. Check the files and resubmit this task. #{e.message.to_s}" raise e end end diff --git a/app/sidekiq/accept_submission_job.rb b/app/sidekiq/accept_submission_job.rb index 8584424d2..71e28bdcf 100644 --- a/app/sidekiq/accept_submission_job.rb +++ b/app/sidekiq/accept_submission_job.rb @@ -13,8 +13,22 @@ def perform(task_id, user_id, accepted_tii_eula) task = Task.find(task_id) user = User.find(user_id) - # Convert submission to PDF - task.convert_submission_to_pdf + begin + # Convert submission to PDF + task.convert_submission_to_pdf(log_to_stdout: false) + rescue StandardError => e + # Send email to student if task pdf failed + if task.project.student.receive_task_notifications + begin + PortfolioEvidenceMailer.task_pdf_failed(project, [task]).deliver + rescue StandardError => e + logger.error "Failed to send task pdf failed email for project #{project.id}!\n#{e.message}" + end + end + + logger.error e + return + end # When converted, we can now send documents to turn it in for checking if TurnItIn.functional? diff --git a/test/api/tasks_api_test.rb b/test/api/tasks_api_test.rb index 1e84f3f3c..7ef684fca 100644 --- a/test/api/tasks_api_test.rb +++ b/test/api/tasks_api_test.rb @@ -400,7 +400,7 @@ def test_can_submit_ipynb assert_equal 201, last_response.status, last_response_body task = project.task_for_task_definition(td) - task.convert_submission_to_pdf + task.convert_submission_to_pdf(log_to_stdout: false) assert File.exist? task.final_pdf_path td.destroy diff --git a/test/api/units/task_definitions_api_test.rb b/test/api/units/task_definitions_api_test.rb index 218472caf..abb0a0cd0 100644 --- a/test/api/units/task_definitions_api_test.rb +++ b/test/api/units/task_definitions_api_test.rb @@ -309,7 +309,7 @@ def test_change_to_group_after_submissions assert_equal 201, last_response.status task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path diff --git a/test/models/task_test.rb b/test/models/task_test.rb index 22bdda0a9..d78bf65c1 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -74,7 +74,7 @@ def test_pdf_creation_with_gif assert_equal 201, last_response.status, last_response_body task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -161,7 +161,7 @@ def test_pdf_creation_with_jpg assert_equal 201, last_response.status task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -205,7 +205,7 @@ def test_pdf_with_quotes_in_task_title task = project.task_for_task_definition(td) - task.convert_submission_to_pdf + task.convert_submission_to_pdf(log_to_stdout: false) path = task.final_pdf_path assert File.exist? path @@ -251,7 +251,7 @@ def test_copy_draft_learning_summary assert project_task.processing_pdf? # Generate pdf for task - assert project_task.convert_submission_to_pdf + assert project_task.convert_submission_to_pdf(log_to_stdout: false) # Check if pdf was copied over project.reload @@ -308,7 +308,7 @@ def test_draft_learning_summary_wont_copy assert project_task.processing_pdf? # Generate pdf for task - assert project_task.convert_submission_to_pdf + assert project_task.convert_submission_to_pdf(log_to_stdout: false) # Check if the file was moved to portfolio assert_not project.uses_draft_learning_summary @@ -352,7 +352,7 @@ def test_ipynb_to_pdf assert_equal 201, last_response.status, last_response_body task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -377,7 +377,7 @@ def test_ipynb_to_pdf assert_equal 201, last_response.status, last_response_body # test submission generation - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -394,7 +394,7 @@ def test_ipynb_to_pdf assert_equal 201, last_response.status, last_response_body # test submission generation - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -446,7 +446,7 @@ def test_code_submission_with_long_lines # test submission generation task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -469,7 +469,7 @@ def test_code_submission_with_long_lines # test submission generation task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -520,7 +520,7 @@ def test_code_submission_with_long_lines # test submission generation task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -543,7 +543,7 @@ def test_code_submission_with_long_lines # test submission generation task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -594,7 +594,7 @@ def test_code_submission_with_long_lines # test submission generation task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -617,7 +617,7 @@ def test_code_submission_with_long_lines # test submission generation task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -631,6 +631,7 @@ def test_code_submission_with_long_lines assert_not File.exist? path unit.destroy! end + def test_pdf_validation_on_submit unit = FactoryBot.create(:unit, student_count: 1, task_count: 0) td = TaskDefinition.new({ @@ -689,7 +690,7 @@ def test_pdf_validation_on_submit assert_equal 201, last_response.status, last_response_body task = project.task_for_task_definition(td) - assert task.convert_submission_to_pdf + assert task.convert_submission_to_pdf(log_to_stdout: false) path = task.zip_file_path_for_done_task assert path assert File.exist? path @@ -699,4 +700,51 @@ def test_pdf_validation_on_submit assert_not File.exist? path unit.destroy! end + + def test_pdf_creation_fails_on_invalid_pdf + unit = FactoryBot.create(:unit, student_count: 1, task_count: 0) + td = TaskDefinition.new({ + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'PDF Test Task', + description: 'Test task', + weighting: 4, + target_grade: 0, + start_date: unit.start_date + 1.week, + target_date: unit.start_date + 2.weeks, + abbreviation: 'PDFTestTask', + restrict_status_updates: false, + upload_requirements: [ { "key" => 'file0', "name" => 'A pdf file', "type" => 'code' } ], + plagiarism_warn_pct: 0.8, + is_graded: false, + max_quality_pts: 0 + }) + td.save! + + data_to_post = { + trigger: 'ready_for_feedback' + } + + project = unit.active_projects.first + + task = project.task_for_task_definition(td) + + folder = FileHelper.student_work_dir(:new, task) + + # Copy the file in + FileUtils.cp('test_files/submissions/corrupted.pdf', "#{folder}/001-code.cs") + + begin + assert_not task.convert_submission_to_pdf(log_to_stdout: false) + rescue StandardError => e + task.reload + + assert_equal 2, task.comments.count + assert task.comments.last.comment.starts_with?('**Automated Comment**:') + assert task.comments.last.comment.include?(e.message.to_s) + + td.destroy + unit.destroy! + end + end end From b70aeacf1ce361a44c23bf372699f135c181742f Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 17:04:18 +1000 Subject: [PATCH 091/124] chore(release): 8.0.16 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 77457387e..382f1c98e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.16](https://github.com/macite/doubtfire-deploy/compare/v8.0.15...v8.0.16) (2024-07-22) + + +### Bug Fixes + +* ensure comment added on task pdf convert fail ([232dcaa](https://github.com/macite/doubtfire-deploy/commit/232dcaa7c5ea11109d35bc3bd7cd9d3c737259cd)) + ### [8.0.15](https://github.com/macite/doubtfire-deploy/compare/v8.0.14...v8.0.15) (2024-07-22) From b8687991d0e8b6d33698c808bb4c3a3b11ddddcf Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 17:06:08 +1000 Subject: [PATCH 092/124] quality: address minor cop issue with automated error messages --- app/models/task.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/task.rb b/app/models/task.rb index d40ff2933..f174a426a 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1149,7 +1149,7 @@ def convert_submission_to_pdf(source_folder: FileHelper.student_work_dir(:new), rescue => e clear_in_process trigger_transition trigger: 'fix', by_user: project.tutor_for(task_definition) - add_text_comment project.tutor_for(task_definition), "**Automated Comment**: Something went wrong with your submission. Check the files and resubmit this task. #{e.message.to_s}" + add_text_comment project.tutor_for(task_definition), "**Automated Comment**: Something went wrong with your submission. Check the files and resubmit this task. #{e.message}" raise e end end From 4e38e6c4bf88b2d5a836ce7af2fcce913946f609 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 21:06:48 +1000 Subject: [PATCH 093/124] test: fix issues with file locn and tii features --- test/api/tii/tii_action_api_test.rb | 2 +- test/models/task_test.rb | 2 +- test/models/tii_user_accept_eula_test.rb | 4 ++++ test/sidekiq/tii_check_progress_job_test.rb | 3 ++- 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/test/api/tii/tii_action_api_test.rb b/test/api/tii/tii_action_api_test.rb index c81cd2b27..50d6b1f1e 100644 --- a/test/api/tii/tii_action_api_test.rb +++ b/test/api/tii/tii_action_api_test.rb @@ -15,7 +15,7 @@ def app setup do TiiAction.delete_all - + setup_tii_features_enabled setup_tii_eula # Create a task definition with two attachments diff --git a/test/models/task_test.rb b/test/models/task_test.rb index d78bf65c1..877ee3fca 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -732,7 +732,7 @@ def test_pdf_creation_fails_on_invalid_pdf folder = FileHelper.student_work_dir(:new, task) # Copy the file in - FileUtils.cp('test_files/submissions/corrupted.pdf', "#{folder}/001-code.cs") + FileUtils.cp(Rails.root.join('test_files/submissions/corrupted.pdf'), "#{folder}/001-code.cs") begin assert_not task.convert_submission_to_pdf(log_to_stdout: false) diff --git a/test/models/tii_user_accept_eula_test.rb b/test/models/tii_user_accept_eula_test.rb index df11250a4..0d131da78 100644 --- a/test/models/tii_user_accept_eula_test.rb +++ b/test/models/tii_user_accept_eula_test.rb @@ -4,6 +4,7 @@ class TiiUserAcceptEulaTest < ActiveSupport::TestCase include TestHelpers::TiiTestHelper def test_can_accept_tii_eula + setup_tii_features_enabled setup_tii_eula assert TurnItIn.eula_version.present? @@ -36,6 +37,7 @@ def test_can_accept_tii_eula def test_eula_accept_will_retry TiiAction.destroy_all + setup_tii_features_enabled setup_tii_eula user = FactoryBot.create(:user) @@ -102,6 +104,7 @@ def test_eula_accept_will_retry end def test_eula_accept_rate_limit + setup_tii_features_enabled setup_tii_eula # Prepare stub for call when eula is accepted and it fails @@ -137,6 +140,7 @@ def test_eula_accept_rate_limit end def test_eula_respects_global_errors + setup_tii_features_enabled setup_tii_eula # Prepare stub for call when eula is accepted and it fails diff --git a/test/sidekiq/tii_check_progress_job_test.rb b/test/sidekiq/tii_check_progress_job_test.rb index f030a98da..719129843 100644 --- a/test/sidekiq/tii_check_progress_job_test.rb +++ b/test/sidekiq/tii_check_progress_job_test.rb @@ -6,7 +6,7 @@ class TiiCheckProgressJobTest < ActiveSupport::TestCase def test_check_eula_change TiiAction.delete_all - + setup_tii_features_enabled setup_tii_eula # Create a task definition with two attachments @@ -217,6 +217,7 @@ def test_that_progress_checks_eula_change def test_waits_to_process_action setup_tii_eula + setup_tii_features_enabled # Will test with user eula user = FactoryBot.create(:user) From 908c803f15a34b4eabdafbec876f11dcfa642d1f Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 22 Jul 2024 21:06:53 +1000 Subject: [PATCH 094/124] chore(release): 8.0.17 --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 382f1c98e..4f25f2983 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.17](https://github.com/macite/doubtfire-deploy/compare/v8.0.16...v8.0.17) (2024-07-22) + ### [8.0.16](https://github.com/macite/doubtfire-deploy/compare/v8.0.15...v8.0.16) (2024-07-22) From 752f26e926b8ab7d4eb5ccf0b3fb35a9e42e0d68 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 24 Jul 2024 21:57:31 +1000 Subject: [PATCH 095/124] test: groups can be locked --- test/api/groups_api_test.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/api/groups_api_test.rb b/test/api/groups_api_test.rb index af200a9af..9c7138951 100644 --- a/test/api/groups_api_test.rb +++ b/test/api/groups_api_test.rb @@ -436,4 +436,27 @@ def test_group_switch_tutorial_unenrolled_students refute group1.at_capacity? # they are not in the right tutorial assert_equal 1, group1.projects.count end + + def test_locked_groups + unit = FactoryBot.create :unit, group_sets: 1, groups: [{gs: 0, students: 0}], task_count: 0 + + gs = unit.group_sets.first + group1 = gs.groups.first + + p1 = group1.tutorial.projects.first + p2 = group1.tutorial.projects.last + + group1.add_member p1 + group1.add_member p2 + + group1.update(locked: true) + + add_auth_header_for(user: p1.user) + delete "/api/units/#{unit.id}/group_sets/#{gs.id}/groups/#{group1.id}/members/#{p1.id}" + + assert_equal 403, last_response.status + + post "/api/units/#{unit.id}/group_sets/#{gs.id}/groups/#{group1.id}/members/#{unit.active_projects.last.id}" + assert_equal 403, last_response.status + end end From 7e9adaa50b8db70fb488ae3a489ad521dac5e28a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 25 Jul 2024 15:30:13 +1000 Subject: [PATCH 096/124] feat: add ability to manually remove webhooks from rails console --- .../turn_it_in/tii_action_register_webhook.rb | 16 +++++++ test/sidekiq/tii_webhooks_job_test.rb | 47 ++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/app/models/turn_it_in/tii_action_register_webhook.rb b/app/models/turn_it_in/tii_action_register_webhook.rb index f1b2e70ae..2cd008c8f 100644 --- a/app/models/turn_it_in/tii_action_register_webhook.rb +++ b/app/models/turn_it_in/tii_action_register_webhook.rb @@ -6,6 +6,22 @@ def description "Register webhooks" end + def remove_webhooks + # Get all webhooks + webhooks = list_all_webhooks + + # Delete each of the webhooks + webhooks.each do |webhook| + exec_tca_call 'delete webhook' do + TCAClient::WebhookApi.new.delete_webhook( + TurnItIn.x_turnitin_integration_name, + TurnItIn.x_turnitin_integration_version, + webhook.id + ) + end + end + end + private def run diff --git a/test/sidekiq/tii_webhooks_job_test.rb b/test/sidekiq/tii_webhooks_job_test.rb index e431676ca..615177b3a 100644 --- a/test/sidekiq/tii_webhooks_job_test.rb +++ b/test/sidekiq/tii_webhooks_job_test.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'test_helper' -class TiiCWebhooksJobTest < ActiveSupport::TestCase +class TiiWebhooksJobTest < ActiveSupport::TestCase include TestHelpers::TiiTestHelper def test_register_webhooks @@ -113,4 +113,49 @@ def test_do_not_register_if_registered assert_requested list_webhooks_stub, times: 1 assert_requested register_webhooks_stub, times: 0 end + + def test_can_remove_webhooks + # Will ask for current webhooks + list_webhooks_stub = stub_request(:get, "https://#{ENV['TCA_HOST']}/api/v1/webhooks"). + with(tii_headers). + to_return( + status: 200, + body: [ + TCAClient::Webhook.new( + "id" => "f5d62573-277d-4725-b557-c64877ddf6c7", + "url" => "https://myschool.sweetlms.com/turnitin-callbacks", + "description" => "my first webhook", + "created_time" => "2017-10-20T13:39:53.816Z", + "event_types" => [ + "SUBMISSION_COMPLETE" + ] + ), + TCAClient::Webhook.new( + "id" => "another-id", + "url" => TurnItIn.webhook_url, + "description" => "my second webhook", + "created_time" => "2017-10-20T13:39:53.816Z", + "event_types" => [ + "SUBMISSION_COMPLETE" + ] + ) + ].to_json, + headers: {} + ) + + delete_webhook_1_stub = stub_request(:delete, "https://#{ENV['TCA_HOST']}/api/v1/webhooks/f5d62573-277d-4725-b557-c64877ddf6c7") + .with(tii_headers) + .to_return(status: 200, body: "", headers: {}) + + delete_webhook_2_stub = stub_request(:delete, "https://#{ENV['TCA_HOST']}/api/v1/webhooks/another-id") + .with(tii_headers) + .to_return(status: 200, body: "", headers: {}) + + action = TiiActionRegisterWebhook.last || TiiActionRegisterWebhook.create + action.remove_webhooks + + assert_requested list_webhooks_stub, times: 1 + assert_requested delete_webhook_1_stub, times: 1 + assert_requested delete_webhook_2_stub, times: 1 + end end From efa669273bc8aa56ecfced4d63ab0f9af4649273 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 25 Jul 2024 15:36:48 +1000 Subject: [PATCH 097/124] fix: ensure tii signing secret is sent as a base64 string --- .../turn_it_in/tii_action_register_webhook.rb | 2 +- test/sidekiq/tii_webhooks_job_test.rb | 32 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/app/models/turn_it_in/tii_action_register_webhook.rb b/app/models/turn_it_in/tii_action_register_webhook.rb index 2cd008c8f..9a78c813a 100644 --- a/app/models/turn_it_in/tii_action_register_webhook.rb +++ b/app/models/turn_it_in/tii_action_register_webhook.rb @@ -44,7 +44,7 @@ def need_to_register_webhook? def register_webhook data = TCAClient::WebhookWithSecret.new( - signing_secret: ENV.fetch('TCA_SIGNING_KEY', nil), + signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)), url: TurnItIn.webhook_url, event_types: %w[ SIMILARITY_COMPLETE diff --git a/test/sidekiq/tii_webhooks_job_test.rb b/test/sidekiq/tii_webhooks_job_test.rb index 615177b3a..23aeaae0d 100644 --- a/test/sidekiq/tii_webhooks_job_test.rb +++ b/test/sidekiq/tii_webhooks_job_test.rb @@ -35,22 +35,22 @@ def test_register_webhooks headers: {}) # and will register the webhooks - register_webhooks_stub = stub_request(:post, "https://#{ENV['TCA_HOST']}/api/v1/webhooks"). - with(tii_headers). - with( - body: TCAClient::WebhookWithSecret.new( - signing_secret: ENV.fetch('TCA_SIGNING_KEY', nil), - url: TurnItIn.webhook_url, - event_types: [ - 'SIMILARITY_COMPLETE', - 'SUBMISSION_COMPLETE', - 'SIMILARITY_UPDATED', - 'PDF_STATUS', - 'GROUP_ATTACHMENT_COMPLETE' - ] - ).to_json, - ). - to_return(status: 200, body: "", headers: {}) + register_webhooks_stub = stub_request(:post, "https://#{ENV['TCA_HOST']}/api/v1/webhooks") + .with(tii_headers) + .with( + body: TCAClient::WebhookWithSecret.new( + signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)), + url: TurnItIn.webhook_url, + event_types: [ + 'SIMILARITY_COMPLETE', + 'SUBMISSION_COMPLETE', + 'SIMILARITY_UPDATED', + 'PDF_STATUS', + 'GROUP_ATTACHMENT_COMPLETE' + ] + ).to_json + ) + .to_return(status: 200, body: "", headers: {}) job = TiiRegisterWebHookJob.new job.perform From 547dbb9fd105b460df305885472c9557666edba1 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 25 Jul 2024 15:37:18 +1000 Subject: [PATCH 098/124] chore(release): 8.0.18 --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f25f2983..5ab58fe42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.18](https://github.com/macite/doubtfire-deploy/compare/v8.0.17...v8.0.18) (2024-07-25) + + +### Features + +* add ability to manually remove webhooks from rails console ([7e9adaa](https://github.com/macite/doubtfire-deploy/commit/7e9adaa50b8db70fb488ae3a489ad521dac5e28a)) + + +### Bug Fixes + +* ensure tii signing secret is sent as a base64 string ([efa6692](https://github.com/macite/doubtfire-deploy/commit/efa669273bc8aa56ecfced4d63ab0f9af4649273)) + ### [8.0.17](https://github.com/macite/doubtfire-deploy/compare/v8.0.16...v8.0.17) (2024-07-22) ### [8.0.16](https://github.com/macite/doubtfire-deploy/compare/v8.0.15...v8.0.16) (2024-07-22) From d84856b8e90126e34cb34e4d405acc462af7e147 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 10:26:22 +1000 Subject: [PATCH 099/124] fix: remove newlines from signing key base64 encoding --- app/models/turn_it_in/tii_action_register_webhook.rb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/models/turn_it_in/tii_action_register_webhook.rb b/app/models/turn_it_in/tii_action_register_webhook.rb index 9a78c813a..8b88cf2f0 100644 --- a/app/models/turn_it_in/tii_action_register_webhook.rb +++ b/app/models/turn_it_in/tii_action_register_webhook.rb @@ -22,8 +22,6 @@ def remove_webhooks end end - private - def run register_webhook if TurnItIn.register_webhooks? && need_to_register_webhook? self.complete = true @@ -43,8 +41,10 @@ def need_to_register_webhook? end def register_webhook + raise "TCA_SIGNING_KEY is not set" if data.signing_secret.nil? + data = TCAClient::WebhookWithSecret.new( - signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)), + signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)).tr("\n", ''), url: TurnItIn.webhook_url, event_types: %w[ SIMILARITY_COMPLETE @@ -55,8 +55,6 @@ def register_webhook ] ) # WebhookWithSecret | - raise "TCA_SIGNING_KEY is not set" if data.signing_secret.nil? - exec_tca_call 'register webhook' do TCAClient::WebhookApi.new.webhooks_post( TurnItIn.x_turnitin_integration_name, From b047e4ce0aeec2063c131c9a15eb379cf12ee03a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 10:27:30 +1000 Subject: [PATCH 100/124] chore: update log level for tii hook debug --- app/api/tii/turn_it_in_hooks_api.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/api/tii/turn_it_in_hooks_api.rb b/app/api/tii/turn_it_in_hooks_api.rb index 99e2a512b..8a039bf4d 100644 --- a/app/api/tii/turn_it_in_hooks_api.rb +++ b/app/api/tii/turn_it_in_hooks_api.rb @@ -21,11 +21,11 @@ class TurnItInHooksApi < Grape::API data = JSON.parse(raw_data) digest = OpenSSL::Digest.new('sha256') - logger.info("TII_HOOK_DEBUG:#{raw_data}") + logger.debug("TII_HOOK_DEBUG:#{raw_data}") hmac = OpenSSL::HMAC.hexdigest(digest, ENV.fetch('TCA_SIGNING_KEY', nil), raw_data) - logger.info("TII_HOOK_DEBUG:#{hmac}") - logger.info("TII_HOOK_DEBUG:#{headers['x-turnitin-signature']}") + logger.debug("TII_HOOK_DEBUG:#{hmac}") + logger.debug("TII_HOOK_DEBUG:#{headers['x-turnitin-signature']}") if hmac != headers["x-turnitin-signature"] logger.error("TII: HMAC does not match") From 166a0ad9e8bea340c0775bc17024929d9fb872a6 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 16:04:02 +1000 Subject: [PATCH 101/124] quality: add tests for filename in task definitions --- app/models/task_definition.rb | 20 +++++ test/models/task_definition_test.rb | 124 +++++++++++++++++++++++++++- 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/app/models/task_definition.rb b/app/models/task_definition.rb index 393f6d272..1ad772611 100644 --- a/app/models/task_definition.rb +++ b/app/models/task_definition.rb @@ -176,6 +176,26 @@ def check_upload_requirements_format errors.add(:upload_requirements, "has additional values for item #{i + 1} --> #{req.keys.join(' ')}.") end + # Check the name matches a valid filename format + unless req['name'].match?(/^[a-zA-Z0-9_\- \.]+$/) + errors.add(:upload_requirements, "the name for item #{i + 1} does not seem to be a valid filename --> #{req['name']}.") + end + + # Check the type is either document or image or code + unless %w(document image code).include? req['type'] + errors.add(:upload_requirements, "the type for item #{i + 1} is not valid --> #{req['type']}.") + end + + # Check that tii check is a boolean + unless req['tii_check'].blank? || [true, false].include?(req['tii_check']) + errors.add(:upload_requirements, "the tii_check for item #{i + 1} is not a boolean --> #{req['tii_check']}.") + end + + # Check that tii_pct is a non-negative number + unless req['tii_pct'].blank? || (req['tii_pct'].is_a?(Numeric) && req['tii_pct'] >= 0) + errors.add(:upload_requirements, "the tii_pct for item #{i + 1} is not a non-negative number --> #{req['tii_pct']}.") + end + i += 1 end end diff --git a/test/models/task_definition_test.rb b/test/models/task_definition_test.rb index 0ff812661..578b0e895 100644 --- a/test/models/task_definition_test.rb +++ b/test/models/task_definition_test.rb @@ -266,8 +266,130 @@ def test_delete_unneeded_group_submission_on_group_set_change t1.reload assert_nil t1.group_submission - + ensure unit.destroy end + def test_upload_req_format + u = FactoryBot.create :unit, task_count: 0, with_students: false + td = FactoryBot.create :task_definition, unit: u, upload_requirements: [], start_date: Time.zone.now + 1.day + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document', + "tii_check" => true, + "tii_pct" => 5 + } + ] + assert td.valid? + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document' + } + ] + assert td.valid?, 'tii check and pct not required' + + td.upload_requirements = + [ + { + "name" => 'Document 1', + "type" => 'document', + "tii_check" => true, + "tii_pct" => 5 + } + ] + + assert_not td.valid?, 'missing key' + + td.upload_requirements = + [ + { + "key" => 'file0', + "type" => 'document', + "tii_check" => true, + "tii_pct" => 5 + } + ] + assert_not td.valid?, 'missing name' + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "tii_check" => true, + "tii_pct" => 5 + } + ] + assert_not td.valid?, 'missing type' + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document', + "other" => true, + "tii_pct" => 5 + } + ] + assert_not td.valid?, 'unknown key' + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'other', + "tii_check" => true, + "tii_pct" => 5 + } + ] + assert_not td.valid?, 'unknown type' + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document', + "tii_check" => 'test', + "tii_pct" => 5 + } + ] + assert_not td.valid?, 'tii_check not boolean' + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document', + "tii_check" => true, + "tii_pct" => 'test' + } + ] + assert_not td.valid?, 'tii_pct not integer' + + td.upload_requirements = + [ + { + "key" => 'file0', + "name" => "\tnot a filename", + "type" => 'document', + "tii_check" => true, + "tii_pct" => 5 + } + ] + assert_not td.valid?, 'name not valid filename' + ensure + u.destroy + end end From cea12e5bee7ba7b954bdeff1c5257d2c9c9a841a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 17:18:30 +1000 Subject: [PATCH 102/124] fix: ensure accept submission checks number of files --- app/models/task.rb | 5 ++ test/models/task_test.rb | 119 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/app/models/task.rb b/app/models/task.rb index f174a426a..6f8236739 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1210,6 +1210,11 @@ def create_alignments_from_submission(alignments) # Checks to make sure that the files match what we expect # def accept_submission(current_user, files, _student, ui, contributions, trigger, alignments, accepted_tii_eula: false) + # Ensure all of the files are present + if files.nil? || files.length != task_definition.number_of_uploaded_files + ui.error!({ 'error' => 'Some files are missing from the submission upload' }, 403) + end + # # Ensure that each file in files has the following attributes: # id, name, filename, type, tempfile diff --git a/test/models/task_test.rb b/test/models/task_test.rb index 877ee3fca..39817ef5d 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -10,6 +10,10 @@ class TaskDefinitionTest < ActiveSupport::TestCase include TestHelpers::AuthHelper include TestHelpers::JsonHelper + def error! msg + raise msg + end + def app Rails.application end @@ -747,4 +751,119 @@ def test_pdf_creation_fails_on_invalid_pdf unit.destroy! end end + + def test_accept_files_checks_they_all_exist + project = FactoryBot.create(:project) + unit = project.unit + user = project.student + convenor = unit.main_convenor_user + task_definition = unit.task_definitions.first + + task_definition.upload_requirements = [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document' + }, + { + "key" => 'file1', + "name" => 'Document 2', + "type" => 'document' + }, + { + "key" => 'file2', + "name" => 'Code 1', + "type" => 'code' + }, + { + "key" => 'file3', + "name" => 'Document 3', + "type" => 'document' + }, + { + "key" => 'file4', + "name" => 'Document 4', + "type" => 'document' + } + ] + + # Saving task def + task_definition.save! + + # Test that the task def is setup correctly + assert_equal 5, task_definition.number_of_uploaded_files + + # Now... lets upload a submission + task = project.task_for_task_definition(task_definition) + + # Create a submission - but no files! + begin + task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil + assert false, 'Should have raised an error with no files submitted' + rescue StandardError => e + assert_equal :not_started, task.status + end + + # Create a submission + task.accept_submission user, [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + }, + { + id: 'file1', + name: 'Document 2', + type: 'document', + filename: 'file1.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + }, + { + id: 'file2', + name: 'Code 1', + type: 'code', + filename: 'code.cs', + "tempfile" => File.new(test_file_path('submissions/program.cs')) + }, + { + id: 'file3', + name: 'Document 3', + type: 'document', + filename: 'file3.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + }, + { + id: 'file4', + name: 'Document 4', + type: 'document', + filename: 'file4.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], user, self, nil, 'ready_for_feedback', nil, accepted_tii_eula: true + + assert_equal :ready_for_feedback, task.status + + task_definition.upload_requirements = [] + task_definition.save! + + task.task_status = TaskStatus.not_started + task.save! + + # Now... lets upload a submission with no files + task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil + assert_equal :ready_for_feedback, task.status + + task.task_status = TaskStatus.not_started + task.save! + + # Now... lets upload a submission with too many files + begin + task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil + assert false, 'Should have raised an error with too many files submitted' + rescue StandardError => e + assert_equal :not_started, task.status + end + end end From edcd36a01251b14aa3e9d7fd8f105589bdebfc65 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 17:21:00 +1000 Subject: [PATCH 103/124] chore(release): 8.0.19 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5ab58fe42..b3c041141 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.19](https://github.com/macite/doubtfire-deploy/compare/v8.0.18...v8.0.19) (2024-07-26) + + +### Bug Fixes + +* ensure accept submission checks number of files ([cea12e5](https://github.com/macite/doubtfire-deploy/commit/cea12e5bee7ba7b954bdeff1c5257d2c9c9a841a)) +* remove newlines from signing key base64 encoding ([d84856b](https://github.com/macite/doubtfire-deploy/commit/d84856b8e90126e34cb34e4d405acc462af7e147)) + ### [8.0.18](https://github.com/macite/doubtfire-deploy/compare/v8.0.17...v8.0.18) (2024-07-25) From 527b810525a106ae155235ba03d4517f51c25998 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 17:37:33 +1000 Subject: [PATCH 104/124] test: fix tests to conform to new validations --- test/api/tii/tii_action_api_test.rb | 23 +++++++++++++-------- test/models/task_test.rb | 2 +- test/sidekiq/tii_check_progress_job_test.rb | 8 +++---- test/sidekiq/tii_webhooks_job_test.rb | 2 +- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/test/api/tii/tii_action_api_test.rb b/test/api/tii/tii_action_api_test.rb index 50d6b1f1e..8a34265e9 100644 --- a/test/api/tii/tii_action_api_test.rb +++ b/test/api/tii/tii_action_api_test.rb @@ -21,15 +21,20 @@ def app # Create a task definition with two attachments @unit = FactoryBot.create(:unit, with_students: false, task_count: 0) - @task_def = FactoryBot.create(:task_definition, unit: @unit, upload_requirements: [ - { - 'key' => 'file0', - 'name' => 'My document', - 'type' => 'document', - 'tii_check' => 'true', - 'tii_pct' => '10' - } - ]) + @task_def = FactoryBot.create( + :task_definition, + unit: @unit, + upload_requirements: + [ + { + 'key' => 'file0', + 'name' => 'My document', + 'type' => 'document', + 'tii_check' => true, + 'tii_pct' => 10 + } + ] + ) ga1 = TiiGroupAttachment.create( task_definition: @task_def, diff --git a/test/models/task_test.rb b/test/models/task_test.rb index 39817ef5d..9ad27e924 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -10,7 +10,7 @@ class TaskDefinitionTest < ActiveSupport::TestCase include TestHelpers::AuthHelper include TestHelpers::JsonHelper - def error! msg + def error! msg, code raise msg end diff --git a/test/sidekiq/tii_check_progress_job_test.rb b/test/sidekiq/tii_check_progress_job_test.rb index 719129843..ed200c20a 100644 --- a/test/sidekiq/tii_check_progress_job_test.rb +++ b/test/sidekiq/tii_check_progress_job_test.rb @@ -17,8 +17,8 @@ def test_check_eula_change 'key' => 'file0', 'name' => 'My document', 'type' => 'document', - 'tii_check' => 'true', - 'tii_pct' => '10' + 'tii_check' => true, + 'tii_pct' => 10 } ]) @@ -150,8 +150,8 @@ def test_that_progress_checks_eula_change 'key' => 'file0', 'name' => 'My document', 'type' => 'document', - 'tii_check' => 'true', - 'tii_pct' => '10' + 'tii_check' => true, + 'tii_pct' => 10 } ]) diff --git a/test/sidekiq/tii_webhooks_job_test.rb b/test/sidekiq/tii_webhooks_job_test.rb index 23aeaae0d..08fbe9dd4 100644 --- a/test/sidekiq/tii_webhooks_job_test.rb +++ b/test/sidekiq/tii_webhooks_job_test.rb @@ -39,7 +39,7 @@ def test_register_webhooks .with(tii_headers) .with( body: TCAClient::WebhookWithSecret.new( - signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)), + signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)).tr("\n", '' ), url: TurnItIn.webhook_url, event_types: [ 'SIMILARITY_COMPLETE', From 70f095c3bb762b73738344f6902cfd53e11daf0b Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 26 Jul 2024 17:57:24 +1000 Subject: [PATCH 105/124] fix: webhook registration key check --- app/models/turn_it_in/tii_action_register_webhook.rb | 5 +++-- test/models/task_test.rb | 12 +++++++++++- test/sidekiq/tii_webhooks_job_test.rb | 10 ++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/app/models/turn_it_in/tii_action_register_webhook.rb b/app/models/turn_it_in/tii_action_register_webhook.rb index 8b88cf2f0..e897eaabb 100644 --- a/app/models/turn_it_in/tii_action_register_webhook.rb +++ b/app/models/turn_it_in/tii_action_register_webhook.rb @@ -41,10 +41,11 @@ def need_to_register_webhook? end def register_webhook - raise "TCA_SIGNING_KEY is not set" if data.signing_secret.nil? + key = ENV.fetch('TCA_SIGNING_KEY', nil) + raise "TCA_SIGNING_KEY is not set" if key.nil? data = TCAClient::WebhookWithSecret.new( - signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)).tr("\n", ''), + signing_secret: Base64.encode64(key).tr("\n", ''), url: TurnItIn.webhook_url, event_types: %w[ SIMILARITY_COMPLETE diff --git a/test/models/task_test.rb b/test/models/task_test.rb index 9ad27e924..c20f32fb2 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -850,6 +850,7 @@ def test_accept_files_checks_they_all_exist task.task_status = TaskStatus.not_started task.save! + task.reload # Now... lets upload a submission with no files task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil @@ -860,7 +861,16 @@ def test_accept_files_checks_they_all_exist # Now... lets upload a submission with too many files begin - task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil + task.accept_submission user, + [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], user, self, nil, 'ready_for_feedback', nil assert false, 'Should have raised an error with too many files submitted' rescue StandardError => e assert_equal :not_started, task.status diff --git a/test/sidekiq/tii_webhooks_job_test.rb b/test/sidekiq/tii_webhooks_job_test.rb index 08fbe9dd4..2381029ca 100644 --- a/test/sidekiq/tii_webhooks_job_test.rb +++ b/test/sidekiq/tii_webhooks_job_test.rb @@ -5,6 +5,9 @@ class TiiWebhooksJobTest < ActiveSupport::TestCase include TestHelpers::TiiTestHelper def test_register_webhooks + setup_tii_eula + setup_tii_features_enabled + Doubtfire::Application.config.tii_register_webhook = true # Will ask for current webhooks @@ -32,14 +35,17 @@ def test_register_webhooks ] ) ].to_json, - headers: {}) + headers: {} + ) + + ENV['TCA_SIGNING_KEY'] = 'TESTING' # and will register the webhooks register_webhooks_stub = stub_request(:post, "https://#{ENV['TCA_HOST']}/api/v1/webhooks") .with(tii_headers) .with( body: TCAClient::WebhookWithSecret.new( - signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)).tr("\n", '' ), + signing_secret: Base64.encode64(ENV.fetch('TCA_SIGNING_KEY', nil)).tr("\n", ''), url: TurnItIn.webhook_url, event_types: [ 'SIMILARITY_COMPLETE', From 875b831100b542fc6e3686571167af67e6a5d518 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 30 Jul 2024 09:29:47 +1000 Subject: [PATCH 106/124] chore(release): 8.0.20 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c041141..844d28019 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.20](https://github.com/macite/doubtfire-deploy/compare/v8.0.19...v8.0.20) (2024-07-29) + + +### Bug Fixes + +* webhook registration key check ([70f095c](https://github.com/macite/doubtfire-deploy/commit/70f095c3bb762b73738344f6902cfd53e11daf0b)) + ### [8.0.19](https://github.com/macite/doubtfire-deploy/compare/v8.0.18...v8.0.19) (2024-07-26) From 6753d803a573c3ced9fb58ef202486cc69d3329c Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 30 Jul 2024 19:26:02 +1000 Subject: [PATCH 107/124] fix: delay pdf generation to ensure sufficient time for async task to run --- app/models/portfolio_evidence.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/portfolio_evidence.rb b/app/models/portfolio_evidence.rb index e5a39e80a..65d1d481b 100644 --- a/app/models/portfolio_evidence.rb +++ b/app/models/portfolio_evidence.rb @@ -22,7 +22,7 @@ def self.move_to_pid_folder pid_folder = File.join(student_work_dir(:in_process), "pid_#{Process.pid}") # Move everything in "new" to "pid" folder but retain the old "new" folder - FileHelper.move_files(student_work_dir(:new), pid_folder, true, DateTime.now - 1.minute) + FileHelper.move_files(student_work_dir(:new), pid_folder, true, DateTime.now - 30.minutes) pid_folder end From 3a4eb51bdf5a96e4039d67e4a621f44edbf2b8ee Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 30 Jul 2024 19:58:44 +1000 Subject: [PATCH 108/124] chore(release): 8.0.21 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 844d28019..0858edbfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.21](https://github.com/macite/doubtfire-deploy/compare/v8.0.20...v8.0.21) (2024-07-30) + + +### Bug Fixes + +* delay pdf generation to ensure sufficient time for async task to run ([6753d80](https://github.com/macite/doubtfire-deploy/commit/6753d803a573c3ced9fb58ef202486cc69d3329c)) + ### [8.0.20](https://github.com/macite/doubtfire-deploy/compare/v8.0.19...v8.0.20) (2024-07-29) From 7dfd54798fc6d00512851a06999d86b750c0bbd9 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 22:24:52 +1000 Subject: [PATCH 109/124] test: task pdf download --- test/api/tasks_api_test.rb | 52 +++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/test/api/tasks_api_test.rb b/test/api/tasks_api_test.rb index 7ef684fca..bcb9dcf85 100644 --- a/test/api/tasks_api_test.rb +++ b/test/api/tasks_api_test.rb @@ -403,8 +403,58 @@ def test_can_submit_ipynb task.convert_submission_to_pdf(log_to_stdout: false) assert File.exist? task.final_pdf_path - td.destroy + unit.destroy end + def test_download_task_pdf + unit = FactoryBot.create(:unit, student_count: 1, task_count: 0) + td = TaskDefinition.create!({ + unit_id: unit.id, + tutorial_stream: unit.tutorial_streams.first, + name: 'Code task', + description: 'Code task', + weighting: 4, + target_grade: 0, + start_date: Time.zone.now - 2.weeks, + target_date: Time.zone.now + 1.week, + abbreviation: 'CodeTask', + restrict_status_updates: false, + upload_requirements: [ { "key" => 'file0', "name" => 'Shape Class', "type" => 'code' } ], + plagiarism_warn_pct: 0.8, + is_graded: true, + max_quality_pts: 0 + }) + + project = unit.active_projects.first + task = project.task_for_task_definition(td) + + # Add username and auth_token to Header + add_auth_header_for(user: project.user) + + get "/api/projects/#{project.id}/task_def_id/#{td.id}/submission" + + assert_equal 200, last_response.status + assert_equal File.size(Rails.root.join('public/resources/FileNotFound.pdf')), last_response.length + dir = FileHelper.student_work_dir(:new, task, true) + + get "/api/projects/#{project.id}/task_def_id/#{td.id}/submission" + + assert_equal 200, last_response.status + assert_equal File.size(Rails.root.join('public/resources/AwaitingProcessing.pdf')), last_response.length + + FileUtils.rm_r dir + + src_file = Rails.root.join('test_files/submissions/1.2P.pdf') + FileUtils.cp src_file, task.final_pdf_path + task.portfolio_evidence_path = task.final_pdf_path + task.save + + get "/api/projects/#{project.id}/task_def_id/#{td.id}/submission" + + assert_equal 200, last_response.status + assert_equal File.size(src_file), last_response.length + + unit.destroy + end end From 33ee3cecd6e8317cd54f51c4e1e4314725b5085c Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 22:58:48 +1000 Subject: [PATCH 110/124] fix: ensure scoop files checks files are a hash --- app/api/submission/generate_helpers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/api/submission/generate_helpers.rb b/app/api/submission/generate_helpers.rb index 073881339..1d74ac443 100644 --- a/app/api/submission/generate_helpers.rb +++ b/app/api/submission/generate_helpers.rb @@ -14,7 +14,7 @@ def scoop_files(params, upload_reqs) # upload_reqs.each do |detail| key = detail['key'] - next unless files.key? key + next unless files.key?(key) && files[key].is_a?(Hash) files[key][:id] = files[key]['name'] files[key][:name] = detail['name'] From 3e0a1bac485322b6f7936fd3c244cdc5594ca9b1 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 22:59:10 +1000 Subject: [PATCH 111/124] fix: add awaiting processing pdf --- public/resources/AwaitingProcessing.pdf | Bin 0 -> 16352 bytes public/resources/FileNotFound.pdf | Bin 27985 -> 15946 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 public/resources/AwaitingProcessing.pdf diff --git a/public/resources/AwaitingProcessing.pdf b/public/resources/AwaitingProcessing.pdf new file mode 100644 index 0000000000000000000000000000000000000000..be6c7c8a2c30e5a081fcbaf32b3d8c92c71d8f7d GIT binary patch literal 16352 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 literal 0 HcmV?d00001 diff --git a/public/resources/FileNotFound.pdf b/public/resources/FileNotFound.pdf index 12eb714db3c1ba6de2d67b65f6ea11ebc194cb30..2a2bfa421169b8d6627051a4409f8ce1d6ae6aeb 100644 GIT binary patch delta 12712 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 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 MQdM1TWN9q)ZyVj!6#xJL From e3d36c27cffbeb8e56dc6c2b085665c5d91cd9ce Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 23:01:10 +1000 Subject: [PATCH 112/124] fix: only try overseer assessment when overseer enabled --- app/api/submission/portfolio_evidence_api.rb | 26 +++++++++----------- app/models/overseer_assessment.rb | 5 +--- app/models/task.rb | 7 ++++++ 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/app/api/submission/portfolio_evidence_api.rb b/app/api/submission/portfolio_evidence_api.rb index 63b6ddabb..b180261dc 100644 --- a/app/api/submission/portfolio_evidence_api.rb +++ b/app/api/submission/portfolio_evidence_api.rb @@ -53,23 +53,21 @@ def self.logger # Copy files to be PDFed task.accept_submission(current_user, scoop_files(params, upload_reqs), student, self, params[:contributions], trigger, alignments, accepted_tii_eula: params[:accepted_tii_eula]) - overseer_assessment = OverseerAssessment.create_for(task) - if overseer_assessment.present? - logger.info "Launching Overseer assessment for task_def_id: #{task_definition.id} task_id: #{task.id}" - - response = overseer_assessment.send_to_overseer - - if response[:error].present? - error!({ error: response[:error] }, 403) + if task.overseer_enabled? + overseer_assessment = OverseerAssessment.create_for(task) + if overseer_assessment.present? + logger.info "Launching Overseer assessment for task_def_id: #{task_definition.id} task_id: #{task.id}" + + response = overseer_assessment.send_to_overseer + + if response[:error].present? + error!({ error: response[:error] }, 403) + end + else + logger.info "Overseer assessment for task_def_id: #{task_definition.id} task_id: #{task.id} was not performed" end - - present :updated_task, task, with: Entities::TaskEntity, update_only: true - present :comment, response[:comment].serialize(current_user), with: Grape::Presenters::Presenter - return end - logger.info "Overseer assessment for task_def_id: #{task_definition.id} task_id: #{task.id} was not performed" - present task, with: Entities::TaskEntity, update_only: true end # post diff --git a/app/models/overseer_assessment.rb b/app/models/overseer_assessment.rb index 179ac6ccc..afca988ad 100644 --- a/app/models/overseer_assessment.rb +++ b/app/models/overseer_assessment.rb @@ -26,10 +26,7 @@ def self.create_for(task) task_definition = task.task_definition unit = task_definition.unit - return nil unless unit.assessment_enabled - return nil unless task_definition.assessment_enabled - return nil unless task_definition.has_task_assessment_resources? - return nil unless task.has_new_files? || task.has_done_file? + return nil unless task.overseer_enabled? docker_image_name_tag = task_definition.docker_image_name_tag || unit.docker_image_name_tag assessment_resources_path = task_definition.task_assessment_resources diff --git a/app/models/task.rb b/app/models/task.rb index 6f8236739..a943b9535 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -1373,6 +1373,13 @@ def archive_submission FileUtils.rm_f(portfolio_evidence_path) if has_pdf end + def overseer_enabled? + return unit.assessment_enabled && + task_definition.assessment_enabled && + task_definition.has_task_assessment_resources? && + (has_new_files? || has_done_file?) + end + private def delete_associated_files From 218afb9291b6864c3ede03b4f74bceaef81b339f Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 23:23:32 +1000 Subject: [PATCH 113/124] fix: change zip of new upload to avoid loss Issues occurred when new to done fails, but the zip is already gone. Add checks to avoid double processing, and delay delete of zip until the files are checked --- app/api/submission/portfolio_evidence_api.rb | 3 +- app/api/task_definitions_api.rb | 2 +- app/models/task.rb | 61 +++++-- test/models/task_test.rb | 163 ++++++++++++++++++- test/models/tii_model_test.rb | 2 +- 5 files changed, 208 insertions(+), 23 deletions(-) diff --git a/app/api/submission/portfolio_evidence_api.rb b/app/api/submission/portfolio_evidence_api.rb index b180261dc..bf9f700b1 100644 --- a/app/api/submission/portfolio_evidence_api.rb +++ b/app/api/submission/portfolio_evidence_api.rb @@ -48,10 +48,9 @@ def self.logger alignments = params[:alignment_data] upload_reqs = task.upload_requirements - student = task.project.student # Copy files to be PDFed - task.accept_submission(current_user, scoop_files(params, upload_reqs), student, self, params[:contributions], trigger, alignments, accepted_tii_eula: params[:accepted_tii_eula]) + task.accept_submission(current_user, scoop_files(params, upload_reqs), self, params[:contributions], trigger, alignments, accepted_tii_eula: params[:accepted_tii_eula]) if task.overseer_enabled? overseer_assessment = OverseerAssessment.create_for(task) diff --git a/app/api/task_definitions_api.rb b/app/api/task_definitions_api.rb index 18a7d1035..08edf62e5 100644 --- a/app/api/task_definitions_api.rb +++ b/app/api/task_definitions_api.rb @@ -297,7 +297,7 @@ class TaskDefinitionsApi < Grape::API upload_reqs = task.upload_requirements # Copy files to be PDFed - task.accept_submission(current_user, scoop_files(params, upload_reqs), current_user, self, nil, 'ready_for_feedback', nil, accepted_tii_eula: false) + task.accept_submission(current_user, scoop_files(params, upload_reqs), self, nil, 'ready_for_feedback', nil, accepted_tii_eula: false) logger.info '********* - about to perform overseer submission' overseer_assessment = OverseerAssessment.create_for(task) diff --git a/app/models/task.rb b/app/models/task.rb index a943b9535..8d5c69f75 100644 --- a/app/models/task.rb +++ b/app/models/task.rb @@ -227,7 +227,7 @@ def self.for_user(user) Task.joins(:project).where('projects.user_id = ?', user.id) end - def processing_pdf? + def folder_exists_in_new? if group_task? && group_submission File.exist? File.join(FileHelper.student_work_dir(:new), group_submission.submitter_task.id.to_s) else @@ -235,6 +235,18 @@ def processing_pdf? end end + def folder_exists_in_process? + if group_task? && group_submission + File.exist? File.join(FileHelper.student_work_dir(:in_process), group_submission.submitter_task.id.to_s) + else + File.exist? File.join(FileHelper.student_work_dir(:in_process), id.to_s) + end + end + + def processing_pdf? + folder_exists_in_new? || folder_exists_in_process? + end + # Get the raw extension date - with extensions representing weeks def raw_extension_date target_date + extensions.weeks @@ -832,12 +844,10 @@ def compress_new_to_done(task_dir: student_work_dir(:new, false), zip_file_path: zip_file = zip_file_path || zip_file_path_for_done_task return false if zip_file.nil? || (!Dir.exist? task_dir) - FileUtils.rm_f(zip_file) - - # compress image files + # compress image files - convert to jpg image_files = Dir.entries(task_dir).select { |f| (f =~ /^\d{3}.(image)/) == 0 } image_files.each do |img| - # Ensure all images in submissions are not jpg + # Ensure all images in submissions are jpg dest_file = "#{task_dir}#{File.basename(img, ".*")}.jpg" raise 'Failed to compress an image. Ensure all images are valid.' unless FileHelper.compress_image_to_dest("#{task_dir}#{img}", dest_file, true) @@ -845,9 +855,20 @@ def compress_new_to_done(task_dir: student_work_dir(:new, false), zip_file_path: FileUtils.rm("#{task_dir}#{img}") unless dest_file == "#{task_dir}#{img}" end - # copy all files into zip input_files = Dir.entries(task_dir).select { |f| (f =~ /^\d{3}.(cover|document|code|image)/) == 0 } + if input_files.length != task_definition.number_of_uploaded_files + logger.error "Error processing task #{log_details} - missing files expected #{task_definition.number_of_uploaded_files} got #{input_files.length}" + logger.error "Files found: #{input_files}" + return false + end + + logger.info "Creating new zip file for task #{id} in #{zip_file}" + + # We have what looks like a good submission, remove old zip + FileUtils.rm_f(zip_file) + + # copy all files into zip zip_dir = File.dirname(zip_file) FileUtils.mkdir_p zip_dir @@ -878,7 +899,7 @@ def copy_done_to(path) def clear_in_process in_process_dir = student_work_dir(:in_process, false) if Dir.exist? in_process_dir - Dir.chdir(FileUtils.student_work_dir) if FileUtils.pwd == in_process_dir + Dir.chdir(FileHelper.student_work_root) if FileUtils.pwd == in_process_dir FileUtils.rm_rf in_process_dir end end @@ -923,7 +944,10 @@ def move_files_to_in_process(source_folder = FileHelper.student_work_dir(:new)) from_dir = File.join(source_folder, id.to_s) + "/" if Dir.exist?(from_dir) # save new files in done folder - return false unless compress_new_to_done(task_dir: from_dir) + unless compress_new_to_done(task_dir: from_dir) + logger.error "Error processing task #{log_details} - failed to compress new files" + return false + end end # Get the zip file path... @@ -1079,7 +1103,12 @@ def final_pdf_path # Convert a submission to pdf - the source folder is the root folder in which the submission folder will be found (not the submission folder itself) def convert_submission_to_pdf(source_folder: FileHelper.student_work_dir(:new), log_to_stdout: true) - return false unless move_files_to_in_process(source_folder) + logger.info "Converting task #{self.id} to pdf" + + unless move_files_to_in_process(source_folder) + logger.error("Failed to move files for #{log_details} to in process") + return false + end begin tac = TaskAppController.new @@ -1134,6 +1163,8 @@ def convert_submission_to_pdf(source_folder: FileHelper.student_work_dir(:new), FileHelper.compress_pdf(portfolio_evidence_path) + logger.info("PDF created for task #{self.id}") + # if the task is the draft learning summary task if task_definition_id == unit.draft_task_definition_id # if there is a learning summary, execute, if there isn't and a learning summary exists, don't execute @@ -1143,14 +1174,13 @@ def convert_submission_to_pdf(source_folder: FileHelper.student_work_dir(:new), end save - - clear_in_process return true rescue => e - clear_in_process trigger_transition trigger: 'fix', by_user: project.tutor_for(task_definition) add_text_comment project.tutor_for(task_definition), "**Automated Comment**: Something went wrong with your submission. Check the files and resubmit this task. #{e.message}" raise e + ensure + clear_in_process end end @@ -1209,7 +1239,12 @@ def create_alignments_from_submission(alignments) # # Checks to make sure that the files match what we expect # - def accept_submission(current_user, files, _student, ui, contributions, trigger, alignments, accepted_tii_eula: false) + def accept_submission(current_user, files, ui, contributions, trigger, alignments, accepted_tii_eula: false) + # Ensure there is not a submission already in process + if processing_pdf? + ui.error!({ 'error' => 'A submission is already being processed. Please wait for the current submission process to complete.' }, 403) + end + # Ensure all of the files are present if files.nil? || files.length != task_definition.number_of_uploaded_files ui.error!({ 'error' => 'Some files are missing from the submission upload' }, 403) diff --git a/test/models/task_test.rb b/test/models/task_test.rb index c20f32fb2..212e75508 100644 --- a/test/models/task_test.rb +++ b/test/models/task_test.rb @@ -10,8 +10,13 @@ class TaskDefinitionTest < ActiveSupport::TestCase include TestHelpers::AuthHelper include TestHelpers::JsonHelper - def error! msg, code - raise msg + def error!(msg, _code) + raise StandardError, msg + end + + def clear_submission(task) + FileUtils.rm_rf(FileHelper.student_work_dir(:new, task, false)) + FileUtils.rm_rf(FileHelper.student_work_dir(:in_process, task, false)) end def app @@ -798,7 +803,7 @@ def test_accept_files_checks_they_all_exist # Create a submission - but no files! begin - task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil + task.accept_submission user, [], self, nil, 'ready_for_feedback', nil assert false, 'Should have raised an error with no files submitted' rescue StandardError => e assert_equal :not_started, task.status @@ -841,7 +846,7 @@ def test_accept_files_checks_they_all_exist filename: 'file4.pdf', "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) } - ], user, self, nil, 'ready_for_feedback', nil, accepted_tii_eula: true + ], self, nil, 'ready_for_feedback', nil, accepted_tii_eula: true assert_equal :ready_for_feedback, task.status @@ -852,8 +857,10 @@ def test_accept_files_checks_they_all_exist task.save! task.reload + clear_submission(task) + # Now... lets upload a submission with no files - task.accept_submission user, [], user, self, nil, 'ready_for_feedback', nil + task.accept_submission user, [], self, nil, 'ready_for_feedback', nil assert_equal :ready_for_feedback, task.status task.task_status = TaskStatus.not_started @@ -870,10 +877,154 @@ def test_accept_files_checks_they_all_exist filename: 'file0.pdf', "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) } - ], user, self, nil, 'ready_for_feedback', nil + ], self, nil, 'ready_for_feedback', nil assert false, 'Should have raised an error with too many files submitted' rescue StandardError => e assert_equal :not_started, task.status end end + + def test_cannot_upload_with_existing_upload_in_process + project = FactoryBot.create(:project) + unit = project.unit + user = project.student + convenor = unit.main_convenor_user + task_definition = unit.task_definitions.first + + task_definition.upload_requirements = [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document' + } + ] + + # Saving task def + task_definition.save! + + # Now... lets upload a submission + task = project.task_for_task_definition(task_definition) + + # Create a submission + task.accept_submission user, [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], self, nil, 'ready_for_feedback', nil, accepted_tii_eula: true + + assert_equal :ready_for_feedback, task.status + + # Now... try uploading again + begin + task.accept_submission user, + [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], self, nil, 'ready_for_feedback', nil + assert false, 'Should have raised an error with existing upload in process' + rescue StandardError => e + assert_includes e.message, 'A submission is already being processed. Please wait for the current submission process to complete.' + assert_equal :ready_for_feedback, task.status + end + + FileHelper.move_files(FileHelper.student_work_dir(:new, task, false), FileHelper.student_work_dir(:in_process, task, false), false) + + begin + task.accept_submission user, + [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], self, nil, 'ready_for_feedback', nil + assert false, 'Should have raised an error with existing upload in process' + rescue StandardError => e + assert_includes e.message, 'A submission is already being processed. Please wait for the current submission process to complete.' + assert_equal :ready_for_feedback, task.status + end + + FileUtils.rm_rf(FileHelper.student_work_dir(:in_process, task, false)) + + assert_not task.processing_pdf? + + # Create a submission + task.accept_submission user, [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], self, nil, 'ready_for_feedback', nil, accepted_tii_eula: true + + assert_equal :ready_for_feedback, task.status + ensure + unit.destroy + end + + def test_check_files_on_task_move + project = FactoryBot.create(:project) + unit = project.unit + user = project.student + convenor = unit.main_convenor_user + task_definition = unit.task_definitions.first + + task_definition.upload_requirements = [ + { + "key" => 'file0', + "name" => 'Document 1', + "type" => 'document' + } + ] + + # Saving task def + task_definition.save! + + # Now... lets upload a submission + task = project.task_for_task_definition(task_definition) + + # Create a submission + task.accept_submission user, [ + { + id: 'file0', + name: 'Document 1', + type: 'document', + filename: 'file0.pdf', + "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) + } + ], self, nil, 'ready_for_feedback', nil, accepted_tii_eula: true + + # Test that we can move to in process + assert task.move_files_to_in_process + assert_not File.exist? FileHelper.student_work_dir(:new, task, false) + assert File.exist? FileHelper.student_work_dir(:in_process, task, false) + + # Test that we can move back to new + FileHelper.move_files(FileHelper.student_work_dir(:in_process, task, false), FileHelper.student_work_dir(:new, task, false), false) + assert File.exist? FileHelper.student_work_dir(:new, task, false) + assert_not File.exist? FileHelper.student_work_dir(:in_process, task, false) + + # Delete a file and try to compress + FileUtils.rm("#{FileHelper.student_work_dir(:new, task)}/000-document.pdf") + + assert_not task.compress_new_to_done + + FileHelper.student_work_dir(:new, task, true) + assert_not task.move_files_to_in_process + ensure + unit.destroy + end end diff --git a/test/models/tii_model_test.rb b/test/models/tii_model_test.rb index 8cc79d3a7..e2a4450c2 100644 --- a/test/models/tii_model_test.rb +++ b/test/models/tii_model_test.rb @@ -311,7 +311,7 @@ def test_tii_process "tempfile" => File.new(test_file_path('submissions/1.2P.pdf')) }, - ], user, nil, nil, 'ready_for_feedback', nil, accepted_tii_eula: true + ], nil, nil, 'ready_for_feedback', nil, accepted_tii_eula: true # Check that the submission is going to be progressed assert_equal 1, AcceptSubmissionJob.jobs.count From 1e3acd4e64af2f41227c03b8fa53ab71811dac20 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 23:25:29 +1000 Subject: [PATCH 114/124] feat: add email on accept submission error --- app/mailers/error_log_mailer.rb | 11 +++++++++++ app/sidekiq/accept_submission_job.rb | 12 +++++++++++- app/views/error_log/error_log.text.erb | 3 +++ config/application.rb | 10 +++++++++- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 app/mailers/error_log_mailer.rb create mode 100644 app/views/error_log/error_log.text.erb diff --git a/app/mailers/error_log_mailer.rb b/app/mailers/error_log_mailer.rb new file mode 100644 index 000000000..0eb66a2e9 --- /dev/null +++ b/app/mailers/error_log_mailer.rb @@ -0,0 +1,11 @@ +class ErrorLogMailer < ApplicationMailer + def error_message(message, exception) + email = Doubtfire::Application.config.email_errors_to + return nil if email.blank? + + @doubtfire_product_name = Doubtfire::Application.config.institution[:product_name] + @error_log = "#{message}\n\n#{exception.message}\n\n#{exception.backtrace.join("\n")}" + + mail(to: email, from: email, subject: "#{@doubtfire_product_name} Error Log") + end +end diff --git a/app/sidekiq/accept_submission_job.rb b/app/sidekiq/accept_submission_job.rb index 71e28bdcf..f1654ceb6 100644 --- a/app/sidekiq/accept_submission_job.rb +++ b/app/sidekiq/accept_submission_job.rb @@ -14,6 +14,7 @@ def perform(task_id, user_id, accepted_tii_eula) user = User.find(user_id) begin + logger.info "Accepting submission for task #{task.id} by user #{user.id}" # Convert submission to PDF task.convert_submission_to_pdf(log_to_stdout: false) rescue StandardError => e @@ -26,7 +27,16 @@ def perform(task_id, user_id, accepted_tii_eula) end end - logger.error e + begin + # Notify system admin + mail = ErrorLogMailer.error_message("Failed to convert submission to PDF for task #{task.id} by user #{user.id}", e) + mail.deliver if mail.present? + + logger.error e + rescue StandardError => e + logger.error "Failed to send error log to admin" + end + return end diff --git a/app/views/error_log/error_log.text.erb b/app/views/error_log/error_log.text.erb new file mode 100644 index 000000000..e25167d08 --- /dev/null +++ b/app/views/error_log/error_log.text.erb @@ -0,0 +1,3 @@ +Something went wrong with <%= @doubtfire_product_name %>, and the following log entry was created: + +<%= @error_log %> diff --git a/config/application.rb b/config/application.rb index 88996a2a1..1f623af0f 100644 --- a/config/application.rb +++ b/config/application.rb @@ -42,7 +42,15 @@ class Application < Rails::Application config.student_import_weeks_before = ENV.fetch('DF_IMPORT_STUDENTS_WEEKS_BEFPRE', 1).to_f * 1.week - config.log_to_stdout = ENV['DF_LOG_TO_STDOUT'].present? && (ENV['DF_LOG_TO_STDOUT'].to_s.downcase == "true" || ENV['DF_LOG_TO_STDOUT'].to_i == 1) + def self.fetch_boolean_env(name) + %w'true 1'.include?(ENV.fetch(name, 'false').downcase) + end + + # ==> Log to stdout + config.log_to_stdout = Application.fetch_boolean_env('DF_LOG_TO_STDOUT') + + # Have rails report errors and log messages to the following email address where present + config.email_errors_to = ENV.fetch('DF_EMAIL_ERRORS_TO', nil) # ==> Load credentials from env credentials.secret_key_base = ENV.fetch('DF_SECRET_KEY_BASE', Rails.env.production? ? nil : '9e010ee2f52af762916406fd2ac488c5694a6cc784777136e657511f8bbc7a73f96d59c0a9a778a0d7cf6406f8ecbf77efe4701dfbd63d8248fc7cc7f32dea97') From 8139f41207a2a2b38f6560cc254d8e65bce40988 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 23:33:48 +1000 Subject: [PATCH 115/124] feat: report high usage on database timeout --- app/api/api_root.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/api/api_root.rb b/app/api/api_root.rb index 53435e1e3..a0dbcfc4c 100644 --- a/app/api/api_root.rb +++ b/app/api/api_root.rb @@ -33,6 +33,9 @@ class ApiRoot < Grape::API when ActionController::ParameterMissing message = "Missing value for #{e.param}" status = 400 + when ActiveRecord::ConnectionTimeoutError + message = 'There is currently high load on the system. Please wait a moment and try again.' + status = 503 else # rubocop:disable Rails/Output puts e.inspect unless Rails.env.production? From 758a51dfb9f8c5bc2cf2471caf5b8c0875467971 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 23:34:21 +1000 Subject: [PATCH 116/124] fix: avoid attempts to read negative size in file stream helper --- app/helpers/file_stream_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/file_stream_helper.rb b/app/helpers/file_stream_helper.rb index 6859954d6..1644b3fe4 100644 --- a/app/helpers/file_stream_helper.rb +++ b/app/helpers/file_stream_helper.rb @@ -40,7 +40,7 @@ def stream_file(file_path) end # Return the requested content - content_length = end_point - begin_point + 1 + content_length = [end_point - begin_point + 1, 0].max # Ensure we don't attempt to read a negative length header['Access-Control-Expose-Headers'] = header.key?('Content-Disposition') ? 'Content-Disposition,Content-Range,Accept-Ranges' : 'Content-Range,Accept-Ranges' header['Content-Range'] = "bytes #{begin_point}-#{end_point}/#{file_size}" header['Content-Length'] = content_length.to_s From eb8859b8b32f88eeffaec5af9dac57b6726a2d45 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 1 Aug 2024 23:41:25 +1000 Subject: [PATCH 117/124] chore(release): 8.0.22 --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0858edbfb..0934e4776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,23 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.22](https://github.com/macite/doubtfire-deploy/compare/v8.0.21...v8.0.22) (2024-08-01) + + +### Features + +* add email on accept submission error ([1e3acd4](https://github.com/macite/doubtfire-deploy/commit/1e3acd4e64af2f41227c03b8fa53ab71811dac20)) +* report high usage on database timeout ([8139f41](https://github.com/macite/doubtfire-deploy/commit/8139f41207a2a2b38f6560cc254d8e65bce40988)) + + +### Bug Fixes + +* add awaiting processing pdf ([3e0a1ba](https://github.com/macite/doubtfire-deploy/commit/3e0a1bac485322b6f7936fd3c244cdc5594ca9b1)) +* avoid attempts to read negative size in file stream helper ([758a51d](https://github.com/macite/doubtfire-deploy/commit/758a51dfb9f8c5bc2cf2471caf5b8c0875467971)) +* change zip of new upload to avoid loss ([218afb9](https://github.com/macite/doubtfire-deploy/commit/218afb9291b6864c3ede03b4f74bceaef81b339f)) +* ensure scoop files checks files are a hash ([33ee3ce](https://github.com/macite/doubtfire-deploy/commit/33ee3cecd6e8317cd54f51c4e1e4314725b5085c)) +* only try overseer assessment when overseer enabled ([e3d36c2](https://github.com/macite/doubtfire-deploy/commit/e3d36c27cffbeb8e56dc6c2b085665c5d91cd9ce)) + ### [8.0.21](https://github.com/macite/doubtfire-deploy/compare/v8.0.20...v8.0.21) (2024-07-30) From 842f233d210345682d051e77cc3ddedb98baadc9 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 5 Aug 2024 13:45:16 +1000 Subject: [PATCH 118/124] fix: remove global error and report failures to admin user for tii --- app/helpers/turn_it_in.rb | 50 +++--------------------- app/mailers/error_log_mailer.rb | 4 +- app/models/turn_it_in/tii_action.rb | 4 +- app/sidekiq/accept_submission_job.rb | 4 +- test/models/tii_user_accept_eula_test.rb | 43 -------------------- test/test_helper.rb | 1 - 6 files changed, 12 insertions(+), 94 deletions(-) diff --git a/app/helpers/turn_it_in.rb b/app/helpers/turn_it_in.rb index 8630f2810..7bf73e4f7 100644 --- a/app/helpers/turn_it_in.rb +++ b/app/helpers/turn_it_in.rb @@ -6,7 +6,6 @@ class TurnItIn # rubocop:disable Style/ClassVars @@x_turnitin_integration_name = 'formatif-tii' @@x_turnitin_integration_version = '1.0' - @@global_error = nil @@delay_call_until = nil cattr_reader :x_turnitin_integration_name, :x_turnitin_integration_version @@ -64,47 +63,6 @@ def self.load_tii_features feature_job.fetch_features_enabled end - # A global error indicates that tii is not configured correctly or a change in the - # environment requires that the configuration is updated - def self.global_error - return nil unless TurnItIn.enabled? - - Rails.cache.fetch("tii.global_error") do - @@global_error - end - end - - # Update the global error, when present this will block calls to tii until resolved - def self.global_error=(value) - return unless TurnItIn.enabled? - - @@global_error = value - - if value.present? - Rails.cache.write("tii.global_error", value) - else - Rails.cache.delete("tii.global_error") - end - end - - # Indicates if there is a global error that indicates that things should not call tii until resolved - def self.global_error? - return false unless TurnItIn.enabled? - - Rails.cache.exist?("tii.global_error") || @@global_error.present? - end - - # Clear a global error - def self.clear_global_error - @@global_error = nil - Rails.cache.delete("tii.global_error") - end - - # Indicates that tii can be called, that it is configured and there are no global errors - def self.functional? - TurnItIn.enabled? && !TurnItIn.global_error? - end - # Indicates that the service is rate limited def self.rate_limited? @@delay_call_until.present? && DateTime.now < @@delay_call_until @@ -124,8 +82,12 @@ def self.handle_tii_error(action, error) case error.code when 429 # rate limit @@delay_call_until = DateTime.now + 1.minute - when 403 # forbidden, issue with authentication... do not attempt more tii requests - TurnItIn.global_error = [403, error.message] + when 403 # forbidden, issue with authentication... notify admin + begin + ErrorLogMailer.error_message('TII Credentials', "TII Error: #{error.message}", error).deliver + rescue StandardError => e + Rails.logger.error "Failed to send error email: #{e}" + end end end diff --git a/app/mailers/error_log_mailer.rb b/app/mailers/error_log_mailer.rb index 0eb66a2e9..43ed8d8f4 100644 --- a/app/mailers/error_log_mailer.rb +++ b/app/mailers/error_log_mailer.rb @@ -1,11 +1,11 @@ class ErrorLogMailer < ApplicationMailer - def error_message(message, exception) + def error_message(subject, message, exception) email = Doubtfire::Application.config.email_errors_to return nil if email.blank? @doubtfire_product_name = Doubtfire::Application.config.institution[:product_name] @error_log = "#{message}\n\n#{exception.message}\n\n#{exception.backtrace.join("\n")}" - mail(to: email, from: email, subject: "#{@doubtfire_product_name} Error Log") + mail(to: email, from: email, subject: "#{@doubtfire_product_name} Error Log - #{subject}") end end diff --git a/app/models/turn_it_in/tii_action.rb b/app/models/turn_it_in/tii_action.rb index c53c78cfc..7c852a316 100644 --- a/app/models/turn_it_in/tii_action.rb +++ b/app/models/turn_it_in/tii_action.rb @@ -239,8 +239,8 @@ def log_error # @param description [String] the description of the action that is being performed # @param block [Proc] the block that will be called to perform the call def exec_tca_call(description, codes = [], &block) - unless TurnItIn.functional? - raise TCAClient::ApiError, code: 0, message: "Turn It In not functiona: #{description}" + unless TurnItIn.enabled? + raise TCAClient::ApiError, code: 0, message: "Turn It In not enabled: #{description}" end if TurnItIn.rate_limited? raise TCAClient::ApiError, code: 429, message: "Turn It In rate limited: #{description}" diff --git a/app/sidekiq/accept_submission_job.rb b/app/sidekiq/accept_submission_job.rb index f1654ceb6..c4f660589 100644 --- a/app/sidekiq/accept_submission_job.rb +++ b/app/sidekiq/accept_submission_job.rb @@ -29,7 +29,7 @@ def perform(task_id, user_id, accepted_tii_eula) begin # Notify system admin - mail = ErrorLogMailer.error_message("Failed to convert submission to PDF for task #{task.id} by user #{user.id}", e) + mail = ErrorLogMailer.error_message('Accept Submission', "Failed to convert submission to PDF for task #{task.id} by user #{user.id}", e) mail.deliver if mail.present? logger.error e @@ -41,7 +41,7 @@ def perform(task_id, user_id, accepted_tii_eula) end # When converted, we can now send documents to turn it in for checking - if TurnItIn.functional? + if TurnItIn.enabled? task.send_documents_to_tii(user, accepted_tii_eula: accepted_tii_eula) end rescue StandardError => e # to raise error message to avoid unnecessary retry diff --git a/test/models/tii_user_accept_eula_test.rb b/test/models/tii_user_accept_eula_test.rb index 0d131da78..567b6af2f 100644 --- a/test/models/tii_user_accept_eula_test.rb +++ b/test/models/tii_user_accept_eula_test.rb @@ -138,47 +138,4 @@ def test_eula_accept_rate_limit action.perform assert_requested accept_stub, times: 2 end - - def test_eula_respects_global_errors - setup_tii_features_enabled - setup_tii_eula - - # Prepare stub for call when eula is accepted and it fails - accept_stub = stub_request(:post, "https://#{ENV['TCA_HOST']}/api/v1/eula/v1beta/accept"). - with(tii_headers). - to_return( - {status: 403, body: "", headers: {} }, - {status: 200, body: "", headers: {} }, # should not occur, until end - ) - - user = FactoryBot.create(:user) - # Queue job to accept eula - user.accept_tii_eula - - action = TiiActionAcceptEula.last - - # Make sure we have the right action - assert_equal user, action.entity - - # Perform manually - TiiActionJob.jobs.clear - action.perform - - assert_requested accept_stub, times: 1 - assert_not TurnItIn.functional? - - assert_not action.retry - - action.perform - # Call does not go to tii as limit applied - assert_requested accept_stub, times: 1 - - # Clear global error - TurnItIn.global_error = nil - assert TurnItIn.functional? - - # When cleared, the job will run - action.perform - assert_requested accept_stub, times: 2 - end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 6912a190a..cc50ccdb5 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -73,7 +73,6 @@ class ActiveSupport::TestCase # Ensure turn it in states is cleared TurnItIn.reset_rate_limit - TurnItIn.global_error = nil TestHelpers::TiiTestHelper.setup_tii_eula TestHelpers::TiiTestHelper.setup_tii_features_enabled From cbec03d9e148e5d3fbead9b88621f6c06d368371 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 5 Aug 2024 13:48:46 +1000 Subject: [PATCH 119/124] fix: ensure folders are removed when we move files with file helper --- app/helpers/file_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/file_helper.rb b/app/helpers/file_helper.rb index 480506199..f0da92db5 100644 --- a/app/helpers/file_helper.rb +++ b/app/helpers/file_helper.rb @@ -376,7 +376,7 @@ def move_files(from_path, to_path, retain_from = false, only_before = nil) begin # remove from_path as files are now "in process" # these can be retained when the old folder wants to be kept - FileUtils.rm_r(from_path) unless retain_from + FileUtils.rm_rf(from_path) unless retain_from rescue logger.warn "failed to rm #{from_path}" end From 70236505e753478391c6290f2a8ab878ffb34ffa Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 5 Aug 2024 14:05:33 +1000 Subject: [PATCH 120/124] chore(release): 8.0.23 --- CHANGELOG.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0934e4776..9c0fab27e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.23](https://github.com/macite/doubtfire-deploy/compare/v8.0.22...v8.0.23) (2024-08-05) + + +### Bug Fixes + +* ensure folders are removed when we move files with file helper ([cbec03d](https://github.com/macite/doubtfire-deploy/commit/cbec03d9e148e5d3fbead9b88621f6c06d368371)) +* remove global error and report failures to admin user for tii ([842f233](https://github.com/macite/doubtfire-deploy/commit/842f233d210345682d051e77cc3ddedb98baadc9)) + ### [8.0.22](https://github.com/macite/doubtfire-deploy/compare/v8.0.21...v8.0.22) (2024-08-01) From 7de1a8f5483889026cb9ae986bdb12d6f7b41af6 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 6 Aug 2024 06:11:00 +1000 Subject: [PATCH 121/124] quality: remove unused scorm entity --- app/api/entities/scorm_entity.rb | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 app/api/entities/scorm_entity.rb diff --git a/app/api/entities/scorm_entity.rb b/app/api/entities/scorm_entity.rb deleted file mode 100644 index 07977ac3c..000000000 --- a/app/api/entities/scorm_entity.rb +++ /dev/null @@ -1,6 +0,0 @@ -module Entities - class ScormEntity < Grape::Entity - expose :file_content, documentation: { type: 'string', desc: 'File content' } - expose :content_type, documentation: { type: 'string', desc: 'Content type' } - end -end From e7a6eed53d8e7049b6144e2b07b8018725be01fb Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 8 Aug 2024 20:10:22 +1000 Subject: [PATCH 122/124] fix: update auth token to work with scorm and general --- app/api/authentication_api.rb | 12 ++--- app/api/scorm_api.rb | 2 +- app/helpers/authentication_helpers.rb | 4 +- app/models/auth_token.rb | 12 +++-- app/models/user.rb | 24 ++++++---- config/application.rb | 2 +- .../20240618135038_add_auth_token_type.rb | 3 +- db/schema.rb | 2 +- test/api/auth_test.rb | 47 +++++++++++++++++-- 9 files changed, 79 insertions(+), 29 deletions(-) diff --git a/app/api/authentication_api.rb b/app/api/authentication_api.rb index fc8193fc8..7097db3cf 100644 --- a/app/api/authentication_api.rb +++ b/app/api/authentication_api.rb @@ -242,9 +242,9 @@ class AuthenticationApi < Grape::API logger.info "Get user via auth_token from #{request.ip}" # Authenticate that the token is okay - if authenticated? + if authenticated?(:login) user = User.find_by(username: params[:username]) - token = user.token_for_text?(params[:auth_token]) unless user.nil? + token = user.token_for_text?(params[:auth_token], :login) unless user.nil? error!({ error: 'Invalid token.' }, 404) if token.nil? # Invalidate the token and regenrate a new one @@ -325,7 +325,7 @@ class AuthenticationApi < Grape::API # Find user user = User.find_by(username: user_param) - token = user.token_for_text?(token_param) unless user.nil? + token = user.token_for_text?(token_param, :general) unless user.nil? remember = params[:remember] || false # Token does not match user @@ -360,7 +360,7 @@ class AuthenticationApi < Grape::API } delete '/auth' do user = User.find_by(username: headers['username'] || headers['Username']) - token = user.token_for_text?(headers['auth-token'] || headers['Auth-Token']) unless user.nil? + token = user.token_for_text?(headers['auth-token'] || headers['Auth-Token'], :general) unless user.nil? if token.present? logger.info "Sign out #{user.username} from #{request.ip}" @@ -372,12 +372,12 @@ class AuthenticationApi < Grape::API desc 'Get SCORM authentication token' get '/auth/scorm' do - if authenticated? + if authenticated?(:general) unless authorise? current_user, User, :get_scorm_token error!({ error: 'You cannot get SCORM tokens' }, 403) end - token = current_user.auth_tokens.find_by(token_type: 'scorm') + token = current_user.auth_tokens.find_by(token_type: :scorm) if token.nil? || token.auth_token_expiry <= Time.zone.now token&.destroy token = current_user.generate_scorm_authentication_token! diff --git a/app/api/scorm_api.rb b/app/api/scorm_api.rb index 737460bde..dc3c0e7c3 100644 --- a/app/api/scorm_api.rb +++ b/app/api/scorm_api.rb @@ -7,7 +7,7 @@ class ScormApi < Grape::API helpers AuthorisationHelpers before do - authenticated? + authenticated? :scorm end helpers do diff --git a/app/helpers/authentication_helpers.rb b/app/helpers/authentication_helpers.rb index 2841a779c..9df3da157 100644 --- a/app/helpers/authentication_helpers.rb +++ b/app/helpers/authentication_helpers.rb @@ -13,7 +13,7 @@ module AuthenticationHelpers # Checks if the requested user is authenticated. # Reads details from the params fetched from the caller context. # - def authenticated? + def authenticated?(token_type = :general) auth_param = headers['auth-token'] || headers['Auth-Token'] || params['authToken'] || headers['Auth_Token'] || headers['auth_token'] || params['auth_token'] || params['Auth_Token'] user_param = headers['username'] || headers['Username'] || params['username'] @@ -23,7 +23,7 @@ def authenticated? # Authenticate from header or params if auth_param.present? && user_param.present? && user.present? # Get the list of tokens for a user - token = user.token_for_text?(auth_param) + token = user.token_for_text?(auth_param, token_type) end # Check user by token diff --git a/app/models/auth_token.rb b/app/models/auth_token.rb index ad470a3cd..78cd3951f 100644 --- a/app/models/auth_token.rb +++ b/app/models/auth_token.rb @@ -6,11 +6,17 @@ class AuthToken < ApplicationRecord validates :authentication_token, presence: true validate :ensure_token_unique_for_user, on: :create - def self.generate(user, remember, expiry_time = Time.zone.now + 2.hours, token_type = 'general') + enum token_type: { + general: 0, + login: 1, + scorm: 2 + } + + def self.generate(user, remember, expiry_time = Time.zone.now + 2.hours, token_type = :general) # Loop until new unique auth token is found token = loop do token = Devise.friendly_token - break token unless user.token_for_text?(token) + break token unless user.token_for_text?(token, token_type) end # Create a new AuthToken with this value @@ -54,7 +60,7 @@ def extend_token(remember, expiry_time = Time.zone.now + 2.hours, save = true) end def ensure_token_unique_for_user - if user.token_for_text?(authentication_token) + if user.token_for_text?(authentication_token, nil) errors.add(:authentication_token, 'already exists for the selected user') end end diff --git a/app/models/user.rb b/app/models/user.rb index d4f79a74a..1d88e33ce 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -95,7 +95,7 @@ def authenticate?(data) def generate_authentication_token!(remember = false) # Ensure this user is saved... so it has an id self.save unless self.persisted? - AuthToken.generate(self, remember) + AuthToken.generate(self, remember) # default timeout, and general token end # @@ -104,16 +104,16 @@ def generate_authentication_token!(remember = false) def generate_temporary_authentication_token! # Ensure this user is saved... so it has an id self.save unless self.persisted? - AuthToken.generate(self, false, Time.zone.now + 30.seconds) + # Generate a short duration login token + AuthToken.generate(self, false, Time.zone.now + 30.seconds, :login) end # # Generate an authentication token for scorm asset retrieval # def generate_scorm_authentication_token! - # Ensure this user is saved... so it has an id - self.save unless self.persisted? - AuthToken.generate(self, false, Time.zone.now + 2.hours, 'scorm') + # generate a timed scorm token + AuthToken.generate(self, false, Time.zone.now + 2.hours, :scorm) end # @@ -126,8 +126,11 @@ def authentication_token_expired? # # Returns authentication of the user # - def token_for_text?(a_token) - self.auth_tokens.each do |token| + def token_for_text?(a_token, token_type) + tokens_to_check = self.auth_tokens + tokens_to_check = tokens_to_check.where(token_type: token_type) if token_type.present? + + tokens_to_check.each do |token| if a_token == token.authentication_token return token end @@ -310,7 +313,9 @@ def self.permissions :get_teaching_periods, :admin_overseer, - :use_overseer + :use_overseer, + + :get_scorm_token ] # What can auditors do with users? @@ -324,7 +329,8 @@ def self.permissions :audit_units, :get_teaching_periods, - :use_overseer + :use_overseer, + :get_scorm_token ] # What can convenors do with users? diff --git a/config/application.rb b/config/application.rb index 1f623af0f..ffa8f13f9 100644 --- a/config/application.rb +++ b/config/application.rb @@ -69,7 +69,7 @@ def self.fetch_boolean_env(name) config.institution[:privacy] = ENV['DF_INSTITUTION_PRIVACY'] if ENV['DF_INSTITUTION_PRIVACY'] config.institution[:plagiarism] = ENV['DF_INSTITUTION_PLAGIARISM'] if ENV['DF_INSTITUTION_PLAGIARISM'] # Institution host becomes localhost in development - config.institution[:host] ||= 'http://localhost:3000' if Rails.env.development? + config.institution[:host] ||= 'http://localhost:4200' if Rails.env.development? config.institution[:settings] = ENV['DF_INSTITUTION_SETTINGS_RB'] if ENV['DF_INSTITUTION_SETTINGS_RB'] config.institution[:ffmpeg] = ENV['DF_FFMPEG_PATH'] || 'ffmpeg' diff --git a/db/migrate/20240618135038_add_auth_token_type.rb b/db/migrate/20240618135038_add_auth_token_type.rb index 0183bda87..da6613a17 100644 --- a/db/migrate/20240618135038_add_auth_token_type.rb +++ b/db/migrate/20240618135038_add_auth_token_type.rb @@ -1,5 +1,6 @@ class AddAuthTokenType < ActiveRecord::Migration[7.1] def change - add_column :auth_tokens, :token_type, :string, null: false + add_column :auth_tokens, :token_type, :integer, null: false, default: 0 + add_index :auth_tokens, :token_type end end diff --git a/db/schema.rb b/db/schema.rb index bf445bfdd..af59778e8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -24,7 +24,7 @@ t.datetime "auth_token_expiry", null: false t.bigint "user_id" t.string "authentication_token", null: false - t.string "token_type", null: false + t.integer "token_type", default: 0, null: false t.index ["user_id"], name: "index_auth_tokens_on_user_id" end diff --git a/test/api/auth_test.rb b/test/api/auth_test.rb index 670a50eea..6e6b13428 100644 --- a/test/api/auth_test.rb +++ b/test/api/auth_test.rb @@ -44,6 +44,10 @@ def test_auth_post # Check other values returned assert_equal expected_auth.role.name, response_user_data['system_role'], 'Roles match' + token = User.first.token_for_text? actual_auth['auth_token'], :general + assert token.present? + assert_equal 'general', token.token_type + # User has the token - count of matching tokens for that user is 1 assert_equal 1, expected_auth.auth_tokens.select{|t| t.authentication_token == actual_auth['auth_token']}.count end @@ -274,13 +278,14 @@ def test_scorm_auth add_auth_header_for(user: admin) - # When user is unauthorised + # All users can access scorm resources get "api/auth/scorm" - assert_equal 403, last_response.status + assert_equal 200, last_response.status + assert_equal 1, student.auth_tokens.where(token_type: :scorm).count student = FactoryBot.create(:user, :student) - student.auth_tokens.where(token_type: 'scorm').destroy_all + student.auth_tokens.where(token_type: :scorm).destroy_all add_auth_header_for(user: student) @@ -288,7 +293,7 @@ def test_scorm_auth get "api/auth/scorm" assert_equal 200, last_response.status assert last_response_body["scorm_auth_token"] - assert student.auth_tokens.where(token_type: 'scorm').count == 1 + assert 2, student.auth_tokens.where(token_type: :scorm).count first_token = last_response_body["scorm_auth_token"] @@ -299,7 +304,7 @@ def test_scorm_auth assert_equal 200, last_response.status assert last_response_body["scorm_auth_token"] == first_token - old_token = student.auth_tokens.find_by(token_type: 'scorm') + old_token = student.auth_tokens.find_by(token_type: :scorm) old_token.auth_token_expiry = Time.zone.now - 1.day old_token.save! @@ -316,4 +321,36 @@ def test_scorm_auth # End SCORM auth test # --------------------------------------------------------------------------- # + + def test_login_token + unit = FactoryBot.create :unit, with_students: false + user = unit.main_convenor_user + + token = user.generate_temporary_authentication_token! + + add_auth_header_for(user: user, auth_token: token) + + get 'api/units' + + assert 403, last_response.status + + post 'api/auth' + ensure + unit.destroy + end + + def test_scorm_token + unit = FactoryBot.create :unit, with_students: false + user = unit.main_convenor_user + + token = user.generate_scorm_authentication_token! + + add_auth_header_for(user: user, auth_token: token) + + get '/api/units' + + assert 403, last_response.status + ensure + unit.destroy + end end From 02af2cf77c234d19c4aba0e9382b73bc552d4bdc Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 9 Aug 2024 10:28:58 +1000 Subject: [PATCH 123/124] test: fix scorm and auth tests with new tokens --- app/api/authentication_api.rb | 10 +++++----- app/models/user.rb | 12 ++++-------- test/api/auth_test.rb | 2 +- test/api/scorm_api_test.rb | 19 +++++++++++++------ test/helpers/auth_helper.rb | 6 +++--- 5 files changed, 26 insertions(+), 23 deletions(-) diff --git a/app/api/authentication_api.rb b/app/api/authentication_api.rb index 7097db3cf..f9e68ff66 100644 --- a/app/api/authentication_api.rb +++ b/app/api/authentication_api.rb @@ -72,7 +72,7 @@ class AuthenticationApi < Grape::API # Return user details present :user, user, with: Entities::UserEntity - present :auth_token, user.generate_authentication_token!(remember).authentication_token + present :auth_token, user.generate_authentication_token!(remember: remember).authentication_token end end @@ -238,18 +238,18 @@ class AuthenticationApi < Grape::API requires :auth_token, type: String, desc: 'The user\'s temporary auth token' end post '/auth' do - error!({ error: 'Invalid token.' }, 404) if params[:auth_token].nil? - logger.info "Get user via auth_token from #{request.ip}" + error!({ error: 'Invalid authentication details.' }, 404) if params[:auth_token].blank? || params[:username].blank? + logger.info "Get user via auth_token from #{request.ip} - #{params[:username]}" # Authenticate that the token is okay if authenticated?(:login) user = User.find_by(username: params[:username]) token = user.token_for_text?(params[:auth_token], :login) unless user.nil? - error!({ error: 'Invalid token.' }, 404) if token.nil? + error!({ error: 'Invalid authentication details.' }, 404) if token.nil? # Invalidate the token and regenrate a new one token.destroy! - token = user.generate_authentication_token! true + token = user.generate_authentication_token! logger.info "Login #{params[:username]} from #{request.ip}" diff --git a/app/models/user.rb b/app/models/user.rb index 1d88e33ce..d53ca9efc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -92,28 +92,24 @@ def authenticate?(data) # Force-generates a new authentication token, regardless of whether or not # it is actually expired # - def generate_authentication_token!(remember = false) + def generate_authentication_token!(remember: false, expiry: Time.zone.now + 2.hours, token_type: :general) # Ensure this user is saved... so it has an id self.save unless self.persisted? - AuthToken.generate(self, remember) # default timeout, and general token + AuthToken.generate(self, remember, expiry, token_type) end # # Generate an authentication token that will expire in 30 seconds # def generate_temporary_authentication_token! - # Ensure this user is saved... so it has an id - self.save unless self.persisted? - # Generate a short duration login token - AuthToken.generate(self, false, Time.zone.now + 30.seconds, :login) + generate_authentication_token!(expiry: Time.zone.now + 30.seconds, token_type: :login) end # # Generate an authentication token for scorm asset retrieval # def generate_scorm_authentication_token! - # generate a timed scorm token - AuthToken.generate(self, false, Time.zone.now + 2.hours, :scorm) + generate_authentication_token!(token_type: :scorm) end # diff --git a/test/api/auth_test.rb b/test/api/auth_test.rb index 6e6b13428..786f0adba 100644 --- a/test/api/auth_test.rb +++ b/test/api/auth_test.rb @@ -281,7 +281,7 @@ def test_scorm_auth # All users can access scorm resources get "api/auth/scorm" assert_equal 200, last_response.status - assert_equal 1, student.auth_tokens.where(token_type: :scorm).count + assert_equal 1, admin.auth_tokens.where(token_type: :scorm).count student = FactoryBot.create(:user, :student) diff --git a/test/api/scorm_api_test.rb b/test/api/scorm_api_test.rb index b4837d3f5..be6808bee 100644 --- a/test/api/scorm_api_test.rb +++ b/test/api/scorm_api_test.rb @@ -40,35 +40,42 @@ def test_serve_scorm_content td.save! # When the task def does not have SCORM data - get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/index.html" + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :scorm)}/index.html" assert_equal 404, last_response.status td.add_scorm_data(test_file_path('numbas.zip'), copy: true) td.save! # When the file is missing - get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/index1.html" + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :scorm)}/index1.html" assert_equal 404, last_response.status # When the file is present - html - get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/index.html" + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :scorm)}/index.html" assert_equal 200, last_response.status assert_equal 'text/html', last_response.content_type + # Cannot access with the wrong token type + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :general)}/index.html" + assert_equal 419, last_response.status + + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :login)}/index.html" + assert_equal 419, last_response.status + # When the file is present - css - get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/styles.css" + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :scorm)}/styles.css" assert_equal 200, last_response.status assert_equal 'text/css', last_response.content_type # When the file is present - js - get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user)}/scripts.js" + get "/api/scorm/#{td.id}/#{user.username}/#{auth_token(user, :scorm)}/scripts.js" assert_equal 200, last_response.status assert_equal 'text/javascript', last_response.content_type tutor = FactoryBot.create(:user, :tutor, username: :test_tutor) # When the user is unauthorised - get "/api/scorm/#{td.id}/#{tutor.username}/#{auth_token(tutor)}/index.html" + get "/api/scorm/#{td.id}/#{tutor.username}/#{auth_token(tutor, :scorm)}/index.html" assert_equal 403, last_response.status tutor.destroy! diff --git a/test/helpers/auth_helper.rb b/test/helpers/auth_helper.rb index 42537449b..c60348949 100644 --- a/test/helpers/auth_helper.rb +++ b/test/helpers/auth_helper.rb @@ -13,11 +13,11 @@ def app # # Gets an auth token for the provided user # - def auth_token(user = User.first) - token = user.valid_auth_tokens().first + def auth_token(user = User.first, token_type = :general) + token = user.valid_auth_tokens.where(token_type: token_type).first return token.authentication_token unless token.nil? - return user.generate_authentication_token!().authentication_token + return user.generate_authentication_token!(token_type: token_type).authentication_token end # From 80592130bfb33bbb74322c5950e62e2663223af1 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 9 Aug 2024 13:05:29 +1000 Subject: [PATCH 124/124] fix: preload unit in test attempt and ensure limit flexibility in validation --- app/api/test_attempts_api.rb | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/app/api/test_attempts_api.rb b/app/api/test_attempts_api.rb index 51fa6ef21..c709cc094 100644 --- a/app/api/test_attempts_api.rb +++ b/app/api/test_attempts_api.rb @@ -10,26 +10,13 @@ class TestAttemptsApi < Grape::API authenticated? end - # Handle common exceptions - rescue_from :all do |e| - error!({ error: e.message }, 500) - end - - rescue_from ActiveRecord::RecordNotFound do |e| - error!({ error: e.message }, 404) - end - - rescue_from Grape::Exceptions::ValidationErrors do |e| - error!({ errors: e.full_messages }, 400) - end - desc 'Get all test results for a task' params do requires :project_id, type: Integer, desc: 'The id of the project with the task' requires :task_definition_id, type: Integer, desc: 'The id of the task definition related to the task' end get '/projects/:project_id/task_def_id/:task_definition_id/test_attempts' do - project = Project.find(params[:project_id]) + project = Project.preload(:unit).find(params[:project_id]) task_definition = project.unit.task_definitions.find(params[:task_definition_id]) unless authorise? current_user, project, :get_submission @@ -38,7 +25,7 @@ class TestAttemptsApi < Grape::API task = project.task_for_task_definition(task_definition) - attempts = TestAttempt.where("task_id = ?", task.id) + attempts = TestAttempt.where(task_id: task.id) tests = attempts.order(id: :desc) present tests, with: Entities::TestAttemptEntity end @@ -133,7 +120,7 @@ class TestAttemptsApi < Grape::API # check attempt limit limit = task.task_definition.scorm_attempt_limit + task.scorm_extensions - if limit != 0 && test_count == limit + if limit != 0 && test_count >= limit error!({ message: 'Attempt limit has been reached' }, 400) return end

dARkjA8JU!8C$3Gy%k6Kdnf&iW7YWG-ZUCfri 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