--- loncom/interface/lonmeta.pm 2001/12/24 21:09:08 1.11 +++ loncom/interface/lonmeta.pm 2005/08/27 23:25:18 1.108 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Metadata display handler # -# $Id: lonmeta.pm,v 1.11 2001/12/24 21:09:08 www Exp $ +# $Id: lonmeta.pm,v 1.108 2005/08/27 23:25:18 banghart Exp $ # # Copyright Michigan State University Board of Trustees # @@ -17,243 +17,1114 @@ # 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 +# 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/ -# -# (TeX Content Handler -# -# 05/29/00,05/30,10/11 Gerd Kortemeyer) -# -# 10/19,10/21,10/23,11/27,08/09/01,12/22,12/24 Gerd Kortemeyer + package Apache::lonmeta; use strict; +use LONCAPA::lonmetadata(); use Apache::Constants qw(:common); -use Apache::lonnet(); +use Apache::lonnet; use Apache::loncommon(); +use Apache::lonhtmlcommon(); +use Apache::lonmsg; +use Apache::lonpublisher; +use Apache::lonlocal; +use Apache::lonmysql; +use Apache::lonmsg; + + +############################################################ +############################################################ +## +## &get_dynamic_metadata_from_sql($url) +## +## Queries sql database for dynamic metdata +## Returns a hash of hashes, with keys of urls which match $url +## Returned fields are given below. +## +## Examples: +## +## %DynamicMetadata = &Apache::lonmeta::get_dynmaic_metadata_from_sql +## ('/res/msu/korte/'); +## +## $DynamicMetadata{'/res/msu/korte/example.problem'}->{$field} +## +############################################################ +############################################################ +sub get_dynamic_metadata_from_sql { + my ($url) = shift(); + my ($authordom,$author)=($url=~m:^/res/(\w+)/(\w+)/:); + if (! defined($authordom)) { + $authordom = shift(); + } + if (! defined($author)) { + $author = shift(); + } + if (! defined($authordom) || ! defined($author)) { + return (); + } + my @Fields = ('url','count','course', + 'goto','goto_list', + 'comefrom','comefrom_list', + 'sequsage','sequsage_list', + 'stdno','stdno_list', + 'dependencies', + 'avetries','avetries_list', + 'difficulty','difficulty_list', + 'disc','disc_list', + 'clear','technical','correct', + 'helpful','depth'); + # + my $query = 'SELECT '.join(',',@Fields). + ' FROM metadata WHERE url LIKE "'.$url.'%"'; + my $server = &Apache::lonnet::homeserver($author,$authordom); + my $reply = &Apache::lonnet::metadata_query($query,undef,undef, + ,[$server]); + return () if (! defined($reply) || ref($reply) ne 'HASH'); + my $filename = $reply->{$server}; + if (! defined($filename) || $filename =~ /^error/) { + return (); + } + my $max_time = time + 10; # wait 10 seconds for results at most + my %ReturnHash; + # + # Look for results + my $finished = 0; + while (! $finished && time < $max_time) { + my $datafile=$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename; + if (! -e "$datafile.end") { next; } + my $fh; + if (!($fh=Apache::File->new($datafile))) { next; } + while (my $result = <$fh>) { + chomp($result); + next if (! $result); + my @Data = + map { + &Apache::lonnet::unescape($_); + } split(',',$result); + my $url = $Data[0]; + for (my $i=0;$i<=$#Fields;$i++) { + $ReturnHash{$url}->{$Fields[$i]}=$Data[$i]; + } + } + $finished = 1; + } + # + return %ReturnHash; +} -# ----------------------------------------- Fetch and evaluate dynamic metadata +# Fetch and evaluate dynamic metadata sub dynamicmeta { my $url=&Apache::lonnet::declutter(shift); $url=~s/\.meta$//; my ($adomain,$aauthor)=($url=~/^(\w+)\/(\w+)\//); - my $regexp=&Apache::lonnet::escape($url); + my $regexp=$url; $regexp=~s/(\W)/\\$1/g; $regexp='___'.$regexp.'___'; - my %evaldata=&Apache::lonnet::dump - ('resevaldata',$adomain,$aauthor,$regexp); - my %sum; - my %cnt; - my %listitems=('count' => 'add', - 'course' => 'add', - 'avetries' => 'avg', - 'stdno' => 'add', - 'difficulty' => 'avg', - 'clear' => 'avg', - 'technical' => 'avg', - 'helpful' => 'avg', - 'correct' => 'avg', - 'depth' => 'avg', - 'comments' => 'app', - 'usage' => 'cnt' - ); - foreach (keys %evaldata) { - $_=~/___(\w+)$/; - if (defined($cnt{$1})) { $cnt{$1}++; } else { $cnt{$1}=1; } - unless ($listitems{$1} eq 'app') { - if (defined($sum{$1})) { - $sum{$1}+=$evaldata{$_}; - } else { - $sum{$1}=$evaldata{$_}; - } + my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain, + $aauthor,$regexp); + my %DynamicData = &LONCAPA::lonmetadata::process_reseval_data(\%evaldata); + my %Data = &LONCAPA::lonmetadata::process_dynamic_metadata($url, + \%DynamicData); + # + # Deal with 'count' separately + $Data{'count'} = &access_count($url,$aauthor,$adomain); + # + # Debugging code I will probably need later + if (0) { + &Apache::lonnet::logthis('Dynamic Metadata'); + while(my($k,$v)=each(%Data)){ + &Apache::lonnet::logthis(' "'.$k.'"=>"'.$v.'"'); + } + &Apache::lonnet::logthis('-------------------'); + } + return %Data; +} + +sub access_count { + my ($src,$author,$adomain) = @_; + my %countdata=&Apache::lonnet::dump('nohist_accesscount',$adomain, + $author,$src); + if (! exists($countdata{$src})) { + return &mt('Not Available'); + } else { + return $countdata{$src}; + } +} + +# Try to make an alt tag if there is none +sub alttag { + my ($base,$src)=@_; + my $fullpath=&Apache::lonnet::hreflocation($base,$src); + my $alttag=&Apache::lonnet::metadata($fullpath,'title').' '. + &Apache::lonnet::metadata($fullpath,'subject').' '. + &Apache::lonnet::metadata($fullpath,'abstract'); + $alttag=~s/\s+/ /gs; + $alttag=~s/\"//gs; + $alttag=~s/\'//gs; + $alttag=~s/\s+$//gs; + $alttag=~s/^\s+//gs; + if ($alttag) { + return $alttag; + } else { + return &mt('No information available'); + } +} + +# Author display +sub authordisplay { + my ($aname,$adom)=@_; + return &Apache::loncommon::aboutmewrapper + (&Apache::loncommon::plainname($aname,$adom), + $aname,$adom,'preview').' ['.$aname.'@'.$adom.']'; +} + +# Pretty display +sub evalgraph { + my $value=shift; + if (! $value) { + return ''; + } + my $val=int($value*10.+0.5)-10; + my $output=''; + if ($val>=20) { + $output.=''; + } else { + $output.=''. + ''; + } + $output.=''; + if ($val>20) { + $output.=''. + ''; + } else { + $output.=''; + } + $output.='
          ('.sprintf("%5.2f",$value).')
