File:
[LON-CAPA] /
loncom /
interface /
lonplacementtest.pm
Revision
1.5:
download - view:
text,
annotated -
select for diffs
Mon May 30 03:16:28 2016 UTC (8 years, 6 months ago) by
raeburn
Branches:
MAIN
CVS tags:
version_2_12_X,
HEAD
- Bug 6808. New course container -- "Placement" for Placement Tests.
- Student's score on a placement test can be exported by customizing
localenroll.pm in /home/httpd/lib/perl on domain's library server.
- When a placement test is completed by the student, the chain:
lonnet::auto_export_grades() > lond::auto_export_grades_handler()
> localenroll::export_grades() is used to export grades (e.g. to
a CMS).
# The LearningOnline Network with CAPA
# Handler for a Placement Test course container
#
# $Id: lonplacementtest.pm,v 1.5 2016/05/30 03:16:28 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
#
###############################################################
###############################################################
=pod
=head1 NAME
lonplacementtest - Handler to provide initial screen for student
after log-in and/or role selection for a Placement Test course container
which is currently partially completed.
=head1 SYNOPSIS
lonplacementtest provides an interface for the student to choose
whether to continue with an existing, partially completed test,
or whether to start a new test. Also provides utility functions
used to compute/export scores, and increment the course-wide maxtries
parameter for the user, when an instance of a test is complete.
=head1 DESCRIPTION
This module is used after student log-in and/or role selection
for a Placement Test course contained, if there is a current,
partially completed version of the test. The student is prompted
to choose whether to continue with the current test or start a
new one.
=head1 INTERNAL SUBROUTINES
=over
=item check_completion()
=back
=cut
package Apache::lonplacementtest;
use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet;
use Apache::loncommon;
use Apache::lonhtmlcommon;
use Apache::lonnavmaps;
use Apache::lonpageflip;
use Apache::lonroles;
use Apache::lonparmset;
use Apache::lonlocal;
use LONCAPA qw(:DEFAULT :match);
sub handler {
my $r=shift;
if ($r->header_only) {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
return OK;
}
if (!$env{'request.course.fn'}) {
# Not in a course.
$env{'user.error.msg'}="/adm/lonplacementtest:bre:0:0:Not in a course";
return HTTP_NOT_ACCEPTABLE;
} elsif ($env{'course.'.$env{'request.course.id'}.'.type'} ne 'Placement') {
# Not in a Placement Test
$env{'user.error.msg'}="/adm/lonplacementtest:bre:0:0:Not in a placement test";
return HTTP_NOT_ACCEPTABLE;
}
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
my ($totalpoints,$incomplete) = &check_completion(undef,undef,1);
if (($incomplete) && ($incomplete < 100) && (!$env{'request.role.adv'})) {
$r->print(&showincomplete($incomplete));
} else {
my $furl = &Apache::lonpageflip::first_accessible_resource();
my $cdesc = $env{'course.'.$env{'request.course.id'}.'.description'};
my $msg = &mt('Entering [_1] ...',$cdesc);
&Apache::lonroles::redirect_user($r, &mt('Entering [_1]',$cdesc),$furl, $msg);
}
return OK;
}
sub check_completion {
my ($makenew,$map,$recursive) = @_;
my $navmap = Apache::lonnavmaps::navmap->new();
return unless (ref($navmap));
my @resources = $navmap->retrieveResources($map,
sub { $_[0]->is_problem() },$recursive);
my $currmax = 0;
my $totalpoints = 0;
my $totaldone = 0;
my $totalnotdone = 0;
my $incomplete;
if (@resources) {
my $firstsymb = $resources[0]->symb();
my (%bytitle,%bysymb);
foreach my $res (@resources) {
my $currsymb = $res->symb();
my $title = $res->compTitle;
unless (exists($bytitle{$title})) {
$bytitle{$title} = 0;
}
unless (exists($bysymb{$currsymb})) {
$bysymb{$currsymb} = 0;
}
my $notdone = 0;
my $done = 0;
my %storetries;
my $points = 0;
foreach my $part (@{$res->parts()}) {
my $tries = $res->tries($part);
my $maxtries = $res->maxtries($part);
if ($currmax < $maxtries) {
$currmax = $maxtries;
}
if ($tries < $maxtries) {
$notdone ++;
my $tries = $res->tries($part);
if ($makenew) {
my @response_ids = $res->responseIds($part);
if (@response_ids) {
foreach my $id (@response_ids) {
$storetries{"resource.$part.$id.awarded"}=0;
$storetries{"resource.$part.$id.awarddetail"}='ASSIGNED_SCORE';
}
$storetries{"resource.$part.tries"}=$maxtries;
$storetries{"resource.$part.solved"}='incorrect_by_override';
$storetries{"resource.$part.award"}='ASSIGNED_SCORE';
$storetries{"resource.$part.awarded"}=0;
}
}
} else {
my $awarded = $res->awarded($part);
my $weight = $res->weight($part);
$points += $awarded * $weight;
$done ++;
}
}
if ($notdone) {
$totalnotdone += $notdone;
if ($makenew && keys(%storetries)) {
my $result=&Apache::lonnet::cstore(\%storetries,$currsymb,$env{'request.course.id'},
$env{'user.domain'},$env{'user.name'});
}
}
if ($done) {
$totaldone += $done;
}
$bytitle{$title} += $points;
$bysymb{$currsymb} += $points;
$totalpoints += $points;
}
if ($makenew) {
my $newmax = $currmax + 1;
my $result =
&Apache::lonparmset::storeparm_by_symb_inner($firstsymb,'0_maxtries',
4,$newmax,'int_pos',
$env{'user.name'},
$env{'user.domain'});
my $user = $env{'user.name'}.':'.$env{'user.domain'};
if ($user) {
my %grades = (
$user => {
role => $env{'request.role'},
id => $env{'environment.id'},
status => $env{'environment.inststatus'},
lastname => $env{'environment.lastname'},
firstname => $env{'environment.firstname'},
permanentemail => $env{'environment.permanentemail'},
section => $env{'request.course.sec'},
total => $totalpoints,
category => '',
gradebookcolumn => '',
context => $map,
},
);
$grades{$user}{bytitle} = \%bytitle;
$grades{$user}{bysymb} = \%bysymb;
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my $scope = 'map';
my $instcode = $env{'course.'.$env{'request.course.id'}.'.internal.coursecode'};
my $crstype = $env{'course.'.$env{'request.course.id'}.'.type'};
my $context = 'completion';
if (($cnum ne '') && ($cdom ne '')) {
my %info = (
scope => $scope,
instcode => $instcode,
crstype => $crstype,
context => $context,
);
my $response = &Apache::lonnet::auto_export_grades($cdom,$cnum,\%info,\%grades);
my $outcome;
if (ref($response) eq 'HASH') {
if ($response->{$user}) {
$outcome = 'ok';
} else {
$outcome = 'fail';
}
} else {
$outcome = $response;
}
unless ($outcome eq 'ok') {
&Apache::lonnet::logthis("Placement Test grade export for $env{'user.name'}:$env{'user.domain'} in $env{'request.course.id'} was: $outcome");
}
}
}
}
}
my $totalparts = $totalnotdone + $totaldone;
if (($totalparts) && ($totalnotdone)) {
if (!$totaldone) {
$incomplete = 100;
} else {
my $undonepct = (100*$totalnotdone)/$totalparts;
$incomplete = sprintf("%0d",$undonepct);
}
}
return ($totalpoints,$incomplete);
}
sub is_lastres {
my ($symb,$navmap) = @_;
return unless (ref($navmap));
my $numforward = 0;
my $currRes = $navmap->getBySymb($symb);
if (ref($currRes)) {
my $it = $navmap->getIterator($currRes,undef,undef,1);
while ( my $res=$it->next()) {
if (ref($res)) {
unless ($res->symb() eq $symb) {
$numforward ++;
}
}
}
}
if (!$numforward) {
return 1;
}
return;
}
sub has_tries {
my ($symb,$navmap) = @_;
return unless (ref($navmap));
my $currRes = $navmap->getBySymb($symb);
if (ref($currRes)) {
if ($currRes->is_problem()) {
if ($currRes->tries < $currRes->maxtries) {
return 1;
}
}
}
return;
}
sub showresult {
my ($complete,$inhibitmenu) = @_;
my ($score) = &Apache::lonplacementtest::check_completion(1,undef,1);
my %aclt = &test_action_text();
my $output;
if ($inhibitmenu) {
$output = '<hr />';
} else {
my $brcrum = [{'href' => '/adm/flip?postdata=firstres%3a',
'text' => 'Test Status'},];
$output = &Apache::loncommon::start_page('Placement Test Completed',
undef,{bread_crumbs=>$brcrum});
}
if ($complete) {
$output .= '<p class="LC_info">'.&mt('Test is complete').'</p>';
}
$output .= '<p>'.&mt('You scored [quant,_1,point].',$score).'</p>'
.&Apache::lonhtmlcommon::actionbox(
['<a href="/adm/flip?postdata=firstres%3a">'.$aclt{'newt'}.'</a></li>',
'<a href="/adm/logout">'.$aclt{'exit'}.'</a></li>',
]);
unless ($inhibitmenu) {
$output .= &Apache::loncommon::end_page();
}
return $output;
}
sub showincomplete {
my ($incomplete,$inhibitmenu) = @_;
my %aclt = &test_action_text();
my $output;
if ($incomplete == 100) {
if ($inhibitmenu) {
$output = '<hr />';
} else {
my $brcrum = [{'href' => '/adm/flip?postdata=firstres%3a',
'text' => 'Test Status'},];
$output = &Apache::loncommon::start_page('Placement Test Unattempted',
undef,{bread_crumbs=>$brcrum});
}
$output .= '<p class="LC_warning">'.&mt('Your Placement Test is incomplete.').'<p></p>'
.&mt('Currently, you have not submitted any answers for any of the questions.')
.'</p>'
.&Apache::lonhtmlcommon::actionbox(
['<a href="/adm/flip?postdata=firstres%3a">'.$aclt{'begin'}.'</a></li>',
'<a href="/adm/logout">'.$aclt{'exit'}.'</a></li>',
]);
} elsif ($incomplete) {
if ($inhibitmenu) {
$output = '<hr />';
} else {
my $brcrum = [{'href' => '/adm/flip?postdata=endplacement%3a',
'text' => 'Test Status'},];
$output .= &Apache::loncommon::start_page('Incomplete Placement Test',
undef,{bread_crumbs=>$brcrum});
}
$output .= '<p class="LC_warning">'.&mt('Your Placement Test is incomplete.').'<p></p>'
.&mt('Currently, you have not provided an answer for [_1]% of the questions.',$incomplete)
.'</p>'
.&Apache::lonhtmlcommon::actionbox(
['<a href="/adm/flip?postdata=endplacement%3a">'.$aclt{'endt'}.'</a></li>',
'<a href="/adm/flip?postdata=firstanswerable%3a">'.$aclt{'comp'}.'</a></li>',
'<a href="/adm/logout">'.$aclt{'exit'}.'</a></li>',
]);
}
unless ($inhibitmenu) {
$output .= &Apache::loncommon::end_page();
}
return $output;
}
sub test_action_text {
return &Apache::lonlocal::texthash(
'exit' => 'Logout',
'newt' => 'Start a new test',
'endt' => 'Mark test as completed',
'comp' => 'Go to first unanswered question',
'begin' => 'Go to start',
);
}
1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>