Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions app/api/entities/task_definition_entity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@ def staff?(my_role)
expose :has_jplag_report?, as: :has_jplag_report, if: ->(unit, options) { staff?(options[:my_role]) }
expose :is_graded
expose :max_quality_pts

expose :estimated_days do |task_def, _options|
task_def.estimated_days
end

expose :estimated_hours do |task_def, _options|
task_def.estimated_hours
end
expose :overseer_image_id, if: ->(unit, options) { staff?(options[:my_role]) }, expose_nil: false
# expose :assessment_enabled, if: ->(unit, options) { staff?(options[:my_role]) }
expose :assessment_enabled
Expand Down
28 changes: 19 additions & 9 deletions app/api/task_definitions_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class TaskDefinitionsApi < Grape::API
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 :estimated_hours, type: Integer, desc: 'Estimated time to complete task, measured in hours'
optional :similarity_language, type: String, desc: 'The language to use for code similarity checks'
optional :scorm_enabled, type: Boolean, desc: 'Whether SCORM assessment is enabled for this task'
optional :scorm_allow_review, type: Boolean, desc: 'Whether a student is allowed to review their completed test attempts'
Expand Down Expand Up @@ -74,6 +75,7 @@ class TaskDefinitionsApi < Grape::API
:max_quality_pts,
:assessment_enabled,
:overseer_image_id,
:estimated_hours,
:similarity_language,
:assess_in_portfolio_only,
:requires_discussion,
Expand All @@ -86,6 +88,9 @@ class TaskDefinitionsApi < Grape::API
task_params[:unit_id] = unit.id
task_params[:upload_requirements] = params[:task_def][:upload_requirements].present? ? JSON.parse(params[:task_def][:upload_requirements]) : []

hours = task_params.delete(:estimated_hours).to_i
task_params[:estimated_time_minutes] = (hours * 60)

task_def = TaskDefinition.new(task_params)

# Set the tutorial stream
Expand Down Expand Up @@ -134,6 +139,7 @@ class TaskDefinitionsApi < Grape::API
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 :estimated_hours, type: Integer, desc: 'Estimated time to complete task, measured in hours'
optional :similarity_language, type: String, desc: 'The language to use for code similarity checks'
optional :assess_in_portfolio_only, type: Boolean, desc: 'Whether a task can only be signed off during portfolio assessment'
optional :requires_discussion, type: Boolean, desc: 'Whether task must be discussed in class before it can be signed off as complete'
Expand Down Expand Up @@ -188,6 +194,7 @@ class TaskDefinitionsApi < Grape::API
:max_quality_pts,
:assessment_enabled,
:overseer_image_id,
:estimated_hours,
:similarity_language,
:assess_in_portfolio_only,
:requires_discussion,
Expand All @@ -199,17 +206,20 @@ class TaskDefinitionsApi < Grape::API
if params[:task_def][:upload_requirements].present?
upload_reqs = JSON.parse(params[:task_def][:upload_requirements])
task_params[:upload_requirements] = upload_reqs
end

# Ensure we permit all of the passed in upload requirements
if task_params[:upload_requirements].is_a? Array
# Force permit - the model validates the details
task_params[:upload_requirements].each(&:permit!)
end
hours = task_params.delete(:estimated_hours).to_i
task_params[:estimated_time_minutes] = (hours * 60)

# Ensure changes to a TD defined as a 'draft task definition' are validated
if unit.draft_task_definition_id == params[:id] && (upload_reqs.length != 1 || upload_reqs[0]['type'] != 'document')
error!({ error: 'Task is marked as the draft learning summary. A draft learning summary task can only contain a single document upload.' }, 403)
end
# Ensure we permit all of the passed in upload requirements
if task_params[:upload_requirements].is_a? Array
# Force permit - the model validates the details
task_params[:upload_requirements].each(&:permit!)
end

# Ensure changes to a TD defined as a 'draft task definition' are validated
if unit.draft_task_definition_id == params[:id] && (upload_reqs.length != 1 || upload_reqs[0]['type'] != 'document')
error!({ error: 'Task is marked as the draft learning summary. A draft learning summary task can only contain a single document upload.' }, 403)
end

# Bulk update task definition with permitted parameters
Expand Down
4 changes: 4 additions & 0 deletions app/models/task_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,10 @@ def read_file_from_resources(filename)
nil
end

def estimated_hours
(estimated_time_minutes.to_i / 60) % 24
end

private

def delete_associated_files()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class AddEstimatedTimeMinutesToTaskDefinitions < ActiveRecord::Migration[8.0]
def up
add_column :task_definitions, :estimated_time_minutes, :integer, null: true, default: 0, comment: "Estimated time to complete task, measured in minutes"
end

def down
remove_column :task_definitions, :estimated_time_minutes
end
end
1 change: 1 addition & 0 deletions db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@
t.boolean "assessment_enabled", default: false
t.bigint "overseer_image_id"
t.string "tii_group_id"
t.integer "estimated_time_minutes", default: 0, comment: "Estimated time to complete task, measured in minutes"
t.string "similarity_language"
t.boolean "scorm_enabled", default: false
t.boolean "scorm_allow_review", default: false
Expand Down
13 changes: 10 additions & 3 deletions test/api/units/task_definitions_api_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ def all_task_def_keys
'restrict_status_updates',
'plagiarism_warn_pct',
'is_graded',
'max_quality_pts'
'max_quality_pts',
'estimated_hours'
]
end

Expand All @@ -49,7 +50,8 @@ 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,
estimated_hours: 0
}
}

Expand All @@ -66,6 +68,8 @@ def test_task_definition_cud
assert_equal [{ "key" => "file0", "name" => "Shape Class", "type" => "document" }], td.upload_requirements
assert_equal unit.tutorial_streams.first.id, td.tutorial_stream_id
assert_equal 4, td.weighting
assert_equal (24 * 60), td.estimated_time_minutes
assert_equal 0, last_response_body['estimated_hours']

data_to_put = {
task_def: {
Expand All @@ -83,7 +87,8 @@ def test_task_definition_cud
upload_requirements: [ { "key": "file0", "name": "Other Class", "type": "document" } ].to_json,
plagiarism_warn_pct: 80,
is_graded: false,
max_quality_pts: 0
max_quality_pts: 0,
estimated_hours: 3
}
}

Expand All @@ -99,6 +104,8 @@ def test_task_definition_cud
assert_equal unit.tutorial_streams.last.id, td.tutorial_stream_id
assert_equal [{ "key" => "file0", "name" => "Other Class", "type" => "document" }], td.upload_requirements
assert_equal 2, td.weighting
assert_equal 3060, td.estimated_time_minutes
assert_equal 3, last_response_body['estimated_hours']
end

def test_post_invalid_file_tasksheet
Expand Down