'; + return $output; +} + +sub diffgraph { + my $value=shift; + if (! $value) { + return ''; + } + my $val=int(40.0*$value+0.5); + my @colors=('#FF9933','#EEAA33','#DDBB33','#CCCC33', + '#BBDD33','#CCCC33','#DDBB33','#EEAA33'); + my $output=''; + for (my $i=0;$i<8;$i++) { + if ($val>$i*5) { + $output.=''; } else { - if (defined($sum{$1})) { - if ($evaldata{$_}) { - $sum{$1}.='
'.$evaldata{$_}; - } - } else { - $sum{$1}=''.$evaldata{$_}; - } + $output.=''; } } - my %returnhash=(); - foreach (keys %cnt) { - if ($listitems{$_} eq 'avg') { - $returnhash{$_}=int(($sum{$_}/$cnt{$_})*100.0+0.5)/100.0; - } elsif ($listitems{$_} eq 'cnt') { - $returnhash{$_}=$cnt{$_}; - } else { - $returnhash{$_}=$sum{$_}; - } + $output.='
   ('.sprintf("%3.2f",$value).')
'; + return $output; +} + + +# The field names +sub fieldnames { + my $file_type=shift; + my %fields = + ('title' => 'Title', + 'author' =>'Author(s)', + 'authorspace' => 'Author Space', + 'modifyinguser' => 'Last Modifying User', + 'subject' => 'Subject', + 'keywords' => 'Keyword(s)', + 'notes' => 'Notes', + 'abstract' => 'Abstract', + 'lowestgradelevel' => 'Lowest Grade Level', + 'highestgradelevel' => 'Highest Grade Level'); + if (! defined($file_type) || $file_type ne 'portfolio') { + %fields = + (%fields, + 'domain' => 'Domain', + 'standards' => 'Standards', + 'mime' => 'MIME Type', + 'language' => 'Language', + 'creationdate' => 'Creation Date', + 'lastrevisiondate' => 'Last Revision Date', + 'owner' => 'Publisher/Owner', + 'copyright' => 'Copyright/Distribution', + 'customdistributionfile' => 'Custom Distribution File', + 'sourceavail' => 'Source Available', + 'sourcerights' => 'Source Custom Distribution File', + 'obsolete' => 'Obsolete', + 'obsoletereplacement' => 'Suggested Replacement for Obsolete File', + 'count' => 'Network-wide number of accesses (hits)', + 'course' => 'Network-wide number of courses using resource', + 'course_list' => 'Network-wide courses using resource', + 'sequsage' => 'Number of resources using or importing resource', + 'sequsage_list' => 'Resources using or importing resource', + 'goto' => 'Number of resources that follow this resource in maps', + 'goto_list' => 'Resources that follow this resource in maps', + 'comefrom' => 'Number of resources that lead up to this resource in maps', + 'comefrom_list' => 'Resources that lead up to this resource in maps', + 'clear' => 'Material presented in clear way', + 'depth' => 'Material covered with sufficient depth', + 'helpful' => 'Material is helpful', + 'correct' => 'Material appears to be correct', + 'technical' => 'Resource is technically correct', + 'avetries' => 'Average number of tries till solved', + 'stdno' => 'Total number of students who have worked on this problem', + 'difficulty' => 'Degree of difficulty', + 'disc' => 'Degree of discrimination', + 'dependencies' => 'Resources used by this resource', + ); } - return %returnhash; + return &Apache::lonlocal::texthash(%fields); } -# ================================================================ Main Handler +sub select_course { + my ($r)=@_; + $r->print('

