+
+
+
+
+
+
+
+
+ Threshold Name
+ Current value
+ Change?
+ ');
+ my $rowNum =0;
+ foreach my $type (@thresholditems) {
+ my $parameter = 'internal.threshold_'.$type;
+# onchange is javascript to automatically check the 'Set' button.
+ my $onchange = 'onFocus="javascript:window.document.forms'.
+ "['thresholdform'].elements['".$parameter."_setparmval']".
+ '.checked=true;"';
+ if ($rowNum %2 == 1) {
+ $rowColor = $rowColor1;
+ } else {
+ $rowColor = $rowColor2;
+ }
+ $r->print('
+
+ '.$threshold_titles{$type}.'
+ '.&Apache::lonhtmlcommon::textbox($parameter.'_value',
+ $threshold{$type},
+ 10,$onchange).'
+ '
+ .&Apache::lonhtmlcommon::checkbox($parameter.'_setparmval').
+ '
+ ');
+ $rowNum ++;
+ }
+ $r->print('
+
+
+ ');
+}
+
sub getitems {
- my ($unread,$ungraded,$bombed,$newdiscussions,$tograde,$bombs) = @_;
+ my ($unread,$ungraded,$bombed,$triggered,$newdiscussions,$tograde,$bombs,$warnings,$rowColor1,$rowColor2,$threshold,$cdom,$crs,$res_title) = @_;
my $navmap = Apache::lonnavmaps::navmap->new();
- my @allres=$navmap->retrieveResources();
- my %discussiontime = &Apache::lonnet::dump('discussiontimes',
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
- my %lastread = &Apache::lonnet::dump('nohist_'.$ENV{'request.course.id'}.'_discuss',$ENV{'user.domain'},$ENV{'user.name'},'lastread');
+ # force retrieve Resource to seed the part id cache we'll need it later
+ my @allres=$navmap->retrieveResources(undef,sub {if ($_[0]->is_problem) { $_[0]->parts();} return 1;});
+ my %discussiontime = &Apache::lonnet::dump('discussiontimes',$cdom,$crs);
+ my %lastread = &Apache::lonnet::dump('nohist_'.$env{'request.course.id'}.
+ '_discuss',$env{'user.domain'},$env{'user.name'},'lastread');
my %lastreadtime = ();
my @discussions = ();
my ($classlist,$keylist) = &Apache::loncoursedata::get_classlist();
+ my %resourcetracker = &Apache::lonnet::dump('nohist_resourcetracker',
+ $cdom,$crs);
+ my $warningnum = 0;
foreach my $key (keys(%lastread)) {
my $newkey = $key;
$newkey =~ s/_lastread$//;
@@ -426,19 +529,15 @@ sub getitems {
my $result = '';
my $applies = 0;
my $symb = $resource->symb();
- %{$$bombed{$symb}} = ();
+# %{$$bombed{$symb}} = ();
%{$$ungraded{$symb}} = ();
+ %{$$triggered{$symb}} = ();
+ $$triggered{$symb}{numparts} = 0;
my $title = $resource->compTitle();
- my $ressymb = $symb;
- if ($ressymb =~ m-(___adm/\w+/\w+)/(\d+)/bulletinboard$-) {
- $ressymb = 'bulletin___'.$2.$1.'/'.$2.'/bulletinboard';
- unless ($ressymb =~ m|bulletin___\d+___adm/wrapper|) {
- $ressymb=~s|(bulletin___\d+___)|$1adm/wrapper/|;
- }
- }
-
+ $$res_title{$symb} = $title;
+ my $ressymb = $resource->wrap_symb();
# Check for unread discussion postings
- if (defined($discussiontime{$ressymb})) {
+ if ($resource->hasDiscussion()) {
push(@discussions,$ressymb);
my $prevread = 0;
my $unreadcount = 0;
@@ -448,63 +547,219 @@ sub getitems {
if (defined($lastreadtime{$ressymb})) {
$prevread = $lastreadtime{$ressymb};
}
- my %contrib = &Apache::lonnet::restore($ressymb,$ENV{'request.course.id'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.domain'},
- $ENV{'course.'.$ENV{'request.course.id'}.'.num'});
+ my %contrib = &Apache::lonnet::restore($ressymb,
+ $env{'request.course.id'},$cdom,$crs);
if ($contrib{'version'}) {
for (my $id=1;$id<=$contrib{'version'};$id++) {
unless (($contrib{'hidden'}=~/\.$id\./) || ($contrib{'deleted'}=~/\.$id\./)) {
if ($prevread <$contrib{$id.':timestamp'}) {
$$unread{$ressymb}{$unreadcount} = $id.': '.$contrib{$id.':subject'};
$unreadcount ++;
- push(@{$newdiscussions}, $ressymb);
}
}
}
}
- }
+ if ($unreadcount) { push(@{$newdiscussions}, $ressymb); }
+ }
# Check for ungraded problems
if ($resource->is_problem()) {
my $ctr = 0;
my ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
- my ($partlist,$handgrade,$responseType) = &Apache::grades::response_type($url,$symb);
- foreach my $student (keys(%$classlist)) {
- my ($uname,$udom) = split(/:/,$student);
- my %status=&Apache::grades::student_gradeStatus($url,$symb,$udom,$uname,$partlist);
- my $submitted = 0;
- my $graded = 0;
- foreach (keys(%status)) {
- $submitted = 1 if ($status{$_} ne 'nothing');
- $graded = 1 if ($status{$_} !~ /^correct/);
- my ($foo,$partid,$foo1) = split(/\./,$_);
- if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
- $submitted = 0;
- }
- }
- next if (!$submitted || !$graded);
- $ctr ++;
- }
- if ($ctr) {
- $$ungraded{$symb}{count} = $ctr;
- $$ungraded{$symb}{title} = $title;
- push(@{$tograde}, $symb);
- }
+ my $partlist=$resource->parts();
+ my $handgradeable;
+ foreach my $part (@$partlist) {
+ if ($resource->handgrade($part) eq 'yes') {
+ $handgradeable=1; last;
+ }
+ }
+ if ($handgradeable) {
+ foreach my $student (keys(%$classlist)) {
+ my ($uname,$udom) = split(/:/,$student);
+ my %status=&Apache::grades::student_gradeStatus($url,$symb,$udom,$uname,$partlist);
+ my $submitted = 0;
+ my $ungraded = 0;
+ foreach (keys(%status)) {
+ $submitted = 1 if ($status{$_} ne 'nothing');
+ $ungraded = 1 if ($status{$_} =~ /^ungraded/);
+ my ($foo,$partid,$foo1) = split(/\./,$_);
+ if ($status{'resource.'.$partid.'.submitted_by'} ne '') {
+ $submitted = 0;
+ }
+ }
+ next if (!$submitted || !$ungraded);
+ $ctr ++;
+ }
+ if ($ctr) {
+ $$ungraded{$symb}{count} = $ctr;
+ $$ungraded{$symb}{title} = $title;
+ push(@{$tograde}, $symb);
+ }
+ }
}
# Check for bombs
if ($resource->getErrors()) {
my $errors = $resource->getErrors();
+ $errors =~ s/^,//;
my @bombs = split(/,/, $errors);
my $errorcount = scalar(@bombs);
my $errorlink = '';
+ &Apache::lonnet::escape($bombs[0]).'">'.
+ $title.' ';
$$bombed{$symb}{errorcount} = $errorcount;
$$bombed{$symb}{errorlink} = $errorlink;
push(@{$bombs}, $symb);
}
+# Compile maxtries and degree of difficulty for problem parts
+ my @parts = @{$resource->parts()};
+ my %stats;
+ my %lastreset = ();
+ my $warning = 0;
+ my $rowColor;
+ foreach my $part (@parts) {
+ %{$stats{$part}} = ();
+ my ($attempts,$users,$corrects,$degdiff,$av_attempts);
+ if (exists($resourcetracker{$symb."\0".$part."\0attempts"})) {
+ $attempts = $resourcetracker{$symb."\0".$part."\0attempts"};
+ }
+ if (exists($resourcetracker{$symb."\0".$part."\0users"})) {
+ $users = $resourcetracker{$symb."\0".$part."\0users"};
+ }
+ if (exists($resourcetracker{$symb."\0".$part."\0correct"})) {
+ $corrects = $resourcetracker{$symb."\0".$part."\0correct"};
+ }
+ if ($attempts > 0) {
+ $degdiff = 1 - ($corrects/$attempts);
+ $degdiff = sprintf("%.2f",$degdiff);
+ }
+ if ($users > 0) {
+ $av_attempts = $attempts/$users;
+ $av_attempts = sprintf("%.2f",$av_attempts);
+ }
+ if ((($degdiff ne '' && $degdiff >= $$threshold{'degdiff'}) || ($av_attempts ne '' && $av_attempts >= $$threshold{'av_attempts'})) && ($users >= $$threshold{'numstudents'})) {
+ $stats{$part}{degdiff} = $degdiff;
+ $stats{$part}{attempts} = $av_attempts;
+ $stats{$part}{users} = $users;
+ $lastreset{$part} = $resourcetracker{$symb."\0".$part."\0resettime"};
+ $warning = 1;
+ }
+ }
+ if ($warning) {
+ if ($warningnum %2 == 1) {
+ $rowColor = $rowColor1;
+ } else {
+ $rowColor = $rowColor2;
+ }
+ $$triggered{$symb}{title} = $resource->title;
+ foreach my $part (@parts) {
+ if (exists($stats{$part}{users})) {
+ my $resetname = 'reset_'.&Apache::lonnet::escape($symb."\0".$part);
+ my $resettitle = 'title_'.&Apache::lonnet::escape($symb."\0".$part);
+ if ($$triggered{$symb}{numparts}) {
+ $$triggered{$symb}{text} .= '