--- loncom/interface/lonmeta.pm 2001/12/24 21:09:08 1.11 +++ loncom/interface/lonmeta.pm 2008/11/17 14:06:14 1.214 @@ -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.214 2008/11/17 14:06:14 schafran Exp $ # # Copyright Michigan State University Board of Trustees # @@ -17,243 +17,1661 @@ # 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 + + +=head1 NAME + +Apache::lonmeta - display meta data + +=head1 SYNOPSIS + +Handler to display meta data + +This is part of the LearningOnline Network with CAPA project +described at http://www.lon-capa.org. + +=head1 HANDLER SUBROUTINE + +handler() + +=head1 OTHER SUBROUTINES + +=over + +=item * + +&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} + +=item * + +dynamicmeta() : Fetch and evaluate dynamic metadata + +=item * + +access_count() + +=item * + +alttag() : Try to make an alt tag if there is none + +=item * + +authordisplay() : Author display + +=item * + +evalgraph() : Pretty display + +=item * + +diffgraph() + +=item * + +fieldnames() + +=item * + +portfolio_linked_path() + +=item * + +get_port_path_and_group() + +=item * + +portfolio_display_uri() + +=item * + +pre_select_course() + +=item * + +select_course() + +=item * + +prettyprint() : Pretty printing of metadata field + +=item * + +direct() : Pretty input of metadata field + +=item * + +selectbox() + +=item * + +relatedfield() + +=item * + +prettyinput() + +=item * + +report_bombs() + +=item * + +present_uneditable_metadata() + +=item * + +present_editable_metadata() + +=item * + +store_metadata() + +=item * + +store_transferred_addedfields() + +=item * + +store_portfolio_metadata() + +=item * + +update_metadata_table() + +=back + +=cut + 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; +use LONCAPA qw(:DEFAULT :match); + + +sub get_dynamic_metadata_from_sql { + my ($url) = shift(); + my ($authordom,$author)=($url=~m{^/res/($match_domain)/($match_username)/}); + if (! defined($authordom)) { + $authordom = shift(); + } + if (! defined($author)) { + $author = shift(); + } + if (! defined($authordom) || ! defined($author)) { + return (); + } + my $query = 'SELECT * 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 %hash=&LONCAPA::lonmetadata::metadata_col_to_hash('metadata', + map { &unescape($_) } split(/\,/,$result)); + foreach my $key (keys(%hash)) { + $ReturnHash{$hash{'url'}}->{$key}=$hash{$key}; + } + } + $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 ($adomain,$aauthor)=($url=~/^($match_domain)\/($match_username)\//); + 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='
  | '; + } else { + $output.=''. + ' | '; + } + $output.=' | '; + if ($val>20) { + $output.=' | '. + ' | '; + } else { + $output.=' |   | '; + } + $output.='('.sprintf("%5.2f",$value).') |
'; } else { - if (defined($sum{$1})) { - if ($evaldata{$_}) { - $sum{$1}.=' | '; } } - 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).') |
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'}
+# Main Handler
+sub handler {
+ my $r=shift;
+ &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
+ ['currentpath','changecourse']);
+ 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)=~/^($match_domain)\/($match_username)\//);
+ if ($uri=~m:/adm/bombs/(.*)$:) {
+ $r->print(&Apache::loncommon::start_page('Error Messages'));
+ # Looking for all bombs?
+ &report_bombs($r,$uri);
+ } elsif ($uri=~m|^/editupload/[^/]+/[^/]+/portfolio/|) {
+ ($resdomain,$resuser)=
+ (&Apache::lonnet::declutter($uri)=~m|^($match_domain)/($match_name)/portfolio|);
+ $r->print(&Apache::loncommon::start_page('Edit Portfolio File Catalog Information',
+ undef,
+ {'domain' => $resdomain,}));
+ if ($env{'form.store'}) {
+ &present_editable_metadata($r,$uri,'portfolio');
+ } else {
+ my $fn=&Apache::lonnet::filelocation('',$uri);
+ %Apache::lonpublisher::metadatafields=();
+ %Apache::lonpublisher::metadatakeys=();
+ my $result=&Apache::lonnet::getfile($fn);
+ &Apache::lonpublisher::metaeval($result);
+ if ((!$Apache::lonpublisher::metadatafields{'courserestricted'}) ||
+ ($env{'form.changecourse'} eq 'true')) {
+ &pre_select_course($r,$uri);
+ } else {
+ &present_editable_metadata($r,$uri,'portfolio');
+ }
+ }
+ } elsif ($uri=~m|^/editupload/[^/]+/[^/]+/groups/|) {
+ $r->print(&Apache::loncommon::start_page('Edit Group Portfolio File Catalog Information',
+ undef,
+ {'domain' => $resdomain,}));
+ &present_editable_metadata($r,$uri,'groups');
+ } elsif ($uri=~m|^/~|) {
+ # Construction space
+ $r->print(&Apache::loncommon::start_page('Edit Catalog Information',
+ "\n".'',
+ {'domain' => $resdomain,}));
+ &present_editable_metadata($r,$uri);
+ } else {
+ $r->print(&Apache::loncommon::start_page('Metadata',
+ undef,
+ {'domain' => $resdomain,}));
+ &present_uneditable_metadata($r,$uri);
+ }
+ $r->print(&Apache::loncommon::end_page());
+ return OK;
+}
+
+#####################################################
+#####################################################
+### ###
+### 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=~/^($match_domain)\/($match_username)\//); + 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'); + my $cancel=&mt('Back to Directory'); + my $cancelurl=$uri; + $cancelurl=~s/^\Q$domain\E/\/priv/; + $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; +} + +##################################################### +##################################################### +### ### +### Uneditable Metadata Display ### +### ### +##################################################### +##################################################### +sub present_uneditable_metadata { + my ($r,$uri) = @_; + # + my $uploaded = ($uri =~ m|/uploaded/|); + 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_with_no_wrapper($uri); + # version + my $versiondisplay=''; + if (!$uploaded) { + my $currentversion=&Apache::lonnet::getversion($disuri); + 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'; + } + my @fields; + if ($uploaded) { + @fields = ('title','author','subject','keywords','notes','abstract', + 'lowestgradelevel','highestgradelevel','standards','mime', + 'owner'); + } else { + @fields = ('title', + 'author', + 'subject', + 'keywords', + 'notes', + 'abstract', + 'lowestgradelevel', + 'highestgradelevel', + 'standards', + 'mime', + 'language', + 'creationdate', + 'lastrevisiondate', + 'owner', + 'copyright', + 'customdistributionfile', + 'sourceavail', + 'sourcerights', + 'obsolete', + 'obsoletereplacement'); + } + foreach my $field (@fields) { + $table.=''.$lt{$field}.
+ ' | '.
+ &prettyprint($field,$content{$field}).' |
+$disuri 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( -' |
'.$items{$_}.' | '. -$dynmeta{$_}." |
'.$items{$_}.' | '. -$dynmeta{$_}." |
'.$items{$_}.' | '. -$dynmeta{$_}." |
'.$dynmeta{'comments'}.''); - } -# ------------------------------------------------------------- All other stuff - $r->print( - '