Instructor Selected Meta-Data


'); + $r->print('
'); + $r->print('Select your course
'); + $r->print(''); + } + my $course_key = $key; + $course_key =~ s/\.metadata\..*//; + $r->print(''); + } + } + unless ($meta_not_found) { + $r->print('
'); + $r->print(''); + $r->print('
'); + } + return 'ok'; +} +# Pretty printing of metadata field -sub handler { - my $r=shift; - my %content=(); +sub prettyprint { + my ($type,$value,$target,$prefix,$form,$noformat)=@_; +# $target,$prefix,$form are optional and for filecrumbs only + if (! defined($value)) { + return ' '; + } + # Title + if ($type eq 'title') { + return ''.$value.''; + } + # Dates + if (($type eq 'creationdate') || + ($type eq 'lastrevisiondate')) { + return ($value?&Apache::lonlocal::locallocaltime( + &Apache::lonmysql::unsqltime($value)): + &mt('not available')); + } + # Language + if ($type eq 'language') { + return &Apache::loncommon::languagedescription($value); + } + # Copyright + if ($type eq 'copyright') { + return &Apache::loncommon::copyrightdescription($value); + } + # Copyright + if ($type eq 'sourceavail') { + return &Apache::loncommon::source_copyrightdescription($value); + } + # MIME + if ($type eq 'mime') { + return ' '. + &Apache::loncommon::filedescription($value); + } + # Person + if (($type eq 'author') || + ($type eq 'owner') || + ($type eq 'modifyinguser') || + ($type eq 'authorspace')) { + $value=~s/(\w+)(\:|\@)(\w+)/&authordisplay($1,$3)/gse; + return $value; + } + # Gradelevel + if (($type eq 'lowestgradelevel') || + ($type eq 'highestgradelevel')) { + return &Apache::loncommon::gradeleveldescription($value); + } + # Only for advance users below + if (! $env{'user.adv'}) { + return '- '.&mt('not displayed').' -'; + } + # File + if (($type eq 'customdistributionfile') || + ($type eq 'obsoletereplacement') || + ($type eq 'goto_list') || + ($type eq 'comefrom_list') || + ($type eq 'sequsage_list') || + ($type eq 'dependencies')) { + return ''; + } + # Evaluations + if (($type eq 'clear') || + ($type eq 'depth') || + ($type eq 'helpful') || + ($type eq 'correct') || + ($type eq 'technical')) { + return &evalgraph($value); + } + # Difficulty + if ($type eq 'difficulty' || $type eq 'disc') { + return &diffgraph($value); + } + # List of courses + if ($type=~/\_list/) { + my @Courses = split(/\s*\,\s*/,$value); + my $Str; + foreach my $course (@Courses) { + my %courseinfo = &Apache::lonnet::coursedescription($course); + if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { + next; + } + if ($Str ne '') { $Str .= '
'; } + $Str .= ''. + $courseinfo{'description'}.''; + } + return $Str; + } + # No pretty print found + return $value; +} + +# Pretty input of metadata field +sub direct { + return shift; +} + +sub selectbox { + my ($name,$value,$functionref,@idlist)=@_; + if (! defined($functionref)) { + $functionref=\&direct; + } + my $selout=''; +} + +sub relatedfield { + my ($show,$relatedsearchflag,$relatedsep,$fieldname,$relatedvalue)=@_; + if (! $relatedsearchflag) { + return ''; + } + if (! defined($relatedsep)) { + $relatedsep=' '; + } + if (! $show) { + return $relatedsep.' '; + } + return $relatedsep.''; +} + +sub prettyinput { + my ($type,$value,$fieldname,$formname, + $relatedsearchflag,$relatedsep,$relatedvalue,$size)=@_; + if (! defined($size)) { + $size = 80; + } + # Language + if ($type eq 'language') { + return &selectbox($fieldname, + $value, + \&Apache::loncommon::languagedescription, + (&Apache::loncommon::languageids)). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Copyright + if ($type eq 'copyright') { + return &selectbox($fieldname, + $value, + \&Apache::loncommon::copyrightdescription, + (&Apache::loncommon::copyrightids)). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Source Copyright + if ($type eq 'sourceavail') { + return &selectbox($fieldname, + $value, + \&Apache::loncommon::source_copyrightdescription, + (&Apache::loncommon::source_copyrightids)). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Gradelevels + if (($type eq 'lowestgradelevel') || + ($type eq 'highestgradelevel')) { + return &Apache::loncommon::select_level_form($value,$fieldname). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Obsolete + if ($type eq 'obsolete') { + return ''. + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Obsolete replacement file + if ($type eq 'obsoletereplacement') { + return '".&mt('Select').''. + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Customdistribution file + if ($type eq 'customdistributionfile') { + return '".&mt('Select').''. + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Source Customdistribution file + if ($type eq 'sourcerights') { + return '".&mt('Select').''. + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # Dates + if (($type eq 'creationdate') || + ($type eq 'lastrevisiondate')) { + return + &Apache::lonhtmlcommon::date_setter($formname,$fieldname,$value). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + # No pretty input found + $value=~s/^\s+//gs; + $value=~s/\s+$//gs; + $value=~s/\s+/ /gs; + $value=~s/\"/\"\;/gs; + return + ''. + &relatedfield(1,$relatedsearchflag,$relatedsep,$fieldname, + $relatedvalue); +} -# ----------------------------------------------------------- Set document type +# Main Handler +sub handler { + my $r=shift; + # + my $uri=$r->uri; + # + # Set document type + &Apache::loncommon::content_type($r,'text/html'); + $r->send_http_header; + return OK if $r->header_only; + # + my ($resdomain,$resuser)= + (&Apache::lonnet::declutter($uri)=~/^(\w+)\/(\w+)\//); + my $html=&Apache::lonxml::xmlbegin(); + $r->print($html.''. + 'Catalog Information'. + ''); + if ($uri=~m:/adm/bombs/(.*)$:) { + $r->print(&Apache::loncommon::bodytag('Error Messages')); + # Looking for all bombs? + &report_bombs($r,$uri); + } elsif ($uri=~/\/portfolio\//) { + $r->print(&Apache::loncommon::bodytag + ('Edit Portfolio File Information','','','',$resdomain)); + &present_editable_metadata($r,$uri,'portfolio'); + &select_course($r); + } elsif ($uri=~/^\/\~/) { + # Construction space + $r->print(&Apache::loncommon::bodytag + ('Edit Catalog Information','','','',$resdomain)); + &present_editable_metadata($r,$uri); + } else { + $r->print(&Apache::loncommon::bodytag + ('Catalog Information','','','',$resdomain)); + &present_uneditable_metadata($r,$uri); + } + $r->print(''); + return OK; +} - $r->content_type('text/html'); - $r->send_http_header; +##################################################### +##################################################### +### ### +### Report Bombs ### +### ### +##################################################### +##################################################### +sub report_bombs { + my ($r,$uri) = @_; + # Set document type + $uri =~ s:/adm/bombs/::; + $uri = &Apache::lonnet::declutter($uri); + $r->print('

'.&Apache::lonnet::clutter($uri).'

'); + my ($domain,$author)=($uri=~/^(\w+)\/(\w+)\//); + if (&Apache::loncacc::constructaccess('/~'.$author.'/',$domain)) { + if ($env{'form.clearbombs'}) { + &Apache::lonmsg::clear_author_res_msg($uri); + } + my $clear=&mt('Clear all Messages in Subdirectory'); + $r->print(< + + +ENDCLEAR + my %brokenurls = + &Apache::lonmsg::all_url_author_res_msg($author,$domain); + foreach (sort(keys(%brokenurls))) { + if ($_=~/^\Q$uri\E/) { + $r->print + (''.$_.''. + &Apache::lonmsg::retrieve_author_res_msg($_). + '
'); + } + } + } else { + $r->print(&mt('Not authorized')); + } + return; +} - return OK if $r->header_only; - -# ------------------------------------------------------------------- Read file - - my $uri=$r->uri; - map { - $content{$_}=&Apache::lonnet::metadata($uri,$_); - } split(/\,/,&Apache::lonnet::metadata($uri,'keys')); - -# ------------------------------------------------------------------ Hide stuff - - unless ($ENV{'user.adv'}) { - map { - $content{$_}='- not displayed -'; - } ('keywords','notes','abstract','subject'); - } - -# --------------------------------------------------------------- Render Output - -my $creationdate=localtime($content{'creationdate'}); -my $lastrevisiondate=localtime($content{'lastrevisiondate'}); -my $language=&Apache::loncommon::languagedescription($content{'language'}); -my $mime=&Apache::loncommon::filedescription($content{'mime'}); -my $disuri=&Apache::lonnet::declutter($uri); - $disuri=~s/\.meta$//; - $r->print(<Catalog Information - -

Catalog Information

-

$content{'title'}

-

$disuri

- - - - - - - - - - - - - - - - - - - - - -'; + delete $content{$_}; + } + # + $r->print(<$title +

+$disuri
+$obsoletewarning +$versiondisplay +

+
Author(s)$content{'author'} 
Subject$content{'subject'} 
Keyword(s)$content{'keywords'} 
Notes$content{'notes'} 
Abstract$content{'abstract'} 
MIME Type$mime ($content{'mime'}) 
Language$language 
Creation Date$creationdate 
-Last Revision Date$lastrevisiondate 
Publisher/Owner$content{'owner'} 
Copyright/Distribution$content{'copyright'} +##################################################### +##################################################### +### ### +### Uneditable Metadata Display ### +### ### +##################################################### +##################################################### +sub present_uneditable_metadata { + my ($r,$uri) = @_; + # + my %content=(); + # Read file + foreach (split(/\,/,&Apache::lonnet::metadata($uri,'keys'))) { + $content{$_}=&Apache::lonnet::metadata($uri,$_); + } + # Render Output + # displayed url + my ($thisversion)=($uri=~/\.(\d+)\.(\w+)\.meta$/); + $uri=~s/\.meta$//; + my $disuri=&Apache::lonnet::clutter($uri); + # version + my $currentversion=&Apache::lonnet::getversion($disuri); + my $versiondisplay=''; + if ($thisversion) { + $versiondisplay=&mt('Version').': '.$thisversion. + ' ('.&mt('most recent version').': '. + ($currentversion>0 ? + $currentversion : + &mt('information not available')).')'; + } else { + $versiondisplay='Version: '.$currentversion; + } + # crumbify displayed URL uri target prefix form size + $disuri=&Apache::lonhtmlcommon::crumbs($disuri,undef, undef, undef,'+1'); + $disuri =~ s:
::g; + # obsolete + my $obsolete=$content{'obsolete'}; + my $obsoletewarning=''; + if (($obsolete) && ($env{'user.adv'})) { + $obsoletewarning='

'. + &mt('This resource has been marked obsolete by the author(s)'). + '

'; + } + # + my %lt=&fieldnames(); + my $table=''; + my $title = $content{'title'}; + if (! defined($title)) { + $title = 'Untitled Resource'; + } + foreach ('title', + 'author', + 'subject', + 'keywords', + 'notes', + 'abstract', + 'lowestgradelevel', + 'highestgradelevel', + 'standards', + 'mime', + 'language', + 'creationdate', + 'lastrevisiondate', + 'owner', + 'copyright', + 'customdistributionfile', + 'sourceavail', + 'sourcerights', + 'obsolete', + 'obsoletereplacement') { + $table.='
'.$lt{$_}. + ''. + &prettyprint($_,$content{$_}).'
+$table
ENDHEAD - delete($content{'title'}); - delete($content{'author'}); - delete($content{'subject'}); - delete($content{'keywords'}); - delete($content{'notes'}); - delete($content{'abstract'}); - delete($content{'mime'}); - delete($content{'language'}); - delete($content{'creationdate'}); - delete($content{'lastrevisiondate'}); - delete($content{'owner'}); - delete($content{'copyright'}); - if ($ENV{'user.adv'}) { -# ------------------------------------------------------------ Dynamic Metadata - $r->print('

Dynamic Metadata (updated periodically)

'); - my %items=( - 'count' => 'Network-wide number of accesses (hits)', - 'course' => 'Network-wide number of courses using resource', - 'usage' => 'Number of resources using or importing resource', - 'clear' => 'Material presented in clear way', - 'depth' => 'Material covered with sufficient depth', - 'helpful' => 'Material is helpful', - 'correct' => 'Material appears to be correct', - 'technical' => 'Resource is technically correct', - 'avetries' => 'Average number of tries till solved', - 'stdno' => 'Total number of students who have worked on this problem', - 'difficulty' => 'Degree of difficulty'); - my %dynmeta=&dynamicmeta($uri); - $r->print( -'

Access and Usage Statistics

'); - foreach ('count','usage','course') { - $r->print( -'\n"); - } - $r->print('
'.$items{$_}.''. -$dynmeta{$_}." 
'); - if ($uri=~/\.(problem|exam|quiz|assess|survey|form)\.meta$/) { - $r->print( -'

Assessment Statistical Data

'); - foreach ('stdno','avetries','difficulty') { - $r->print( -'\n"); - } - $r->print('
'.$items{$_}.''. -$dynmeta{$_}." 
'); - } - $r->print('

Evaluation Data

'); - foreach ('clear','depth','helpful','correct','technical') { - $r->print( -'\n"); - } - $r->print('
'.$items{$_}.''. -$dynmeta{$_}." 
'); - $disuri=~/^(\w+)\/(\w+)\//; - if ((($ENV{'user.domain'} eq $1) && ($ENV{'user.name'} eq $2)) - || ($ENV{'user.role.ca./'.$1.'/'.$2})) { - $r->print( - '

Evaluation Comments (visible to author and co-authors only)

'. - '
'.$dynmeta{'comments'}.'
'); - } -# ------------------------------------------------------------- All other stuff - $r->print( - '

Additional Metadata (non-standard, parameters, exports)

'); - foreach (sort keys %content) { - my $name=$_; - my $display=&Apache::lonnet::metadata($uri,$name.'.display'); - unless ($display) { $display=$name; }; - my $otherinfo=''; - map { - if (defined(&Apache::lonnet::metadata($uri,$name.'.'.$_))) { - $otherinfo.=' '.$_.'='. - &Apache::lonnet::metadata($uri,$name.'.'.$_).'; '; - } - } ('name','part','type','default'); - $r->print(''.$display.': '.$content{$name}); - if ($otherinfo) { - $r->print(' ('.$otherinfo.')'); - } - $r->print("
\n"); - } - } - $r->print(''); - return OK; + if ($env{'user.adv'}) { + &print_dynamic_metadata($r,$uri,\%content); + } + return; } -1; -__END__ - +sub print_dynamic_metadata { + my ($r,$uri,$content) = @_; + # + my %content = %$content; + my %lt=&fieldnames(); + # + my $description = 'Dynamic Metadata (updated periodically)'; + $r->print('

'.&mt($description).'

'. + &mt('Processing')); + $r->rflush(); + my %items=&fieldnames(); + my %dynmeta=&dynamicmeta($uri); + # + # General Access and Usage Statistics + if (exists($dynmeta{'count'}) || + exists($dynmeta{'sequsage'}) || + exists($dynmeta{'comefrom'}) || + exists($dynmeta{'goto'}) || + exists($dynmeta{'course'})) { + $r->print('

'.&mt('Access and Usage Statistics').'

'. + ''); + foreach ('count', + 'sequsage','sequsage_list', + 'comefrom','comefrom_list', + 'goto','goto_list', + 'course','course_list') { + $r->print(''. + '\n"); + } + $r->print('
'.$lt{$_}.''. + &prettyprint($_,$dynmeta{$_})."
'); + } else { + $r->print('

'.&mt('No Access or Usages Statistics are available for this resource.').'

'); + } + # + # Assessment statistics + if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/) { + if (exists($dynmeta{'stdno'}) || + exists($dynmeta{'avetries'}) || + exists($dynmeta{'difficulty'}) || + exists($dynmeta{'disc'})) { + # This is an assessment, print assessment data + $r->print('

'. + &mt('Overall Assessment Statistical Data'). + '

'. + ''); + $r->print(''. + ''."\n"); + foreach ('avetries','difficulty','disc') { + $r->print(''. + ''."\n"); + } + $r->print('
'.$lt{'stdno'}.''. + &prettyprint('stdno',$dynmeta{'stdno'}). + '
'.$lt{$_}.''. + &prettyprint($_,sprintf('%5.2f',$dynmeta{$_})). + '
'); + } + if (exists($dynmeta{'stats'})) { + # + # New assessment statistics + $r->print('

'. + &mt('Detailed Assessment Statistical Data'). + '

'); + my $table = ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''. + ''.$/; + foreach my $identifier (sort(keys(%{$dynmeta{'stats'}}))) { + my $data = $dynmeta{'stats'}->{$identifier}; + my $course = $data->{'course'}; + my %courseinfo = &Apache::lonnet::coursedescription($course); + if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { + &Apache::lonnet::logthis('lookup for '.$course.' failed'); + next; + } + $table .= ''; + $table .= + ''; + $table .= + ''; + $table .= + ''; + foreach ('avetries','difficulty','disc') { + $table .= ''; + } + $table .= + ''; + $table .= + ''.$/; + } + $table .= '
CourseSection(s)Num StudentsMean TriesDegree of DifficultyDegree of DiscriminationTime of computation
'.$courseinfo{'description'}.''.$data->{'sections'}.''.$data->{'stdno'}.''; + if (exists($data->{$_})) { + $table .= sprintf('%.2f',$data->{$_}).' '; + } else { + $table .= ''; + } + $table .= ''. + &Apache::lonlocal::locallocaltime($data->{'timestamp'}). + '
'.$/; + $r->print($table); + } else { + $r->print('No new dynamic data found.'); + } + } else { + $r->print('

'. + &mt('No Assessment Statistical Data is available for this resource'). + '

'); + } + # + # + if (exists($dynmeta{'clear'}) || + exists($dynmeta{'depth'}) || + exists($dynmeta{'helpful'}) || + exists($dynmeta{'correct'}) || + exists($dynmeta{'technical'})){ + $r->print('

'.&mt('Evaluation Data').'

'. + ''); + foreach ('clear','depth','helpful','correct','technical') { + $r->print(''. + '\n"); + } + $r->print('
'.$lt{$_}.''. + &prettyprint($_,$dynmeta{$_})."
'); + } else { + $r->print('

'.&mt('No Evaluation Data is available for this resource.').'

'); + } + $uri=~/^\/res\/(\w+)\/(\w+)\//; + if ((($env{'user.domain'} eq $1) && ($env{'user.name'} eq $2)) + || ($env{'user.role.ca./'.$1.'/'.$2})) { + if (exists($dynmeta{'comments'})) { + $r->print('

'.&mt('Evaluation Comments').' ('. + &mt('visible to author and co-authors only'). + ')

'. + '
'.$dynmeta{'comments'}.'
'); + } else { + $r->print('

'.&mt('There are no Evaluation Comments on this resource.').'

'); + } + my $bombs = &Apache::lonmsg::retrieve_author_res_msg($uri); + if (defined($bombs) && $bombs ne '') { + $r->print('

'.&mt('Error Messages').' ('. + &mt('visible to author and co-authors only').')'. + '

'.$bombs); + } else { + $r->print('

'.&mt('There are currently no Error Messages for this resource.').'

'); + } + } + # + # All other stuff + $r->print('

'. + &mt('Additional Metadata (non-standard, parameters, exports)'). + '

'); + foreach (sort(keys(%content))) { + my $name=$_; + if ($name!~/\.display$/) { + my $display=&Apache::lonnet::metadata($uri, + $name.'.display'); + if (! $display) { + $display=$name; + }; + my $otherinfo=''; + foreach ('name','part','type','default') { + if (defined(&Apache::lonnet::metadata($uri, + $name.'.'.$_))) { + $otherinfo.=' '.$_.'='. + &Apache::lonnet::metadata($uri, + $name.'.'.$_).'; '; + } + } + $r->print('\n"); + } + } + $r->print("
'.$display.''.$content{$name}); + if ($otherinfo) { + $r->print(' ('.$otherinfo.')'); + } + $r->print("
"); + return; +} +##################################################### +##################################################### +### ### +### Editable metadata display ### +### ### +##################################################### +##################################################### +sub present_editable_metadata { + my ($r,$uri, $file_type) = @_; + # Construction Space Call + # Header + my $disuri=$uri; + my $fn=&Apache::lonnet::filelocation('',$uri); + $disuri=~s/^\/\~/\/priv\//; + $disuri=~s/\.meta$//; + my $target=$uri; + $target=~s/^\/\~/\/res\/$env{'request.role.domain'}\//; + $target=~s/\.meta$//; + my $bombs=&Apache::lonmsg::retrieve_author_res_msg($target); + if ($bombs) { + my $showdel=1; + if ($env{'form.delmsg'}) { + if (&Apache::lonmsg::del_url_author_res_msg($target) eq 'ok') { + $bombs=&mt('Messages deleted.'); + $showdel=0; + } else { + $bombs=&mt('Error deleting messages'); + } + } + if ($env{'form.clearmsg'}) { + my $cleardir=$target; + $cleardir=~s/\/[^\/]+$/\//; + if (&Apache::lonmsg::clear_author_res_msg($cleardir) eq 'ok') { + $bombs=&mt('Messages cleared.'); + $showdel=0; + } else { + $bombs=&mt('Error clearing messages'); + } + } + my $del=&mt('Delete Messages for this Resource'); + my $clear=&mt('Clear all Messages in Subdirectory'); + my $goback=&mt('Back to Source File'); + $r->print(<$disuri +
+ENDBOMBS + if ($showdel) { + $r->print(< + +ENDDEL + } else { + $r->print(''.$goback.''); + } + $r->print('
'.$bombs); + } else { + my $displayfile='Catalog Information for '.$disuri; + if ($disuri=~/\/default$/) { + my $dir=$disuri; + $dir=~s/default$//; + $displayfile= + &mt('Default Cataloging Information for Directory').' '. + $dir; + } + %Apache::lonpublisher::metadatafields=(); + %Apache::lonpublisher::metadatakeys=(); + my $result=&Apache::lonnet::getfile($fn); + if ($result == -1){ + $r->print('Creating new '.$fn); + } else { + &Apache::lonpublisher::metaeval($result); + } + $r->print(<$displayfile + +ENDEDIT + $r->print(''); + my %lt=&fieldnames($file_type); + my $output; + my @fields; + if ($file_type eq 'portfolio') { + @fields = ('author','title','subject','keywords','abstract','notes','lowestgradelevel', + 'highestgradelevel'); + } else { + @fields = ('author','title','subject','keywords','abstract','notes', + 'copyright','customdistributionfile','language', + 'standards', + 'lowestgradelevel','highestgradelevel','sourceavail','sourcerights', + 'obsolete','obsoletereplacement'); + } + foreach (@fields) { + if (defined($env{'form.new_'.$_})) { + $Apache::lonpublisher::metadatafields{$_}= + $env{'form.new_'.$_}; + } + if (! $Apache::lonpublisher::metadatafields{'copyright'}) { + $Apache::lonpublisher::metadatafields{'copyright'}= + 'default'; + } + $output.=('

'.$lt{$_}.': '. + &prettyinput($_, + $Apache::lonpublisher::metadatafields{$_}, + 'new_'.$_,'defaultmeta').'

'); + if ($env{'form.metacourse'}) { + $r->print('This is the instructor metadata area
'); + # have to find all the metadata items, so we'll loop through and find them + $r->print(''); + $r->print('The course is: '.$env{'form.metacourse'}.'
'); + foreach my $key (sort keys %env) { + if ($key=~m/^($env{'form.metacourse'}\.metadata\.)(\d+)\.title/) { + my $key_base = $1; + my $item_num = $2; + # found one, so let's display it + my $title = $env{$key_base.$item_num.'.title'}; + my $type = $env{$key_base.$item_num.'.type'}; + my @choices = sort(split /, /,$env{$key_base.$item_num.'.values'}); + $r->print($title.'
'); + $r->print($type.'
'); + + foreach my $word (@choices) { + my $checked; + if ($Apache::lonpublisher::metadatafields{'coursekeyword'}=~ m/$word/) { + $checked = 1; + } else { + undef($checked); + } + $r->print(&Apache::lonhtmlcommon::checkbox('instmeta_'.$env{'form.metacourse'}.'_'.$item_num,$checked,$word).$word.'
'); + } + } + } + $r->print('
'); + $r->print(''); + return 'ok'; + } + } + if ($env{'form.store'}) { + my $mfh; + my $formname='store'; + my $file_content; + foreach my $meta_field (keys %env) { + if ($meta_field=~m/^form.instmeta_(.+)_(\d+)$/) { + $r->print('Found a field
'); + } + if (&Apache::loncommon::get_env_multiple('form.keywords')) { + $Apache::lonpublisher::metadatafields{'coursekeyword'} = + join (', ', &Apache::loncommon::get_env_multiple('form.keywords')); + } + } + foreach (sort keys %Apache::lonpublisher::metadatafields) { + next if ($_ =~ /\./); + my $unikey=$_; + $unikey=~/^([A-Za-z]+)/; + my $tag=$1; + $tag=~tr/A-Z/a-z/; + $file_content.= "\n\<$tag"; + foreach (split(/\,/, + $Apache::lonpublisher::metadatakeys{$unikey}) + ) { + my $value= + $Apache::lonpublisher::metadatafields{$unikey.'.'.$_}; + $value=~s/\"/\'\'/g; + $file_content.=' '.$_.'="'.$value.'"' ; + # print $mfh ' '.$_.'="'.$value.'"'; + } + $file_content.= '>'. + &HTML::Entities::encode + ($Apache::lonpublisher::metadatafields{$unikey}, + '<>&"'). + ''; + } + if ($fn =~ /\/portfolio\//) { + $fn =~ /\/portfolio\/(.*)$/; + my $new_fn = '/'.$1; + $env{'form.'.$formname}=$file_content; + $env{'form.'.$formname.'.filename'}=$new_fn; + &Apache::lonnet::userfileupload('uploaddoc','', + 'portfolio'.$env{'form.currentpath'}); + my $status =&Apache::lonnet::userfileupload($formname,'','portfolio'); + if (&Apache::lonnet::userfileupload($formname,'','portfolio') eq 'error: no uploaded file') { + $r->print('

'. + &mt('Could not write metadata').', '. + &mt('FAIL').'

'); + } else { + $r->print('

'.&mt('Wrote Metadata'). + ' '.&Apache::lonlocal::locallocaltime(time). + '

'); + } + } else { + if (! ($mfh=Apache::File->new('>'.$fn))) { + $r->print('

'. + &mt('Could not write metadata').', '. + &mt('FAIL').'

'); + } else { + print $mfh $file_content; + $r->print('

'.&mt('Wrote Metadata'). + ' '.&Apache::lonlocal::locallocaltime(time). + '

'); + } + } + } + $r->print($output.'
'); + } + $r->print(''); + return; +} +1; +__END__ + 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.