diff --git a/htdocs/js/AchievementItems/achievementitems.js b/htdocs/js/AchievementItems/achievementitems.js deleted file mode 100644 index 267d27f495..0000000000 --- a/htdocs/js/AchievementItems/achievementitems.js +++ /dev/null @@ -1,33 +0,0 @@ -(() => { - for (const setSelect of document.querySelectorAll('select[data-problems]')) { - setSelect.addEventListener('change', () => { - const problemIds = JSON.parse( - Array.from(setSelect.querySelectorAll('option')).find((option) => option.value === setSelect.value) - ?.dataset.problemIds ?? '[]' - ); - - const problemSelect = document.getElementById(setSelect.dataset.problems); - if (problemSelect) { - for (const option of problemSelect.querySelectorAll('option')) option.remove(); - for (const id of problemIds) { - const option = document.createElement('option'); - option.value = id; - option.text = id; - problemSelect.add(option); - } - } - - // This is only used by the "Box of Transmogrification". - const problemSelect2 = document.getElementById(setSelect.dataset.problems2); - if (problemSelect2) { - for (const option of problemSelect2.querySelectorAll('option')) option.remove(); - for (const id of problemIds) { - const option = document.createElement('option'); - option.value = id; - option.text = id; - problemSelect2.add(option); - } - } - }); - } -})(); diff --git a/lib/WeBWorK/AchievementItems.pm b/lib/WeBWorK/AchievementItems.pm index 7585142b5d..f0f0eea827 100644 --- a/lib/WeBWorK/AchievementItems.pm +++ b/lib/WeBWorK/AchievementItems.pm @@ -16,7 +16,7 @@ package WeBWorK::AchievementItems; use Mojo::Base -signatures; -use WeBWorK::Utils qw(thaw_base64); +use WeBWorK::Utils qw(nfreeze_base64 thaw_base64); # List of available achievement items. Make sure to add any new items to this list. Furthermore, the elements in this # list have to match the class name of the achievement item classes loaded below. @@ -44,65 +44,125 @@ use constant ITEMS => [ qw( =head2 NAME -This is the base class for achievement times. This defines an interface for all of the achievement items. Each -achievement item will have a name, a description, a method for creating an html form to get its inputs called print_form -and a method for applying those inputs called use_item. +This is the base class for achievement times. This defines an interface for all of the achievement items. +Each achievement item will have an id, a name, a description, and the three methods can_use (checks if the +item can be used on the given set), print_form (prints the form to use the item), and use_item. Note: the ID has to match the name of the class. +The global method UserItems returns an array of all achievement items available to the given user. If no +set is included, a list of all earned achievement items is return. If provided a set and corresponding problem +or test version records, a list of items usable on the current set and records paired with an input form to +use the item is returned. This method will also process any posts to use the achievement item. + =cut -sub id ($c) { return $c->{id}; } -sub name ($c) { return $c->{name}; } -sub description ($c) { return $c->{description}; } +sub id ($self) { return $self->{id}; } +sub name ($self) { return $self->{name}; } +sub count ($self) { return $self->{count}; } +sub description ($self) { return $self->{description}; } + +# Method to find all achievement items available to the given user. +# If $set is undefined return an array reference of all earned items. +# If $set is defined, return an array reference of the usable items +# for the given $set and problem or test versions records. Each item +# is paired with its input form to use the item. +sub UserItems ($c, $userName, $set, $records) { + my $db = $c->db; -# This is a global method that returns all of the provided users items. -sub UserItems ($userName, $db, $ce) { - # return unless the user has global achievement data - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); + # When acting as another user, achievement items can be listed but not used. + return if $set && $userName ne $c->param('user'); - return unless ($globalUserAchievement->frozen_hash); + # Return unless the user has global achievement data. + my $globalUserAchievement = $c->{globalData} // $db->getGlobalUserAchievement($userName); + return unless $globalUserAchievement && $globalUserAchievement->frozen_hash; - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); + my $globalData = thaw_base64($globalUserAchievement->frozen_hash); + my $use_item_id = $c->param('use_achievement_item_id') // ''; my @items; - # Get a new item object for each type of item. for my $item (@{ +ITEMS }) { - push(@items, [ "WeBWorK::AchievementItems::$item"->new, $globalData->{$item} ]) - if ($globalData->{$item}); + next unless $globalData->{$item}; + my $achievementItem = "WeBWorK::AchievementItems::$item"->new; + $achievementItem->{count} = $globalData->{$item}; + + # Return list of achievements items if $set is not defined. + unless ($set) { + push(@items, $achievementItem); + next; + } + next unless $achievementItem->can_use($set, $records); + + # Use the achievement item. + if ($use_item_id eq $item) { + my $message = $achievementItem->use_item($set, $records, $c); + if ($message) { + $globalData->{$item}--; + $achievementItem->{count}--; + $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); + $db->putGlobalUserAchievement($globalUserAchievement); + $c->addgoodmessage($c->maketext('[_1] succesffuly used. [_2]', $achievementItem->name, $message)); + } + } + + push(@items, [ $achievementItem, $use_item_id ? '' : $achievementItem->print_form($set, $records, $c) ]); } + # If an achievement item has been used, double check if the achievement items can still be used + # since the item count could now be zero or an achievement item has altered the set/records. + # Input forms are also built here to account for any possible change. + if ($set && $use_item_id) { + my @new_items; + for (@items) { + my $item = $_->[0]; + next unless $item->{count} && $item->can_use($set, $records); + push(@new_items, [ $item, $item->print_form($set, $records, $c) ]); + } + return \@new_items; + } return \@items; } +# Method that returns a string with the achievement name and number of remaining items. +sub remaining_title ($self, $c) { + if ($self->count > 1) { + return $c->maketext('[_1] ([_2] remaining)', $c->maketext($self->name), $self->count); + } elsif ($self->count < 0) { + return $c->maketext('[_1] (unlimited reusability)', $c->maketext($self->name)); + } else { + return $c->maketext('[_1] (1 remains)', $c->maketext($self->name)); + } +} + # Utility method for outputing a form row with a label and popup menu. # The id, label_text, and values are required parameters. sub form_popup_menu_row ($c, %options) { my %params = ( - id => '', - label_text => '', - label_attr => {}, - values => [], - menu_attr => {}, - menu_container_attr => {}, - add_container => 1, + id => '', + first_item => '', + label_text => '', + label_attr => {}, + values => [], + menu_attr => {}, + add_container => 1, %options ); - $params{label_attr}{class} //= 'col-4 col-form-label'; - $params{menu_attr}{class} //= 'form-select'; - $params{menu_container_attr}{class} //= 'col-8'; + $params{label_attr}{class} //= 'col-form-label'; + $params{menu_attr}{class} //= 'form-select'; - my $row_contents = $c->c( - $c->label_for($params{id} => $params{label_text}, %{ $params{label_attr} }), - $c->tag( - 'div', - %{ $params{menu_container_attr} }, - $c->select_field($params{id} => $params{values}, id => $params{id}, %{ $params{menu_attr} }) - ) - )->join(''); + unshift(@{ $params{values} }, [ $params{first_item} => '' ]) if $params{first_item}; + + my $row_contents = $c->tag( + 'div', + class => 'form-floating', + $c->c( + $c->select_field($params{id} => $params{values}, %{ $params{menu_attr} }), + $c->label_for($params{id} => $params{label_text}, %{ $params{label_attr} }) + )->join('') + ); - return $params{add_container} ? $c->tag('div', class => 'row mb-3', $row_contents) : $row_contents; + return $params{add_container} ? $c->tag('div', class => 'my-3', $row_contents) : $row_contents; } END { diff --git a/lib/WeBWorK/AchievementItems/AddNewTestGW.pm b/lib/WeBWorK/AchievementItems/AddNewTestGW.pm index 07b1d4e813..ebfefeef4b 100644 --- a/lib/WeBWorK/AchievementItems/AddNewTestGW.pm +++ b/lib/WeBWorK/AchievementItems/AddNewTestGW.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to allow students to take an additional version of a test within its test version interval -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); -use WeBWorK::Utils::DateTime qw(before between); -use WeBWorK::Utils::Sets qw(format_set_name_display); +use WeBWorK::Utils qw(x); +use WeBWorK::Utils::DateTime qw(between); sub new ($class) { return bless { @@ -33,60 +32,34 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my $db = $c->db; - - my @openGateways; - - # Find the template sets of open gateway quizzes. - for my $set (@$sets) { - push(@openGateways, [ format_set_name_display($set->set_id) => $set->set_id ]) - if $set->assignment_type =~ /gateway/ - && $set->set_id !~ /,v\d+$/ - && between($set->open_date, $set->due_date); - } - - return unless @openGateways; +sub can_use ($self, $set, $records) { + return + $set->assignment_type =~ /gateway/ + && $set->set_id !~ /,v\d+$/ + && between($set->open_date, $set->due_date) + && $set->versions_per_interval > 0; +} - return $c->c( - $c->tag('p', $c->maketext('Add a new version for which test?')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'adtgw_gw_id', - label_text => $c->maketext('Test Name'), - values => \@openGateways, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + 'Increase the number of versions from [_1] to [_2] for this test.', + $set->versions_per_interval, + $set->versions_per_interval + 1 ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('adtgw_gw_id'); - return 'You need to input a Test Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set && $userSet; - - # Add an additional version per interval to the set. - $userSet->versions_per_interval($set->versions_per_interval + 1) unless $set->versions_per_interval == 0; +sub use_item ($self, $set, $records, $c) { + # Increase the number of versions per interval by 1. + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); + $set->versions_per_interval($set->versions_per_interval + 1); + $userSet->versions_per_interval($set->versions_per_interval); $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext('One additional test version added to this test.'); } 1; diff --git a/lib/WeBWorK/AchievementItems/DoubleProb.pm b/lib/WeBWorK/AchievementItems/DoubleProb.pm index a23b294061..3e82bea2c7 100644 --- a/lib/WeBWorK/AchievementItems/DoubleProb.pm +++ b/lib/WeBWorK/AchievementItems/DoubleProb.pm @@ -18,11 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to make a problem worth double. -use Mojo::JSON qw(encode_json); - -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -32,84 +29,49 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # Construct a dropdown with open sets and another with problems. - # Javascript ensures the appropriate problems are shown for the selected set. - - my (@openSets, @initialProblemIDs); - - for my $i (0 .. $#$sets) { - if (after($sets->[$i]->open_date) - && $sets->[$i]->assignment_type eq 'default' - && @{ $setProblemIds->{ $sets->[$i]->set_id } }) - { - push( - @openSets, - [ - format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id, - data => { problem_ids => encode_json($setProblemIds->{ $sets->[$i]->set_id }) } - ] - ); - @initialProblemIDs = @{ $setProblemIds->{ $sets->[$i]->set_id } } unless @initialProblemIDs; - } - } - - return unless @openSets; - - return $c->c( - $c->tag( - 'p', - $c->maketext( - 'Please choose the set name and problem number of the question which should have its weight doubled.') - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'dbp_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr', data => { problems => 'dbp_problem_id' } } - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'dbp_problem_id', - label_text => $c->maketext('Problem Number'), - values => \@initialProblemIDs, - menu_container_attr => { class => 'col-3' } - ) - )->join(''); +sub can_use ($self, $set, $records) { + return $set->assignment_type eq 'default' && after($set->open_date); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('dbp_set_id'); - return 'You need to input a Set Name' unless defined $setID; +sub print_form ($self, $set, $records, $c) { + return WeBWorK::AchievementItems::form_popup_menu_row( + $c, + id => 'dbp_problem_id', + label_text => $c->maketext('Problem Number'), + first_item => $c->maketext('Choose problem to double.'), + values => [ + map { [ $c->maketext('Problem [_1] ([_2] to [_3])', $_->problem_id, $_->value, 2 * $_->value) => + $_->problem_id ] } @$records + ], + ); +} +sub use_item ($self, $set, $records, $c) { my $problemID = $c->param('dbp_problem_id'); - return 'You need to input a Problem Number' unless $problemID; + unless ($problemID) { + $c->addbadmessage($c->maketext('Select problem to double with the [_1].', $self->name)); + return ''; + } - my $globalproblem = $db->getMergedProblem($userName, $setID, $problemID); - my $problem = $db->getUserProblem($userName, $setID, $problemID); - return 'There was an error accessing that problem.' unless $globalproblem && $problem; + my $problem; + for (@$records) { + if ($_->problem_id == $problemID) { + $problem = $_; + last; + } + } + return '' unless $problem; # Double the value of the problem. - $problem->value($globalproblem->value * 2); - $db->putUserProblem($problem); - - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + my $db = $c->db; + my $userProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); + my $orig_value = $problem->value; + $problem->value($orig_value * 2); + $userProblem->value($problem->value); + $db->putUserProblem($userProblem); + + return $c->maketext('Problem [_1] increased from [_2] points to [_3] points.', + $problemID, $orig_value, $problem->value); } 1; diff --git a/lib/WeBWorK/AchievementItems/DoubleSet.pm b/lib/WeBWorK/AchievementItems/DoubleSet.pm index 680ffc2672..f6c3213982 100644 --- a/lib/WeBWorK/AchievementItems/DoubleSet.pm +++ b/lib/WeBWorK/AchievementItems/DoubleSet.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to make a homework set worth twice as much -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -30,62 +29,35 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; +sub can_use ($self, $set, $records) { + return $set->assignment_type eq 'default' && after($set->open_date); +} - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (after($sets->[$i]->open_date) && $sets->[$i]->assignment_type eq 'default'); +sub print_form ($self, $set, $records, $c) { + my $total = 0; + for my $problem (@$records) { + $total += $problem->value; } - - return unless @openSets; - - return $c->c( - $c->tag('p', $c->maketext('Choose the set which you would like to be worth twice as much.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'dub_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } - ) - )->join(''); + return $c->tag('p', + $c->maketext(q(Increase this assignment's total number of points from [_1] to [_2].), $total, 2 * $total)); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('dub_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - return q{Couldn't find that set!} unless $set; - - my @probIDs = $db->listUserProblems($userName, $setID); - - for my $probID (@probIDs) { - my $globalproblem = $db->getMergedProblem($userName, $setID, $probID); - my $problem = $db->getUserProblem($userName, $setID, $probID); - - # Double the problem value. - $problem->value($globalproblem->value * 2); - $db->putUserProblem($problem); +sub use_item ($self, $set, $records, $c) { + my $db = $c->db; + my $old_value = 0; + my $new_value = 0; + + my @userProblems = $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $old_value += $records->[$n]->value; + $records->[$n]->value($records->[$n]->value * 2); + $userProblems[$n]->value($records->[$n]->value); + $new_value += $userProblems[$n]->value; + $db->putUserProblem($userProblems[$n]); } - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext(q(Assignment's total point value increased from [_1] points to [_2] points), + $old_value, $new_value); } 1; diff --git a/lib/WeBWorK/AchievementItems/DuplicateProb.pm b/lib/WeBWorK/AchievementItems/DuplicateProb.pm index 054154cce7..18765951d4 100644 --- a/lib/WeBWorK/AchievementItems/DuplicateProb.pm +++ b/lib/WeBWorK/AchievementItems/DuplicateProb.pm @@ -18,11 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to turn one problem into another problem -use Mojo::JSON qw(encode_json); - -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(between); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -32,109 +29,57 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # Show open sets and allow for a choice of two problems from the set. - # Javascript ensures the appropriate problems are shown for the selected set. - - my (@openSets, @initialProblemIDs); - - for my $i (0 .. $#$sets) { - if (between($sets->[$i]->open_date, $sets->[$i]->due_date) - && $sets->[$i]->assignment_type eq 'default' - && @{ $setProblemIds->{ $sets->[$i]->set_id } }) - { - push( - @openSets, - [ - format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id, - data => { problem_ids => encode_json($setProblemIds->{ $sets->[$i]->set_id }) } - ] - ); - @initialProblemIDs = @{ $setProblemIds->{ $sets->[$i]->set_id } } unless @initialProblemIDs; - } - } - - return unless @openSets; +sub can_use ($self, $set, $records) { + return $set->assignment_type eq 'default' && between($set->open_date, $set->due_date); +} +sub print_form ($self, $set, $records, $c) { return $c->c( - $c->tag( - 'p', - $c->maketext( - 'Please choose the set, the problem you would like to copy, ' - . 'and the problem you would like to copy it to.' - ) + $c->tag('p', $c->maketext('Replaces the second problem with a copy of the first.')), + WeBWorK::AchievementItems::form_popup_menu_row( + $c, + id => 'clone_source_problem_id', + label_text => $c->maketext('Problem Number'), + first_item => $c->maketext('Choose problem to copy from.'), + values => [ map { [ $c->maketext('Problem [_1]', $_->problem_id) => $_->problem_id ] } @$records ], ), WeBWorK::AchievementItems::form_popup_menu_row( $c, - id => 'tran_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { - dir => 'ltr', - data => { problems => 'tran_problem_id', problems2 => 'tran_problem_id2' } - } + id => 'clone_dest_problem_id', + label_text => $c->maketext('Problem Number'), + first_item => $c->maketext('Choose problem to replace.'), + values => [ map { [ $c->maketext('Problem [_1]', $_->problem_id) => $_->problem_id ] } @$records ], ), - $c->tag( - 'div', - class => 'row mb-3', - $c->c( - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'tran_problem_id', - values => \@initialProblemIDs, - label_text => $c->maketext('Copy this Problem'), - menu_container_attr => { class => 'col-2 ps-0' }, - add_container => 0 - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'tran_problem_id2', - values => \@initialProblemIDs, - label_text => $c->maketext('To this Problem'), - menu_container_attr => { class => 'col-2 ps-0' }, - add_container => 0 - ) - )->join('') - ) )->join(''); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('tran_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $problemID = $c->param('tran_problem_id'); - return 'You need to input a Problem Number' unless $problemID; - - my $problemID2 = $c->param('tran_problem_id2'); - return 'You need to input a Problem Number' unless $problemID2; - - return 'You need to pick 2 different problems!' if $problemID == $problemID2; - - my $problem = $db->getMergedProblem($userName, $setID, $problemID); - my $problem2 = $db->getUserProblem($userName, $setID, $problemID2); - return 'There was an error accessing those problems.' unless $problem && $problem2; +sub use_item ($self, $set, $records, $c) { + my $sourceID = $c->param('clone_source_problem_id'); + my $destID = $c->param('clone_dest_problem_id'); + unless ($sourceID) { + $c->addbadmessage($c->maketext('Select problem to clone with the [_1].', $self->name)); + return ''; + } + unless ($destID) { + $c->addbadmessage($c->maketext('Select problem to replace with the [_1].', $self->name)); + return ''; + } - # Set the source of the second problem to that of the first problem. - $problem2->source_file($problem->source_file); - $db->putUserProblem($problem2); + my ($sourceProblem, $destProblem); + for (@$records) { + $sourceProblem = $_ if $_->problem_id == $sourceID; + $destProblem = $_ if $_->problem_id == $destID; + last if $sourceProblem && $destProblem; + } + return '' unless $sourceProblem && $destProblem; - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); + my $db = $c->db; + my $userProblem = $db->getUserProblem($destProblem->user_id, $destProblem->set_id, $destProblem->problem_id); + $destProblem->source_file($sourceProblem->source_file); + $userProblem->source_file($destProblem->source_file); + $db->putUserProblem($userProblem); - return; + return $c->maketext("Problem [_1] replaced with problem [_2].", $destID, $sourceID); } 1; diff --git a/lib/WeBWorK/AchievementItems/ExtendDueDate.pm b/lib/WeBWorK/AchievementItems/ExtendDueDate.pm index f645c59734..6ff82ea546 100644 --- a/lib/WeBWorK/AchievementItems/ExtendDueDate.pm +++ b/lib/WeBWorK/AchievementItems/ExtendDueDate.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 24 hours. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(after between); -use WeBWorK::Utils::Sets qw(format_set_name_display); use constant ONE_DAY => 86400; @@ -35,69 +34,56 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; - - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (between($sets->[$i]->open_date, $sets->[$i]->due_date + ONE_DAY) - && $sets->[$i]->assignment_type eq 'default'); - } - - return unless @openSets; +sub can_use ($self, $set, $records) { + return $set->assignment_type eq 'default' && between($set->open_date, $set->due_date + ONE_DAY); +} - return $c->c( - $c->tag('p', $c->maketext('Choose the set whose close date you would like to extend.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'ext_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + my $randomization_statement = after($set->due_date) ? $c->maketext('All problems will be rerandomized.') : ''; + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this assignment to [_1] (an additional 24 hours). [_2]', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}), + $randomization_statement ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('ext_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set && $userSet; +sub use_item ($self, $set, $records, $c) { + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); # Change the seed for all of the problems if the set is currently closed. if (after($set->due_date)) { - for my $problem ($db->getUserProblemsWhere({ user_id => $userName, set_id => $setID })) { - $problem->problem_seed($problem->problem_seed % 2**31 + 1); - $db->putUserProblem($problem); + my @userProblems = + $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $userProblems[$n]->problem_seed($userProblems[$n]->problem_seed % 2**31 + 1); + $records->[$n]->problem_seed($userProblems[$n]->problem_seed); + $db->putUserProblem($userProblems[$n]); } } # Add time to the reduced scoring date if it was defined in the first place - $userSet->reduced_scoring_date($set->reduced_scoring_date + ONE_DAY) if $set->reduced_scoring_date; + if ($set->reduced_scoring_date) { + $set->reduced_scoring_date($set->reduced_scoring_date + ONE_DAY); + $userSet->reduced_scoring_date($set->reduced_scoring_date); + } # Add time to the close date - $userSet->due_date($set->due_date + ONE_DAY); + $set->due_date($set->due_date + ONE_DAY); + $userSet->due_date($set->due_date); # This may require also extending the answer date. - $userSet->answer_date($userSet->due_date) if $userSet->due_date > $set->answer_date; + if ($set->due_date > $set->answer_date) { + $set->answer_date($set->due_date); + $userSet->answer_date($set->answer_date); + } $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext( + 'Closing date of this assignment extended by 24 hours to [_1].', + $c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat}) + ); } 1; diff --git a/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm b/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm index cccefc6f12..0f215cf929 100644 --- a/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm +++ b/lib/WeBWorK/AchievementItems/ExtendDueDateGW.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend the close date on a test -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(between); -use WeBWorK::Utils::Sets qw(format_set_name_display); use constant ONE_DAY => 86400; @@ -33,76 +32,53 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my $db = $c->db; - - my @openGateways; - - # Find the template sets for open tests. - for my $set (@$sets) { - push(@openGateways, [ format_set_name_display($set->set_id) => $set->set_id ]) - if $set->assignment_type =~ /gateway/ - && $set->set_id !~ /,v\d+$/ - && between($set->open_date, $set->due_date); - } - - return unless @openGateways; +sub can_use ($self, $set, $records) { + return + $set->assignment_type =~ /gateway/ + && $set->set_id !~ /,v\d+$/ + && between($set->open_date, $set->due_date + ONE_DAY); +} - return $c->c( - $c->tag('p', $c->maketext('Extend the close date for which test?')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'eddgw_gw_id', - label_text => $c->maketext('Test Name'), - values => \@openGateways, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this test to [_1] (an additional 24 hours).', + $c->formatDateTime($set->due_date + ONE_DAY, $c->ce->{studentDateDisplayFormat}) ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('eddgw_gw_id'); - return 'You need to input a Test Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set && $userSet; +sub use_item ($self, $set, $records, $c) { + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); # Add time to the reduced scoring date, due date, and answer date. - $userSet->reduced_scoring_date($set->reduced_scoring_date() + ONE_DAY) - if defined($set->reduced_scoring_date()) && $set->reduced_scoring_date(); - $userSet->due_date($set->due_date() + ONE_DAY); - $userSet->answer_date($set->answer_date() + ONE_DAY); + if ($set->reduced_scoring_date) { + $set->reduced_scoring_date($set->reduced_scoring_date + ONE_DAY); + $userSet->reduced_scoring_date($set->reduced_scoring_date); + } + $set->due_date($set->due_date + ONE_DAY); + $userSet->due_date($set->due_date); + $set->answer_date($set->answer_date + ONE_DAY); + $userSet->answer_date($set->answer_date); $db->putUserSet($userSet); + # FIXME: Should we add time to each test version, as adding 24 hours to a 1 hour long test + # isn't reasonable. Disabling this for now, will revisit later. # Add time to the reduced scoring date, due date, and answer date for all versions. - my @versions = $db->listSetVersions($userName, $setID); - - for my $version (@versions) { - $set = $db->getSetVersion($userName, $setID, $version); - $set->reduced_scoring_date($set->reduced_scoring_date() + ONE_DAY) - if defined($set->reduced_scoring_date()) && $set->reduced_scoring_date(); - $set->due_date($set->due_date() + ONE_DAY); - $set->answer_date($set->answer_date() + ONE_DAY); - $db->putSetVersion($set); - } - - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + #my @versions = $db->listSetVersions($userName, $setID); + #for my $version (@versions) { + # $set = $db->getSetVersion($userName, $setID, $version); + # $set->reduced_scoring_date($set->reduced_scoring_date() + ONE_DAY) + # if defined($set->reduced_scoring_date()) && $set->reduced_scoring_date(); + # $set->due_date($set->due_date() + ONE_DAY); + # $set->answer_date($set->answer_date() + ONE_DAY); + # $db->putSetVersion($set); + #} + + return $c->maketext('Close date of this test change to [_1].', + $c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat})); } 1; diff --git a/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm b/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm index f3d78333ae..dd929e9ded 100644 --- a/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm +++ b/lib/WeBWorK/AchievementItems/ExtendReducedDate.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 24 hours. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(between); -use WeBWorK::Utils::Sets qw(format_set_name_display); use constant ONE_DAY => 86400; @@ -36,75 +35,50 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; +sub can_use ($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && $set->enable_reduced_scoring + && $set->reduced_scoring_date + && $set->reduced_scoring_date < $set->due_date; - # Nothing to do if reduced scoring is not enabled. - return unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - - for my $i (0 .. $#$sets) { - my $new_date = 0; - if ($sets->[$i]->reduced_scoring_date() && $sets->[$i]->reduced_scoring_date() < $sets->[$i]->due_date()) { - $new_date = $sets->[$i]->reduced_scoring_date() + ONE_DAY; - $new_date = $sets->[$i]->due_date() if $sets->[$i]->due_date() < $new_date; - } - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if ($new_date - && between($sets->[$i]->open_date, $new_date) - && $sets->[$i]->assignment_type eq 'default' - && $sets->[$i]->enable_reduced_scoring); - } + $self->{new_date} = $set->reduced_scoring_date + ONE_DAY; + $self->{new_date} = $set->due_date if $set->due_date < $self->{new_date}; + return between($set->open_date, $self->{new_date}); +} - return unless @openSets; +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + q{This item won't work unless your instructor enables the reduced scoring feature. } + . 'Let your instructor know that you recieved this message.' + ) + ) unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - return $c->c( - $c->tag( - 'p', - $c->maketext('Choose the assignment whose reduced scoring date you would like to extend by 24 hours.') - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'ext_reduced_set_id', - label_text => $c->maketext('Assignment Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } + return $c->tag( + 'p', + $c->maketext( + 'Extend the reduced scoring date to [_1] (an additional 24 hours).', + $c->formatDateTime($self->{new_date}, $c->ce->{studentDateDisplayFormat}) ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - # Nothing to do if reduced scoring is not enabled. - return 'Reduced scoring disabled.' unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; +sub use_item ($self, $set, $records, $c) { + return '' unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('ext_reduced_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set && $userSet; - - # Add time to the reduced scoring date, keeping in mind this cannot extend past the due date. - my $new_date = $set->reduced_scoring_date() + ONE_DAY; - $new_date = $set->due_date() if $set->due_date() < $new_date; - $userSet->reduced_scoring_date($new_date); + $set->reduced_scoring_date($self->{new_date}); + $userSet->reduced_scoring_date($set->reduced_scoring_date); $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext( + 'Reduced scoring date of this assignment exted by 24 hours to [_1].', + $c->formatDateTime($self->{new_date}, $c->ce->{studentDateDisplayFormat}) + ); } 1; diff --git a/lib/WeBWorK/AchievementItems/FullCreditProb.pm b/lib/WeBWorK/AchievementItems/FullCreditProb.pm index 8cf759d30f..02593b938d 100644 --- a/lib/WeBWorK/AchievementItems/FullCreditProb.pm +++ b/lib/WeBWorK/AchievementItems/FullCreditProb.pm @@ -18,11 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to give full credit on a single problem -use Mojo::JSON qw(encode_json); - -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x wwRound); use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -32,84 +29,57 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # Construct a dropdown with open sets and another with problems. - # Javascript ensures the appropriate problems are shown for the selected set. - - my (@openSets, @initialProblemIDs); +sub can_use ($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && after($set->open_date); - for my $i (0 .. $#$sets) { - if (after($sets->[$i]->open_date) - && $sets->[$i]->assignment_type eq 'default' - && @{ $setProblemIds->{ $sets->[$i]->set_id } }) - { - push( - @openSets, - [ - format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id, - data => { problem_ids => encode_json($setProblemIds->{ $sets->[$i]->set_id }) } - ] - ); - @initialProblemIDs = @{ $setProblemIds->{ $sets->[$i]->set_id } } unless @initialProblemIDs; - } - } + my @problems = grep { $_->status < 1 } @$records; + return 0 unless @problems; - return unless @openSets; - - return $c->c( - $c->tag( - 'p', - $c->maketext( - 'Please choose the set name and problem number of the question which should be given full credit.') - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'fcp_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr', data => { problems => 'fcp_problem_id' } } - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'fcp_problem_id', - label_text => $c->maketext('Problem Number'), - values => \@initialProblemIDs, - menu_container_attr => { class => 'col-3' } - ) - )->join(''); + $self->{usableProblems} = \@problems; + return 1; } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('fcp_set_id'); - return 'You need to input a Set Name' unless defined $setID; +sub print_form ($self, $set, $records, $c) { + return WeBWorK::AchievementItems::form_popup_menu_row( + $c, + id => 'full_cred_problem_id', + label_text => $c->maketext('Problem Number'), + first_item => $c->maketext('Choose problem to give full credit.'), + values => [ + map { [ $c->maketext('Problem [_1] ([_2]% to 100%)', $_->problem_id, 100 * wwRound(2, $_->status)) => + $_->problem_id ] } @{ $self->{usableProblems} } + ], + ); +} - my $problemID = $c->param('fcp_problem_id'); - return 'You need to input a Problem Number' unless $problemID; +sub use_item ($self, $set, $records, $c) { + my $problemID = $c->param('full_cred_problem_id'); + unless ($problemID) { + $c->addbadmessage($c->maketext('Select problem to give 100% to the [_1].', $self->name)); + return ''; + } - my $problem = $db->getUserProblem($userName, $setID, $problemID); - return 'There was an error accessing that problem.' unless $problem; + my $problem; + for (@$records) { + if ($_->problem_id == $problemID) { + $problem = $_; + last; + } + } + return '' unless $problem; - # Set the status and sub_status of the problem to one. + # Increase status to 100%. + my $db = $c->db; + my $userProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); $problem->status(1); $problem->sub_status(1); - $db->putUserProblem($problem); - - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); + $userProblem->status(1); + $userProblem->sub_status(1); + $db->putUserProblem($userProblem); - return; + return $c->maketext('Problem number [_1] increased to 100%.', $problemID); } 1; diff --git a/lib/WeBWorK/AchievementItems/FullCreditSet.pm b/lib/WeBWorK/AchievementItems/FullCreditSet.pm index 21bc077285..0437357cdd 100644 --- a/lib/WeBWorK/AchievementItems/FullCreditSet.pm +++ b/lib/WeBWorK/AchievementItems/FullCreditSet.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to give half credit on all problems in a homework set. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x wwRound); use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -30,59 +29,38 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; +sub can_use ($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && after($set->open_date); - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (after($sets->[$i]->open_date) && $sets->[$i]->assignment_type eq 'default'); + my $total = 0; + my $grade = 0; + for my $problem (@$records) { + $grade += $problem->status * $problem->value; + $total += $problem->value; } + $self->{old_grade} = 100 * wwRound(2, $grade / $total); + return $self->{old_grade} == 100 ? 0 : 1; +} - return unless @openSets; - - return $c->c( - $c->tag('p', $c->maketext('Please choose the set for which all problems should be given full credit.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'fcs_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } - ) - )->join(''); +sub print_form ($self, $set, $records, $c) { + return $c->tag('p', $c->maketext(q(Increase this assignment's grade from [_1]% to 100%.), $self->{old_grade})); } -sub use_item ($self, $userName, $c) { +sub use_item ($self, $set, $records, $c) { my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - my $setID = $c->param('fcs_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my @probIDs = $db->listUserProblems($userName, $setID); - - for my $probID (@probIDs) { - my $problem = $db->getUserProblem($userName, $setID, $probID); - - # Set status and sub_status to 1. - $problem->status(1); - $problem->sub_status(1); - $db->putUserProblem($problem); + my @userProblems = $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $records->[$n]->status(1); + $records->[$n]->sub_status(1); + $userProblems[$n]->status(1); + $userProblems[$n]->sub_status(1); + $db->putUserProblem($userProblems[$n]); } - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext(q(Assignment's grade increased from [_1]% to 100%.), $self->{old_grade}); } 1; diff --git a/lib/WeBWorK/AchievementItems/HalfCreditProb.pm b/lib/WeBWorK/AchievementItems/HalfCreditProb.pm index f607a8bb01..80ae83b80d 100644 --- a/lib/WeBWorK/AchievementItems/HalfCreditProb.pm +++ b/lib/WeBWorK/AchievementItems/HalfCreditProb.pm @@ -18,11 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to give half credit on a single problem. -use Mojo::JSON qw(encode_json); - -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x wwRound); use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -32,87 +29,60 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # Construct a dropdown with open sets and another with problems. - # Javascript ensures the appropriate problems are shown for the selected set. - - my (@openSets, @initialProblemIDs); - - for my $i (0 .. $#$sets) { - if (after($sets->[$i]->open_date) - && $sets->[$i]->assignment_type eq 'default' - && @{ $setProblemIds->{ $sets->[$i]->set_id } }) - { - push( - @openSets, - [ - format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id, - data => { problem_ids => encode_json($setProblemIds->{ $sets->[$i]->set_id }) } - ] - ); - @initialProblemIDs = @{ $setProblemIds->{ $sets->[$i]->set_id } } unless @initialProblemIDs; - } - } +sub can_use($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && after($set->open_date); - return unless @openSets; - - return $c->c( - $c->tag( - 'p', - $c->maketext( - 'Please choose the assignment name and problem number of the question to add half credit to.') - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'hcp_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr', data => { problems => 'hcp_problem_id' } } - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'hcp_problem_id', - values => \@initialProblemIDs, - label_text => $c->maketext('Problem Number'), - menu_container_attr => { class => 'col-3' } - ) - )->join(''); + $self->{unfinishedProblems} = [ grep { $_->status < 1 } @$records ]; + return @{ $self->{unfinishedProblems} } ? 1 : 0; } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('hcp_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $problemID = $c->param('hcp_problem_id'); - return 'You need to input a Problem Number' unless $problemID; - - my $problem = $db->getUserProblem($userName, $setID, $problemID); - return 'There was an error accessing that problem.' unless $problem; - - # Add .5 to grade with max of 1 - my $new_status = $problem->status + 0.5; - $new_status = 1 if $new_status > 1; - $problem->status($new_status); - $problem->sub_status($new_status); - - $db->putUserProblem($problem); +sub print_form ($self, $set, $records, $c) { + return WeBWorK::AchievementItems::form_popup_menu_row( + $c, + id => 'half_cred_problem_id', + label_text => $c->maketext('Problem Number'), + first_item => $c->maketext('Choose problem to increase 50%.'), + values => [ + map { [ + $c->maketext( + 'Problem [_1] ([_2]% to [_3]%)', + $_->problem_id, + 100 * wwRound(2, $_->status), + 100 * wwRound(2, $_->status < 0.5 ? $_->status + 0.5 : 1) + ) => $_->problem_id + ] } @{ $self->{unfinishedProblems} } + ], + ); +} - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); +sub use_item ($self, $set, $records, $c) { + my $problemID = $c->param('half_cred_problem_id'); + unless ($problemID) { + $c->addbadmessage($c->maketext('Select problem to add 50% with the [_1].', $self->name)); + return ''; + } - return; + my $problem; + for (@$records) { + if ($_->problem_id == $problemID) { + $problem = $_; + last; + } + } + return '' unless $problem; + + # Increase status to 100%. + my $db = $c->db; + my $userProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); + $problem->status($problem->status > 0.5 ? 1 : $problem->status + 0.5); + $problem->sub_status($problem->status); + $userProblem->status($problem->status); + $userProblem->sub_status($problem->status); + $db->putUserProblem($userProblem); + + return $c->maketext('Problem number [_1] increased to [_2]%.', $problemID, 100 * wwRound(2, $problem->status)); } 1; diff --git a/lib/WeBWorK/AchievementItems/HalfCreditSet.pm b/lib/WeBWorK/AchievementItems/HalfCreditSet.pm index c70cfa73c4..a93ef346e0 100644 --- a/lib/WeBWorK/AchievementItems/HalfCreditSet.pm +++ b/lib/WeBWorK/AchievementItems/HalfCreditSet.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to give half credit on all problems in a homework set. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x wwRound); use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -30,64 +29,47 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; - - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (after($sets->[$i]->open_date) && $sets->[$i]->assignment_type eq 'default'); +sub can_use($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && after($set->open_date); + + my $total = 0; + my $old_grade = 0; + my $new_grade = 0; + for my $problem (@$records) { + $old_grade += $problem->status * $problem->value; + $new_grade += ($problem->status > 0.5 ? 1 : $problem->status + 0.5) * $problem->value; + $total += $problem->value; } + $self->{old_grade} = 100 * wwRound(2, $old_grade / $total); + $self->{new_grade} = 100 * wwRound(2, $new_grade / $total); + return $self->{old_grade} == 100 ? 0 : 1; +} - return unless @openSets; - - return $c->c( - $c->tag( - 'p', $c->maketext('Please choose the assignment for which all problems should have half credit added.') - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'hcs_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + q(Increase this assignment's grade from [_1]% to [_2]%.), + $self->{old_grade}, $self->{new_grade} ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { +sub use_item ($self, $set, $records, $c) { my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - my $setID = $c->param('hcs_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my @probIDs = $db->listUserProblems($userName, $setID); - - for my $probID (@probIDs) { - my $problem = $db->getUserProblem($userName, $setID, $probID); - - # Add .5 to grade with max of 1. - my $new_status = $problem->status + 0.5; - $new_status = 1 if $new_status > 1; - $problem->status($new_status); - $problem->sub_status($new_status); - - $db->putUserProblem($problem); + my @userProblems = $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $records->[$n]->status($records->[$n]->status > 0.5 ? 1 : $records->[$n]->status + 0.5); + $records->[$n]->sub_status($records->[$n]->status); + $userProblems[$n]->status($records->[$n]->status); + $userProblems[$n]->sub_status($records->[$n]->status); + $db->putUserProblem($userProblems[$n]); } - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext(q(Assignment's grade increased from [_1] to [_2].), $self->{old_grade}, $self->{new_grade}); } 1; diff --git a/lib/WeBWorK/AchievementItems/NoReducedCred.pm b/lib/WeBWorK/AchievementItems/NoReducedCred.pm index cc302dcd0b..01a5db47d6 100644 --- a/lib/WeBWorK/AchievementItems/NoReducedCred.pm +++ b/lib/WeBWorK/AchievementItems/NoReducedCred.pm @@ -19,9 +19,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to remove reduce credit scoring period from a set. # Reduced scoring needs to be enabled for this item to be useful. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(between); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -34,67 +33,48 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; - - # Nothing to do if reduced scoring is not enabled. - return unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - - # Only show open sets that have reduced scoring enabled. - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (between($sets->[$i]->open_date, $sets->[$i]->due_date) - && $sets->[$i]->assignment_type eq 'default' - && $sets->[$i]->enable_reduced_scoring); - } - - return unless @openSets; +sub can_use ($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && $set->enable_reduced_scoring + && $set->reduced_scoring_date + && $set->reduced_scoring_date < $set->due_date + && between($set->open_date, $set->due_date); +} - return $c->c( - $c->tag('p', $c->maketext('Choose the assignment to remove the reduced scoring pentaly from.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'no_reduce_set_id', - label_text => $c->maketext('Assignment Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + q{This item won't work unless your instructor enables the reduced scoring feature. } + . 'Let your instructor know that you recieved this message.' + ) + ) unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; + + return $c->tag( + 'p', + $c->maketext( + 'Remove the reduced scoring pentaly from this assignment. Problems submitted before ' + . 'the close date on [_1] will earn full credit. Any problems that have already been ' + . 'penalized will have to be resubmitted for full credit.', + $c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat}) ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data +sub use_item ($self, $set, $records, $c) { + return '' unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - return q{This item won't work unless your instructor enables the reduced scoring feature. } - . 'Let your instructor know that you received this message.' - unless $ce->{pg}{ansEvalDefaults}{enableReducedScoring}; + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return "No achievement data?!?!?!" unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('no_reduce_set_id'); - return "You need to input a Set Name" unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return "Couldn't find that set!" unless $set && $userSet; - - # Remove reduced scoring from the set and set the reduced scoring date to be the due date. + $set->enable_reduced_scoring(0); + $set->reduced_scoring_date($set->due_date); $userSet->enable_reduced_scoring(0); - $userSet->reduced_scoring_date($set->due_date()); + $userSet->reduced_scoring_date($set->due_date); $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext('Reduced scoring pentaly removed.'); } 1; diff --git a/lib/WeBWorK/AchievementItems/ReducedCred.pm b/lib/WeBWorK/AchievementItems/ReducedCred.pm index 297c275d7e..6d70a6f687 100644 --- a/lib/WeBWorK/AchievementItems/ReducedCred.pm +++ b/lib/WeBWorK/AchievementItems/ReducedCred.pm @@ -19,9 +19,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 24 hours for reduced credit # Reduced scoring needs to be enabled for this item to work. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(after between); -use WeBWorK::Utils::Sets qw(format_set_name_display); use constant ONE_DAY => 86400; @@ -37,75 +36,73 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; - - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (between($sets->[$i]->open_date, $sets->[$i]->due_date + ONE_DAY) - && $sets->[$i]->assignment_type eq 'default'); - } +sub can_use ($self, $set, $records) { + return $set->assignment_type eq 'default' && between($set->open_date, $set->due_date + ONE_DAY); +} - return unless @openSets; +sub print_form ($self, $set, $records, $c) { + my $ce = $c->ce; - return $c->c( - $c->tag('p', $c->maketext('Choose the set which you would like to enable partial credit for.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'red_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } + return $c->tag( + 'p', + $c->maketext( + q{This item won't work unless your instructor enables the reduced scoring feature. } + . 'Let your instructor know that you received this message.' ) - )->join(''); + ) unless $ce->{pg}{ansEvalDefaults}{enableReducedScoring}; + + my $randomization_statement = after($set->due_date) ? $c->maketext('All problems will be rerandomized.') : ''; + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this assignment to [_1] (an additional 24 hours). Any submissions during ' + . 'this additional time will be reducend and are worth [_2]% of their full value. [_3]', + $c->formatDateTime($set->due_date + ONE_DAY, $ce->{studentDateDisplayFormat}), + 100 * $ce->{pg}{ansEvalDefaults}{reducedScoringValue}, + $randomization_statement + ) + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; +sub use_item ($self, $set, $records, $c) { my $ce = $c->ce; + my $db = $c->db; - # Validate data - - return q{This item won't work unless your instructor enables the reduced scoring feature. } - . 'Let your instructor know that you received this message.' - unless $ce->{pg}{ansEvalDefaults}{reducedScoringPeriod}; - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return "No achievement data?!?!?!" unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('red_set_id'); - return "You need to input a Set Name" unless defined $setID; + # Still need to double check reduced scoring is enabled. + return '' unless $ce->{pg}{ansEvalDefaults}{enableReducedScoring}; - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return "Couldn't find that set!" unless $set && $userSet; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); # Change the seed for all of the problems if the set is currently closed. if (after($set->due_date)) { - for my $problem ($db->getUserProblemsWhere({ user_id => $userName, set_id => $setID })) { - $problem->problem_seed($problem->problem_seed % 2**31 + 1); - $db->putUserProblem($problem); + my @userProblems = + $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $userProblems[$n]->problem_seed($userProblems[$n]->problem_seed % 2**31 + 1); + $records->[$n]->problem_seed($userProblems[$n]->problem_seed); + $db->putUserProblem($userProblems[$n]); } } # Either there is already a valid reduced scoring date, or set the reduced scoring date to the close date. - $userSet->reduced_scoring_date($set->due_date) - unless ($set->reduced_scoring_date && ($set->reduced_scoring_date < $set->due_date)); + unless ($set->reduced_scoring_date && $set->reduced_scoring_date < $set->due_date) { + $set->reduced_scoring_date($set->due_date); + $userSet->reduced_scoring_date($set->reduced_scoring_date); + } + $set->enable_reduced_scoring(1); $userSet->enable_reduced_scoring(1); # Add time to the close date - $userSet->due_date($set->due_date + ONE_DAY); + $set->due_date($set->due_date + ONE_DAY); + $userSet->due_date($set->due_date); # This may require also extending the answer date. - $userSet->answer_date($userSet->due_date) if ($userSet->due_date > $set->answer_date); + if ($set->due_date > $set->answer_date) { + $set->answer_date($set->due_date); + $userSet->answer_date($set->answer_date); + } $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext('Close date changed by 24 hours to [_1].', + $c->formatDateTime($set->due_date, $ce->{studentDateDisplayFormat})); } 1; diff --git a/lib/WeBWorK/AchievementItems/ResetIncorrectAttempts.pm b/lib/WeBWorK/AchievementItems/ResetIncorrectAttempts.pm index 6462fbae9a..df919aaaca 100644 --- a/lib/WeBWorK/AchievementItems/ResetIncorrectAttempts.pm +++ b/lib/WeBWorK/AchievementItems/ResetIncorrectAttempts.pm @@ -18,11 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to reset number of incorrect attempts. -use Mojo::JSON qw(encode_json); - -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(between); -use WeBWorK::Utils::Sets qw(format_set_name_display); sub new ($class) { return bless { @@ -32,85 +29,56 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # Construct a dropdown with open sets and another with problems. - # Javascript ensures the appropriate problems are shown for the selected set. - - my (@openSets, @initialProblemIDs); - - for my $i (0 .. $#$sets) { - if (between($sets->[$i]->open_date, $sets->[$i]->due_date) - && $sets->[$i]->assignment_type eq 'default' - && @{ $setProblemIds->{ $sets->[$i]->set_id } }) - { - push( - @openSets, - [ - format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id, - data => { problem_ids => encode_json($setProblemIds->{ $sets->[$i]->set_id }) } - ] - ); - @initialProblemIDs = @{ $setProblemIds->{ $sets->[$i]->set_id } } unless @initialProblemIDs; - } - } - - return unless @openSets; +sub can_use ($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && between($set->open_date, $set->due_date); - return $c->c( - $c->tag( - 'p', - $c->maketext( - 'Please choose the set name and problem number of the question which ' - . 'should have its incorrect attempt count reset.' - ) - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'ria_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr', data => { problems => 'ria_problem_id' } } - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'ria_problem_id', - label_text => $c->maketext('Problem Number'), - values => \@initialProblemIDs, - menu_container_attr => { class => 'col-3' } - ) - )->join(''); + $self->{usableProblems} = [ grep { $_->max_attempts > 0 && $_->num_incorrect > 0 && $_->status < 1 } @$records ]; + return @{ $self->{usableProblems} } ? 1 : 0; } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('ria_set_id'); - return 'You need to input a Set Name' unless defined $setID; +sub print_form ($self, $set, $records, $c) { + return WeBWorK::AchievementItems::form_popup_menu_row( + $c, + id => 'reset_attempts_problem_id', + label_text => $c->maketext('Problem Number'), + first_item => $c->maketext('Choose problem to reset incorrect attempts.'), + values => [ + map { [ + $c->maketext('Problem [_1] ([_2] of [_3] used)', + $_->problem_id, $_->num_incorrect, $_->max_attempts) => $_->problem_id + ] } @{ $self->{usableProblems} } + ], + ); +} - my $problemID = $c->param('ria_problem_id'); - return 'You need to input a Problem Number' unless $problemID; +# use_item is called after print_form returns a non-empty form. +# So we can assume that $set and $records have already been validated. +sub use_item ($self, $set, $records, $c) { + my $problemID = $c->param('reset_attempts_problem_id'); + unless ($problemID) { + $c->addbadmessage($c->maketext('Select problem to reset with the [_1].', $self->name)); + return ''; + } - my $problem = $db->getUserProblem($userName, $setID, $problemID); - return 'There was an error accessing that problem.' unless $problem; + my $problem; + for (@$records) { + if ($_->problem_id == $problemID) { + $problem = $_; + last; + } + } + return '' unless $problem; # Set the number of incorrect attempts to zero. + my $db = $c->db; + my $userProblem = $db->getUserProblem($problem->user_id, $problem->set_id, $problem->problem_id); $problem->num_incorrect(0); - $db->putUserProblem($problem); - - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); + $userProblem->num_incorrect(0); + $db->putUserProblem($userProblem); - return; + return $c->maketext('Reset the number of attempts on problem [_1].', $problemID); } 1; diff --git a/lib/WeBWorK/AchievementItems/ResurrectGW.pm b/lib/WeBWorK/AchievementItems/ResurrectGW.pm index eb7286f3ec..6d47348914 100644 --- a/lib/WeBWorK/AchievementItems/ResurrectGW.pm +++ b/lib/WeBWorK/AchievementItems/ResurrectGW.pm @@ -18,9 +18,10 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend the due date on a gateway -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); -use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); +use WeBWorK::Utils qw(x); +use WeBWorK::Utils::DateTime qw(between); + +use constant ONE_DAY => 86400; sub new ($class) { return bless { @@ -33,63 +34,38 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my $db = $c->db; - - my @closed_gateway_sets; - - # Find the template sets of gateway quizzes. - for my $set (@$sets) { - push(@closed_gateway_sets, [ format_set_name_display($set->set_id) => $set->set_id ]) - if $set->assignment_type =~ /gateway/ - && $set->set_id !~ /,v\d+$/ - && (after($set->due_date) - || ($set->reduced_scoring_date && after($set->reduced_scoring_date))); - } - - return unless @closed_gateway_sets; +sub can_use($self, $set, $records) { + return $set->assignment_type =~ /gateway/ && between($set->due_date, $set->due_date + ONE_DAY); + # TODO: Check if a new version can be created, and only allow using this reward in that case. +} - return $c->c( - $c->tag('p', $c->maketext('Resurrect which test?')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'resgw_gw_id', - label_text => $c->maketext('Test Name'), - values => \@closed_gateway_sets, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + 'Reopen this test for the next 24 hours. This item does not allow you to take any additional ' + . 'versions of the test.' ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('resgw_gw_id'); - return 'You need to input a Test Name' unless defined $setID; - - my $set = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set; +sub use_item ($self, $set, $records, $c) { + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); # Add time to the reduced scoring date, due date, and answer date. - $set->reduced_scoring_date(time + 86400) if defined($set->reduced_scoring_date()) && $set->reduced_scoring_date(); - $set->due_date(time + 86400); - $set->answer_date(time + 86400); - $db->putUserSet($set); - - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + if ($set->reduced_scoring_date) { + $set->reduced_scoring_date($set->reduced_scoring_date + ONE_DAY); + $userSet->reduced_scoring_date($set->reduced_scoring_date); + } + $set->due_date($set->due_date + ONE_DAY); + $userSet->due_date($set->due_date); + $set->answer_date($set->answer_date + ONE_DAY); + $userSet->answer_date($set->answer_date); + $db->putUserSet($userSet); + + return $c->maketext('Close date of this test extended 24 hours to [_1].', + $c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat})); } 1; diff --git a/lib/WeBWorK/AchievementItems/ResurrectHW.pm b/lib/WeBWorK/AchievementItems/ResurrectHW.pm index 323c66020d..63a0f76f6b 100644 --- a/lib/WeBWorK/AchievementItems/ResurrectHW.pm +++ b/lib/WeBWorK/AchievementItems/ResurrectHW.pm @@ -18,9 +18,10 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to resurrect a homework for 24 hours -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); -use WeBWorK::Utils::DateTime qw(after); -use WeBWorK::Utils::Sets qw(format_set_name_display); +use WeBWorK::Utils qw(x); +use WeBWorK::Utils::DateTime qw(between); + +use constant ONE_DAY => 86400; sub new ($class) { return bless { @@ -30,70 +31,49 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # List all of the sets that are closed or past their reduced scoring date. - - my @closedSets; - - for my $i (0 .. $#$sets) { - push(@closedSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if $sets->[$i]->assignment_type eq 'default' - && (after($sets->[$i]->due_date) - || ($sets->[$i]->reduced_scoring_date && after($sets->[$i]->reduced_scoring_date))); - } - - return unless @closedSets; - - return $c->c( - $c->tag('p', $c->maketext('Choose the set which you would like to resurrect.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'res_set_id', - label_text => $c->maketext('Set Name'), - values => \@closedSets, - menu_attr => { dir => 'ltr' } - ) - )->join(''); +sub can_use($self, $set, $records) { + return $set->assignment_type eq 'default' && between($set->due_date, $set->due_date + ONE_DAY); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('res_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $set = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set; - - # Set a new reduced scoring date, close date, and answer date for the student. - $set->reduced_scoring_date(time + 86400); - $set->due_date(time + 86400); - $set->answer_date(time + 86400); - $db->putUserSet($set); - - my @probIDs = $db->listUserProblems($userName, $setID); +sub print_form ($self, $set, $records, $c) { + return $c->tag('p', + $c->maketext('Reopen this homework assignment for the next 24 hours. All problems will be rerandomized.')); +} - # Change the seed for all of the problems in the set. - for my $probID (@probIDs) { - my $problem = $db->getUserProblem($userName, $setID, $probID); - $problem->problem_seed($problem->problem_seed + 100); - $db->putUserProblem($problem); +sub use_item ($self, $set, $records, $c) { + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); + + # Change the seed for all of the problems if the set is currently closed. + if (after($set->due_date)) { + my @userProblems = + $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $userProblems[$n]->problem_seed($userProblems[$n]->problem_seed % 2**31 + 1); + $records->[$n]->problem_seed($userProblems[$n]->problem_seed); + $db->putUserProblem($userProblems[$n]); + } } - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); + # Add time to the reduced scoring date if it was defined in the first place + if ($set->reduced_scoring_date) { + $set->reduced_scoring_date($set->reduced_scoring_date + ONE_DAY); + $userSet->reduced_scoring_date($set->reduced_scoring_date); + } + # Add time to the close date + $set->due_date($set->due_date + ONE_DAY); + $userSet->due_date($set->due_date); + # This may require also extending the answer date. + if ($set->due_date > $set->answer_date) { + $set->answer_date($set->due_date); + $userSet->answer_date($set->answer_date); + } + $db->putUserSet($userSet); - return; + return $c->maketext( + 'Closing date of this assignment extended by 24 hours to [_1].', + $c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat}) + ); } 1; diff --git a/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm b/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm index ccf960321d..9e299445b8 100644 --- a/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm +++ b/lib/WeBWorK/AchievementItems/SuperExtendDueDate.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 48 hours. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(after between); -use WeBWorK::Utils::Sets qw(format_set_name_display); use constant TWO_DAYS => 172800; @@ -35,69 +34,56 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; - - for my $i (0 .. $#$sets) { - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if (between($sets->[$i]->open_date, $sets->[$i]->due_date + TWO_DAYS) - && $sets->[$i]->assignment_type eq 'default'); - } - - return unless @openSets; +sub can_use ($self, $set, $records) { + return $set->assignment_type eq 'default' && between($set->open_date, $set->due_date + TWO_DAYS); +} - return $c->c( - $c->tag('p', $c->maketext('Choose the set whose close date you would like to extend.')), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'super_ext_set_id', - label_text => $c->maketext('Set Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } +sub print_form ($self, $set, $records, $c) { + my $randomization_statement = after($set->due_date) ? $c->maketext('All problems will be rerandomized.') : ''; + return $c->tag( + 'p', + $c->maketext( + 'Extend the close date of this assignment to [_1] (an additional 48 hours). [_2]', + $c->formatDateTime($set->due_date + TWO_DAYS, $c->ce->{studentDateDisplayFormat}), + $randomization_statement ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; - - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('super_ext_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set && $userSet; +sub use_item ($self, $set, $records, $c) { + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); # Change the seed for all of the problems if the set is currently closed. if (after($set->due_date)) { - for my $problem ($db->getUserProblemsWhere({ user_id => $userName, set_id => $setID })) { - $problem->problem_seed($problem->problem_seed % 2**31 + 1); - $db->putUserProblem($problem); + my @userProblems = + $db->getUserProblemsWhere({ user_id => $set->user_id, set_id => $set->set_id }, 'problem_id'); + for my $n (0 .. $#userProblems) { + $userProblems[$n]->problem_seed($userProblems[$n]->problem_seed % 2**31 + 1); + $records->[$n]->problem_seed($userProblems[$n]->problem_seed); + $db->putUserProblem($userProblems[$n]); } } # Add time to the reduced scoring date if it was defined in the first place - $userSet->reduced_scoring_date($set->reduced_scoring_date + TWO_DAYS) if $set->reduced_scoring_date; + if ($set->reduced_scoring_date) { + $set->reduced_scoring_date($set->reduced_scoring_date + TWO_DAYS); + $userSet->reduced_scoring_date($set->reduced_scoring_date); + } # Add time to the close date - $userSet->due_date($set->due_date + TWO_DAYS); + $set->due_date($set->due_date + TWO_DAYS); + $userSet->due_date($set->due_date); # This may require also extending the answer date. - $userSet->answer_date($userSet->due_date) if ($userSet->due_date > $set->answer_date); + if ($set->due_date > $set->answer_date) { + $set->answer_date($set->due_date); + $userSet->answer_date($set->answer_date); + } $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext( + 'Closing date of this assignment extended by 48 hours too [_1].', + $c->formatDateTime($set->due_date, $c->ce->{studentDateDisplayFormat}) + ); } 1; diff --git a/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm b/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm index 5996b58984..3071340d11 100644 --- a/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm +++ b/lib/WeBWorK/AchievementItems/SuperExtendReducedDate.pm @@ -18,9 +18,8 @@ use Mojo::Base 'WeBWorK::AchievementItems', -signatures; # Item to extend a close date by 48 hours. -use WeBWorK::Utils qw(x nfreeze_base64 thaw_base64); +use WeBWorK::Utils qw(x); use WeBWorK::Utils::DateTime qw(between); -use WeBWorK::Utils::Sets qw(format_set_name_display); use constant TWO_DAYS => 172800; @@ -36,75 +35,50 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - my @openSets; +sub can_use ($self, $set, $records) { + return 0 + unless $set->assignment_type eq 'default' + && $set->enable_reduced_scoring + && $set->reduced_scoring_date + && $set->reduced_scoring_date < $set->due_date; - # Nothing to do if reduced scoring is not enabled. - return unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - - for my $i (0 .. $#$sets) { - my $new_date = 0; - if ($sets->[$i]->reduced_scoring_date() && $sets->[$i]->reduced_scoring_date() < $sets->[$i]->due_date()) { - $new_date = $sets->[$i]->reduced_scoring_date() + TWO_DAYS; - $new_date = $sets->[$i]->due_date() if $sets->[$i]->due_date() < $new_date; - } - push(@openSets, [ format_set_name_display($sets->[$i]->set_id) => $sets->[$i]->set_id ]) - if ($new_date - && between($sets->[$i]->open_date, $new_date) - && $sets->[$i]->assignment_type eq 'default' - && $sets->[$i]->enable_reduced_scoring); - } + $self->{new_date} = $set->reduced_scoring_date + TWO_DAYS; + $self->{new_date} = $set->due_date if $set->due_date < $self->{new_date}; + return between($set->open_date, $self->{new_date}); +} - return unless @openSets; +sub print_form ($self, $set, $records, $c) { + return $c->tag( + 'p', + $c->maketext( + q{This item won't work unless your instructor enables the reduced scoring feature. } + . 'Let your instructor know that you recieved this message.' + ) + ) unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - return $c->c( - $c->tag( - 'p', - $c->maketext('Choose the assignment whose reduced scoring date you would like to extend by 48 hours.') - ), - WeBWorK::AchievementItems::form_popup_menu_row( - $c, - id => 'super_ext_reduced_set_id', - label_text => $c->maketext('Assignment Name'), - values => \@openSets, - menu_attr => { dir => 'ltr' } + return $c->tag( + 'p', + $c->maketext( + 'Extend the reduced scoring date to [_1] (an additional 48 hours).', + $c->formatDateTime($self->{new_date}, $c->ce->{studentDateDisplayFormat}) ) - )->join(''); + ); } -sub use_item ($self, $userName, $c) { - my $db = $c->db; - my $ce = $c->ce; - - # Validate data - - # Nothing to do if reduced scoring is not enabled. - return 'Reduce scoring disabled.' unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; +sub use_item ($self, $set, $records, $c) { + return '' unless $c->{ce}->{pg}{ansEvalDefaults}{enableReducedScoring}; - my $globalUserAchievement = $db->getGlobalUserAchievement($userName); - return 'No achievement data?!?!?!' unless $globalUserAchievement->frozen_hash; + my $db = $c->db; + my $userSet = $db->getUserSet($set->user_id, $set->set_id); - my $globalData = thaw_base64($globalUserAchievement->frozen_hash); - return "You are $self->{id} trying to use an item you don't have" unless $globalData->{ $self->{id} }; - - my $setID = $c->param('super_ext_reduced_set_id'); - return 'You need to input a Set Name' unless defined $setID; - - my $set = $db->getMergedSet($userName, $setID); - my $userSet = $db->getUserSet($userName, $setID); - return q{Couldn't find that set!} unless $set && $userSet; - - # Add time to the reduced scoring date, keeping in mind this cannot extend past the due date. - my $new_date = $set->reduced_scoring_date() + TWO_DAYS; - $new_date = $set->due_date() if $set->due_date() < $new_date; - $userSet->reduced_scoring_date($new_date); + $set->reduced_scoring_date($self->{new_date}); + $userSet->reduced_scoring_date($set->reduced_scoring_date); $db->putUserSet($userSet); - $globalData->{ $self->{id} }--; - $globalUserAchievement->frozen_hash(nfreeze_base64($globalData)); - $db->putGlobalUserAchievement($globalUserAchievement); - - return; + return $c->maketext( + 'Reduced scoring date of this assignment exted by 48 hours to [_1].', + $c->formatDateTime($self->{new_date}, $c->ce->{studentDateDisplayFormat}) + ); } 1; diff --git a/lib/WeBWorK/AchievementItems/Surprise.pm b/lib/WeBWorK/AchievementItems/Surprise.pm index 299634df28..37dbd04669 100644 --- a/lib/WeBWorK/AchievementItems/Surprise.pm +++ b/lib/WeBWorK/AchievementItems/Surprise.pm @@ -28,10 +28,11 @@ sub new ($class) { }, $class; } -sub print_form ($self, $sets, $setProblemIds, $c) { - # The form opens the file "suprise_message.txt" in the achievements - # folder and prints the contents of the file. +sub can_use ($self, $set, $records) { return 1; } +sub print_form ($self, $set, $records, $c) { + # The form opens the file "surprise_message.txt" in the achievements + # folder and prints the contents of the file. open my $MESSAGE, '<', "$c->{ce}{courseDirs}{achievements}/surprise_message.txt" or return $c->tag('p', $c->maketext(q{I couldn't find the file [ACHIEVEMENT_DIR]/surprise_message.txt!})); local $/ = undef; @@ -41,7 +42,7 @@ sub print_form ($self, $sets, $setProblemIds, $c) { return $c->tag('div', $c->b($message)); } -sub use_item ($self, $userName, $c) { +sub use_item ($self, $set, $records, $c) { # This doesn't do anything. } diff --git a/lib/WeBWorK/ContentGenerator/Achievements.pm b/lib/WeBWorK/ContentGenerator/Achievements.pm index 9d08fc3d78..613f509054 100644 --- a/lib/WeBWorK/ContentGenerator/Achievements.pm +++ b/lib/WeBWorK/ContentGenerator/Achievements.pm @@ -37,25 +37,8 @@ sub initialize ($c) { $c->{globalData} = $db->getGlobalUserAchievement($c->{studentName}); # Check to see if user items are enabled and if the user has achievement data. - if ($ce->{achievementItemsEnabled} && defined $c->{globalData}) { - my $itemsWithCounts = WeBWorK::AchievementItems::UserItems($c->{studentName}, $db, $ce); - $c->{achievementItems} = $itemsWithCounts; - - my $usedItem = $c->param('useditem'); - - # If the useditem parameter is defined then the student wanted to use an item, so lets do that by calling the - # appropriate item's use method and printing results. - if (defined $usedItem) { - my $error = $itemsWithCounts->[$usedItem][0]->use_item($c->{studentName}, $c); - if ($error) { - $c->addbadmessage($error); - } else { - if ($itemsWithCounts->[$usedItem][1] != 1) { --$itemsWithCounts->[$usedItem][1]; } - else { splice(@$itemsWithCounts, $usedItem, 1); } - $c->addgoodmessage($c->maketext('Reward used successfully!')); - } - } - } + $c->{achievementItems} = WeBWorK::AchievementItems::UserItems($c, $c->{studentName}, undef, undef) + if $ce->{achievementItemsEnabled} && defined $c->{globalData}; return; } @@ -88,35 +71,6 @@ sub getAchievementLevelData ($c) { ); } -sub getAchievementItemsData ($c) { - my $db = $c->db; - - my $userID = $c->{studentName}; - - my (@items, %itemCounts, @sets, %setProblemIds); - - if ($c->ce->{achievementItemsEnabled} && $c->{achievementItems}) { - # Remove count data so @items is structured as originally designed. - for my $item (@{ $c->{achievementItems} }) { - push(@items, $item->[0]); - $itemCounts{ $item->[0]->id } = $item->[1]; - } - - for my $set ($db->getMergedSets(map { [ $userID, $_ ] } $db->listUserSets($userID))) { - push(@sets, $set); - $setProblemIds{ $set->set_id } = [ map { $_->[2] } - $db->listUserProblemsWhere({ user_id => $userID, set_id => $set->set_id }, 'problem_id') ]; - } - } - - return ( - items => \@items, - itemCounts => \%itemCounts, - sets => \@sets, - setProblemIds => \%setProblemIds - ); -} - sub getAchievementsData ($c) { my $db = $c->db; my $ce = $c->ce; diff --git a/lib/WeBWorK/ContentGenerator/Problem.pm b/lib/WeBWorK/ContentGenerator/Problem.pm index f3512a3a0f..e699e8b396 100644 --- a/lib/WeBWorK/ContentGenerator/Problem.pm +++ b/lib/WeBWorK/ContentGenerator/Problem.pm @@ -38,6 +38,7 @@ use WeBWorK::AchievementEvaluator qw(checkForAchievements); use WeBWorK::DB::Utils qw(global2user fake_set fake_problem); use WeBWorK::Localize; use WeBWorK::AchievementEvaluator; +use WeBWorK::AchievementItems; # GET/POST Parameters for this module # diff --git a/lib/WeBWorK/ContentGenerator/ProblemSet.pm b/lib/WeBWorK/ContentGenerator/ProblemSet.pm index d54b813417..3e8e24b9f0 100644 --- a/lib/WeBWorK/ContentGenerator/ProblemSet.pm +++ b/lib/WeBWorK/ContentGenerator/ProblemSet.pm @@ -31,6 +31,7 @@ use WeBWorK::Utils::Rendering qw(renderPG); use WeBWorK::Utils::Sets qw(is_restricted grade_set format_set_name_display); use WeBWorK::DB::Utils qw(grok_versionID_from_vsetID_sql); use WeBWorK::Localize; +use WeBWorK::AchievementItems; async sub initialize ($c) { my $db = $c->db; @@ -58,6 +59,22 @@ async sub initialize ($c) { $c->{displayMode} = $user->displayMode || $ce->{pg}{options}{displayMode}; + # Import problem records for assignments or test version records for tests now. Then initialize all + # achievement item data to have access to the updated records if an achievement item was used. + if ($c->{set}->assignment_type =~ /gateway/) { + $c->{setVersions} = [ + $db->getMergedSetVersionsWhere( + { user_id => $eUserID, set_id => { like => $c->{set}->set_id . ',v%' } }, + \grok_versionID_from_vsetID_sql($db->{set_version_merged}->sql->_quote('set_id')) + ) + ]; + $c->{achievementItems} = WeBWorK::AchievementItems::UserItems($c, $eUserID, $c->{set}, $c->{setVersions}); + } else { + $c->{setProblems} = + [ $db->getMergedProblemsWhere({ user_id => $eUserID, set_id => $c->{set}->set_id }, 'problem_id') ]; + $c->{achievementItems} = WeBWorK::AchievementItems::UserItems($c, $eUserID, $c->{set}, $c->{setProblems}); + } + # Display status messages. $c->addmessage($c->tag('p', $c->b($c->authen->flash('status_message')))) if $c->authen->flash('status_message'); @@ -168,16 +185,7 @@ sub info { # This is called by the ContentGenerator/ProblemSet/body template for a regular homework set. # It lists the problems in the set. sub problem_list ($c) { - my $authz = $c->authz; - my $db = $c->db; - - my $setID = $c->stash('setID'); - my $user = $c->param('user'); - - my @problems = - $db->getMergedProblemsWhere({ user_id => $c->param('effectiveUser'), set_id => $setID }, 'problem_id'); - - return $c->include('ContentGenerator/ProblemSet/problem_list', problems => \@problems); + return $c->include('ContentGenerator/ProblemSet/problem_list', problems => $c->{setProblems}); } # This is called by the ContentGenerator/ProblemSet/body template for a test. @@ -204,12 +212,7 @@ sub gateway_body ($c) { my $timeInterval = $set->time_interval || 0; my @versionData; - my @setVersions = $db->getMergedSetVersionsWhere( - { user_id => $effectiveUser, set_id => { like => $set->set_id . ',v%' } }, - \grok_versionID_from_vsetID_sql($db->{set_version_merged}->sql->_quote('set_id')) - ); - - for my $verSet (@setVersions) { + for my $verSet (@{ $c->{setVersions} }) { # Count number of versions in current timeInterval if (!$timeInterval || $verSet->version_creation_time > ($timeNow - $timeInterval)) { ++$currentVersions; @@ -323,7 +326,7 @@ sub gateway_body ($c) { timeInterval => $timeInterval, timeNow => $timeNow, lastTime => $lastTime, - setVersions => \@setVersions, + setVersions => $c->{setVersions}, versionData => \@versionData, currentVersions => $currentVersions ); diff --git a/templates/ContentGenerator/Achievements.html.ep b/templates/ContentGenerator/Achievements.html.ep index 8124e7def9..15eacb3867 100644 --- a/templates/ContentGenerator/Achievements.html.ep +++ b/templates/ContentGenerator/Achievements.html.ep @@ -4,10 +4,6 @@ <%= stylesheet getAssetURL($ce, 'js/Achievements/achievements.css') =%> % end % -% content_for js => begin - <%= javascript getAssetURL($ce, 'js/AchievementItems/achievementitems.js'), defer => undef =%> -% end -% % # Exit if there is no global achievement data for this user. % unless (defined $c->{globalData}) {
<%= maketext(q{You don't have any Achievement data associated to you!}) =%>
@@ -15,5 +11,5 @@ % } % <%= include 'ContentGenerator/Achievements/cheevobigbox', $c->getAchievementLevelData =%> -<%= include 'ContentGenerator/Achievements/achievement_items', $c->getAchievementItemsData =%> +<%= include 'ContentGenerator/Achievements/achievement_items' =%> <%= include 'ContentGenerator/Achievements/achievement_badges', $c->getAchievementsData =%> diff --git a/templates/ContentGenerator/Achievements/achievement_items.html.ep b/templates/ContentGenerator/Achievements/achievement_items.html.ep index eeada97d42..a490df2d3d 100644 --- a/templates/ContentGenerator/Achievements/achievement_items.html.ep +++ b/templates/ContentGenerator/Achievements/achievement_items.html.ep @@ -1,58 +1,21 @@ -% last unless $ce->{achievementItemsEnabled} && $c->{achievementItems}; +% last unless $ce->{achievementItemsEnabled}; % % # Show any items the user may have.+ <%= maketext( + 'Achievement rewards can be used to modify assignments. To use a reward, go to the assignment you ' + . 'wish to apply the reward to, then click the "Use Achievement Reward" button. You currently have ' + . 'access to the following rewards:' + ) %> +
<%= maketext($item->description) %>
- % my $form = $item->print_form($sets, $setProblemIds, $c); - % # Print a modal popup for each item which contains the form necessary to get the data to use the item. - % my $button_text; - % if ($itemCounts->{ $item->id } > 1) { - % $button_text = maketext('[_1] ([_2] remaining)', maketext($item->name), $itemCounts->{ $item->id }); - % } elsif ($itemCounts->{ $item->id } < 0) { - % $button_text = maketext('[_1] (unlimited reusability)', maketext($item->name)); - % } else { - % $button_text = maketext($item->name); - % } - <%= link_to maketext('Use [_1]', $button_text) => '#modal_' . $item->id, - role => 'button', - class => 'btn btn-secondary' . ($form ? '' : ' disabled'), - id => 'popup_' . $item->id, - $form ? (data => { bs_toggle => 'modal' }) : () =%> - % if ($form) { - - % } -