![]() ![]() | ![]() |
Allow to continue when no meta file exists.
1: # The LearningOnline Network with CAPA 2: # Metadata display handler 3: # 4: # $Id: lonmeta.pm,v 1.97 2005/05/09 01:51:44 banghart Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: 28: 29: package Apache::lonmeta; 30: 31: use strict; 32: use LONCAPA::lonmetadata(); 33: use Apache::Constants qw(:common); 34: use Apache::lonnet; 35: use Apache::loncommon(); 36: use Apache::lonhtmlcommon(); 37: use Apache::lonmsg; 38: use Apache::lonpublisher; 39: use Apache::lonlocal; 40: use Apache::lonmysql; 41: use Apache::lonmsg; 42: 43: 44: ############################################################ 45: ############################################################ 46: ## 47: ## &get_dynamic_metadata_from_sql($url) 48: ## 49: ## Queries sql database for dynamic metdata 50: ## Returns a hash of hashes, with keys of urls which match $url 51: ## Returned fields are given below. 52: ## 53: ## Examples: 54: ## 55: ## %DynamicMetadata = &Apache::lonmeta::get_dynmaic_metadata_from_sql 56: ## ('/res/msu/korte/'); 57: ## 58: ## $DynamicMetadata{'/res/msu/korte/example.problem'}->{$field} 59: ## 60: ############################################################ 61: ############################################################ 62: sub get_dynamic_metadata_from_sql { 63: my ($url) = shift(); 64: my ($authordom,$author)=($url=~m:^/res/(\w+)/(\w+)/:); 65: if (! defined($authordom)) { 66: $authordom = shift(); 67: } 68: if (! defined($author)) { 69: $author = shift(); 70: } 71: if (! defined($authordom) || ! defined($author)) { 72: return (); 73: } 74: my @Fields = ('url','count','course', 75: 'goto','goto_list', 76: 'comefrom','comefrom_list', 77: 'sequsage','sequsage_list', 78: 'stdno','stdno_list', 79: 'dependencies', 80: 'avetries','avetries_list', 81: 'difficulty','difficulty_list', 82: 'disc','disc_list', 83: 'clear','technical','correct', 84: 'helpful','depth'); 85: # 86: my $query = 'SELECT '.join(',',@Fields). 87: ' FROM metadata WHERE url LIKE "'.$url.'%"'; 88: my $server = &Apache::lonnet::homeserver($author,$authordom); 89: my $reply = &Apache::lonnet::metadata_query($query,undef,undef, 90: ,[$server]); 91: return () if (! defined($reply) || ref($reply) ne 'HASH'); 92: my $filename = $reply->{$server}; 93: if (! defined($filename) || $filename =~ /^error/) { 94: return (); 95: } 96: my $max_time = time + 10; # wait 10 seconds for results at most 97: my %ReturnHash; 98: # 99: # Look for results 100: my $finished = 0; 101: while (! $finished && time < $max_time) { 102: my $datafile=$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename; 103: if (! -e "$datafile.end") { next; } 104: my $fh; 105: if (!($fh=Apache::File->new($datafile))) { next; } 106: while (my $result = <$fh>) { 107: chomp($result); 108: next if (! $result); 109: my @Data = 110: map { 111: &Apache::lonnet::unescape($_); 112: } split(',',$result); 113: my $url = $Data[0]; 114: for (my $i=0;$i<=$#Fields;$i++) { 115: $ReturnHash{$url}->{$Fields[$i]}=$Data[$i]; 116: } 117: } 118: $finished = 1; 119: } 120: # 121: return %ReturnHash; 122: } 123: 124: 125: # Fetch and evaluate dynamic metadata 126: sub dynamicmeta { 127: my $url=&Apache::lonnet::declutter(shift); 128: $url=~s/\.meta$//; 129: my ($adomain,$aauthor)=($url=~/^(\w+)\/(\w+)\//); 130: my $regexp=$url; 131: $regexp=~s/(\W)/\\$1/g; 132: $regexp='___'.$regexp.'___'; 133: my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain, 134: $aauthor,$regexp); 135: my %DynamicData = &LONCAPA::lonmetadata::process_reseval_data(\%evaldata); 136: my %Data = &LONCAPA::lonmetadata::process_dynamic_metadata($url, 137: \%DynamicData); 138: # 139: # Deal with 'count' separately 140: $Data{'count'} = &access_count($url,$aauthor,$adomain); 141: # 142: # Debugging code I will probably need later 143: if (0) { 144: &Apache::lonnet::logthis('Dynamic Metadata'); 145: while(my($k,$v)=each(%Data)){ 146: &Apache::lonnet::logthis(' "'.$k.'"=>"'.$v.'"'); 147: } 148: &Apache::lonnet::logthis('-------------------'); 149: } 150: return %Data; 151: } 152: 153: sub access_count { 154: my ($src,$author,$adomain) = @_; 155: my %countdata=&Apache::lonnet::dump('nohist_accesscount',$adomain, 156: $author,$src); 157: if (! exists($countdata{$src})) { 158: return &mt('Not Available'); 159: } else { 160: return $countdata{$src}; 161: } 162: } 163: 164: # Try to make an alt tag if there is none 165: sub alttag { 166: my ($base,$src)=@_; 167: my $fullpath=&Apache::lonnet::hreflocation($base,$src); 168: my $alttag=&Apache::lonnet::metadata($fullpath,'title').' '. 169: &Apache::lonnet::metadata($fullpath,'subject').' '. 170: &Apache::lonnet::metadata($fullpath,'abstract'); 171: $alttag=~s/\s+/ /gs; 172: $alttag=~s/\"//gs; 173: $alttag=~s/\'//gs; 174: $alttag=~s/\s+$//gs; 175: $alttag=~s/^\s+//gs; 176: if ($alttag) { 177: return $alttag; 178: } else { 179: return &mt('No information available'); 180: } 181: } 182: 183: # Author display 184: sub authordisplay { 185: my ($aname,$adom)=@_; 186: return &Apache::loncommon::aboutmewrapper 187: (&Apache::loncommon::plainname($aname,$adom), 188: $aname,$adom,'preview').' <tt>['.$aname.'@'.$adom.']</tt>'; 189: } 190: 191: # Pretty display 192: sub evalgraph { 193: my $value=shift; 194: if (! $value) { 195: return ''; 196: } 197: my $val=int($value*10.+0.5)-10; 198: my $output='<table border="0" cellpadding="0" cellspacing="0"><tr>'; 199: if ($val>=20) { 200: $output.='<td width="20" bgcolor="#555555">  </td>'; 201: } else { 202: $output.='<td width="'.($val).'" bgcolor="#555555"> </td>'. 203: '<td width="'.(20-$val).'" bgcolor="#FF3333"> </td>'; 204: } 205: $output.='<td bgcolor="#FFFF33"> </td>'; 206: if ($val>20) { 207: $output.='<td width="'.($val-20).'" bgcolor="#33FF33"> </td>'. 208: '<td width="'.(40-$val).'" bgcolor="#555555"> </td>'; 209: } else { 210: $output.='<td width="20" bgcolor="#555555">  </td>'; 211: } 212: $output.='<td> ('.sprintf("%5.2f",$value).') </td></tr></table>'; 213: return $output; 214: } 215: 216: sub diffgraph { 217: my $value=shift; 218: if (! $value) { 219: return ''; 220: } 221: my $val=int(40.0*$value+0.5); 222: my @colors=('#FF9933','#EEAA33','#DDBB33','#CCCC33', 223: '#BBDD33','#CCCC33','#DDBB33','#EEAA33'); 224: my $output='<table border="0" cellpadding="0" cellspacing="0"><tr>'; 225: for (my $i=0;$i<8;$i++) { 226: if ($val>$i*5) { 227: $output.='<td width="5" bgcolor="'.$colors[$i].'"> </td>'; 228: } else { 229: $output.='<td width="5" bgcolor="#555555"> </td>'; 230: } 231: } 232: $output.='<td> ('.sprintf("%3.2f",$value).') </td></tr></table>'; 233: return $output; 234: } 235: 236: 237: # The field names 238: sub fieldnames { 239: my $file_type=shift; 240: my %fields = 241: ('title' => 'Title', 242: 'author' =>'Author(s)', 243: 'authorspace' => 'Author Space', 244: 'modifyinguser' => 'Last Modifying User', 245: 'subject' => 'Subject', 246: 'keywords' => 'Keyword(s)', 247: 'notes' => 'Notes', 248: 'abstract' => 'Abstract', 249: 'lowestgradelevel' => 'Lowest Grade Level', 250: 'highestgradelevel' => 'Highest Grade Level'); 251: if (! defined($file_type) || $file_type ne 'portfolio') { 252: %fields = 253: (%fields, 254: 'domain' => 'Domain', 255: 'standards' => 'Standards', 256: 'mime' => 'MIME Type', 257: 'language' => 'Language', 258: 'creationdate' => 'Creation Date', 259: 'lastrevisiondate' => 'Last Revision Date', 260: 'owner' => 'Publisher/Owner', 261: 'copyright' => 'Copyright/Distribution', 262: 'customdistributionfile' => 'Custom Distribution File', 263: 'sourceavail' => 'Source Available', 264: 'sourcerights' => 'Source Custom Distribution File', 265: 'obsolete' => 'Obsolete', 266: 'obsoletereplacement' => 'Suggested Replacement for Obsolete File', 267: 'count' => 'Network-wide number of accesses (hits)', 268: 'course' => 'Network-wide number of courses using resource', 269: 'course_list' => 'Network-wide courses using resource', 270: 'sequsage' => 'Number of resources using or importing resource', 271: 'sequsage_list' => 'Resources using or importing resource', 272: 'goto' => 'Number of resources that follow this resource in maps', 273: 'goto_list' => 'Resources that follow this resource in maps', 274: 'comefrom' => 'Number of resources that lead up to this resource in maps', 275: 'comefrom_list' => 'Resources that lead up to this resource in maps', 276: 'clear' => 'Material presented in clear way', 277: 'depth' => 'Material covered with sufficient depth', 278: 'helpful' => 'Material is helpful', 279: 'correct' => 'Material appears to be correct', 280: 'technical' => 'Resource is technically correct', 281: 'avetries' => 'Average number of tries till solved', 282: 'stdno' => 'Total number of students who have worked on this problem', 283: 'difficulty' => 'Degree of difficulty', 284: 'disc' => 'Degree of discrimination', 285: 'dependencies' => 'Resources used by this resource', 286: ); 287: } 288: return &Apache::lonlocal::texthash(%fields); 289: } 290: 291: # Pretty printing of metadata field 292: 293: sub prettyprint { 294: my ($type,$value,$target,$prefix,$form,$noformat)=@_; 295: # $target,$prefix,$form are optional and for filecrumbs only 296: if (! defined($value)) { 297: return ' '; 298: } 299: # Title 300: if ($type eq 'title') { 301: return '<font size="+1" face="arial">'.$value.'</font>'; 302: } 303: # Dates 304: if (($type eq 'creationdate') || 305: ($type eq 'lastrevisiondate')) { 306: return ($value?&Apache::lonlocal::locallocaltime( 307: &Apache::lonmysql::unsqltime($value)): 308: &mt('not available')); 309: } 310: # Language 311: if ($type eq 'language') { 312: return &Apache::loncommon::languagedescription($value); 313: } 314: # Copyright 315: if ($type eq 'copyright') { 316: return &Apache::loncommon::copyrightdescription($value); 317: } 318: # Copyright 319: if ($type eq 'sourceavail') { 320: return &Apache::loncommon::source_copyrightdescription($value); 321: } 322: # MIME 323: if ($type eq 'mime') { 324: return '<img src="'.&Apache::loncommon::icon($value).'" /> '. 325: &Apache::loncommon::filedescription($value); 326: } 327: # Person 328: if (($type eq 'author') || 329: ($type eq 'owner') || 330: ($type eq 'modifyinguser') || 331: ($type eq 'authorspace')) { 332: $value=~s/(\w+)(\:|\@)(\w+)/&authordisplay($1,$3)/gse; 333: return $value; 334: } 335: # Gradelevel 336: if (($type eq 'lowestgradelevel') || 337: ($type eq 'highestgradelevel')) { 338: return &Apache::loncommon::gradeleveldescription($value); 339: } 340: # Only for advance users below 341: if (! $env{'user.adv'}) { 342: return '<i>- '.&mt('not displayed').' -</i>'; 343: } 344: # File 345: if (($type eq 'customdistributionfile') || 346: ($type eq 'obsoletereplacement') || 347: ($type eq 'goto_list') || 348: ($type eq 'comefrom_list') || 349: ($type eq 'sequsage_list') || 350: ($type eq 'dependencies')) { 351: return '<ul><font size="-1">'.join("\n",map { 352: my $url = &Apache::lonnet::clutter($_); 353: my $title = &Apache::lonnet::gettitle($url); 354: if ($title eq '') { 355: $title = 'Untitled'; 356: if ($url =~ /\.sequence$/) { 357: $title .= ' Sequence'; 358: } elsif ($url =~ /\.page$/) { 359: $title .= ' Page'; 360: } elsif ($url =~ /\.problem$/) { 361: $title .= ' Problem'; 362: } elsif ($url =~ /\.html$/) { 363: $title .= ' HTML document'; 364: } elsif ($url =~ m:/syllabus$:) { 365: $title .= ' Syllabus'; 366: } 367: } 368: $_ = '<li>'.$title.' '. 369: &Apache::lonhtmlcommon::crumbs($url,$target,$prefix,$form,'-1',$noformat). 370: '</li>' 371: } split(/\s*\,\s*/,$value)).'</ul></font>'; 372: } 373: # Evaluations 374: if (($type eq 'clear') || 375: ($type eq 'depth') || 376: ($type eq 'helpful') || 377: ($type eq 'correct') || 378: ($type eq 'technical')) { 379: return &evalgraph($value); 380: } 381: # Difficulty 382: if ($type eq 'difficulty' || $type eq 'disc') { 383: return &diffgraph($value); 384: } 385: # List of courses 386: if ($type=~/\_list/) { 387: my @Courses = split(/\s*\,\s*/,$value); 388: my $Str; 389: foreach my $course (@Courses) { 390: my %courseinfo = &Apache::lonnet::coursedescription($course); 391: if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { 392: next; 393: } 394: if ($Str ne '') { $Str .= '<br />'; } 395: $Str .= '<a href="/public/'.$courseinfo{'domain'}.'/'. 396: $courseinfo{'num'}.'/syllabus" target="preview">'. 397: $courseinfo{'description'}.'</a>'; 398: } 399: return $Str; 400: } 401: # No pretty print found 402: return $value; 403: } 404: 405: # Pretty input of metadata field 406: sub direct { 407: return shift; 408: } 409: 410: sub selectbox { 411: my ($name,$value,$functionref,@idlist)=@_; 412: if (! defined($functionref)) { 413: $functionref=\&direct; 414: } 415: my $selout='<select name="'.$name.'">'; 416: foreach (@idlist) { 417: $selout.='<option value=\''.$_.'\''; 418: if ($_ eq $value) { 419: $selout.=' selected>'.&{$functionref}($_).'</option>'; 420: } 421: else {$selout.='>'.&{$functionref}($_).'</option>';} 422: } 423: return $selout.'</select>'; 424: } 425: 426: sub relatedfield { 427: my ($show,$relatedsearchflag,$relatedsep,$fieldname,$relatedvalue)=@_; 428: if (! $relatedsearchflag) { 429: return ''; 430: } 431: if (! defined($relatedsep)) { 432: $relatedsep=' '; 433: } 434: if (! $show) { 435: return $relatedsep.' '; 436: } 437: return $relatedsep.'<input type="checkbox" name="'.$fieldname.'_related"'. 438: ($relatedvalue?' checked="1"':'').' />'; 439: } 440: 441: sub prettyinput { 442: my ($type,$value,$fieldname,$formname, 443: $relatedsearchflag,$relatedsep,$relatedvalue,$size)=@_; 444: if (! defined($size)) { 445: $size = 80; 446: } 447: # Language 448: if ($type eq 'language') { 449: return &selectbox($fieldname, 450: $value, 451: \&Apache::loncommon::languagedescription, 452: (&Apache::loncommon::languageids)). 453: &relatedfield(0,$relatedsearchflag,$relatedsep); 454: } 455: # Copyright 456: if ($type eq 'copyright') { 457: return &selectbox($fieldname, 458: $value, 459: \&Apache::loncommon::copyrightdescription, 460: (&Apache::loncommon::copyrightids)). 461: &relatedfield(0,$relatedsearchflag,$relatedsep); 462: } 463: # Source Copyright 464: if ($type eq 'sourceavail') { 465: return &selectbox($fieldname, 466: $value, 467: \&Apache::loncommon::source_copyrightdescription, 468: (&Apache::loncommon::source_copyrightids)). 469: &relatedfield(0,$relatedsearchflag,$relatedsep); 470: } 471: # Gradelevels 472: if (($type eq 'lowestgradelevel') || 473: ($type eq 'highestgradelevel')) { 474: return &Apache::loncommon::select_level_form($value,$fieldname). 475: &relatedfield(0,$relatedsearchflag,$relatedsep); 476: } 477: # Obsolete 478: if ($type eq 'obsolete') { 479: return '<input type="checkbox" name="'.$fieldname.'"'. 480: ($value?' checked="1"':'').' />'. 481: &relatedfield(0,$relatedsearchflag,$relatedsep); 482: } 483: # Obsolete replacement file 484: if ($type eq 'obsoletereplacement') { 485: return '<input type="text" name="'.$fieldname. 486: '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. 487: "('".$formname."','".$fieldname."'". 488: ",'')\">".&mt('Select').'</a>'. 489: &relatedfield(0,$relatedsearchflag,$relatedsep); 490: } 491: # Customdistribution file 492: if ($type eq 'customdistributionfile') { 493: return '<input type="text" name="'.$fieldname. 494: '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. 495: "('".$formname."','".$fieldname."'". 496: ",'rights')\">".&mt('Select').'</a>'. 497: &relatedfield(0,$relatedsearchflag,$relatedsep); 498: } 499: # Source Customdistribution file 500: if ($type eq 'sourcerights') { 501: return '<input type="text" name="'.$fieldname. 502: '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. 503: "('".$formname."','".$fieldname."'". 504: ",'rights')\">".&mt('Select').'</a>'. 505: &relatedfield(0,$relatedsearchflag,$relatedsep); 506: } 507: # Dates 508: if (($type eq 'creationdate') || 509: ($type eq 'lastrevisiondate')) { 510: return 511: &Apache::lonhtmlcommon::date_setter($formname,$fieldname,$value). 512: &relatedfield(0,$relatedsearchflag,$relatedsep); 513: } 514: # No pretty input found 515: $value=~s/^\s+//gs; 516: $value=~s/\s+$//gs; 517: $value=~s/\s+/ /gs; 518: $value=~s/\"/\"\;/gs; 519: return 520: '<input type="text" name="'.$fieldname.'" size="'.$size.'" '. 521: 'value="'.$value.'" />'. 522: &relatedfield(1,$relatedsearchflag,$relatedsep,$fieldname, 523: $relatedvalue); 524: } 525: 526: # Main Handler 527: sub handler { 528: my $r=shift; 529: # 530: my $uri=$r->uri; 531: # 532: # Set document type 533: &Apache::loncommon::content_type($r,'text/html'); 534: $r->send_http_header; 535: return OK if $r->header_only; 536: # 537: my ($resdomain,$resuser)= 538: (&Apache::lonnet::declutter($uri)=~/^(\w+)\/(\w+)\//); 539: my $html=&Apache::lonxml::xmlbegin(); 540: $r->print($html.'<head><title>'. 541: 'Catalog Information'. 542: '</title></head>'); 543: if ($uri=~m:/adm/bombs/(.*)$:) { 544: $r->print(&Apache::loncommon::bodytag('Error Messages')); 545: # Looking for all bombs? 546: &report_bombs($r,$uri); 547: } elsif ($uri=~/\/portfolio\//) { 548: $r->print(&Apache::loncommon::bodytag 549: ('Edit Portfolio File Information','','','',$resdomain)); 550: &present_editable_metadata($r,$uri,'portfolio'); 551: 552: } elsif ($uri=~/^\/\~/) { 553: # Construction space 554: $r->print(&Apache::loncommon::bodytag 555: ('Edit Catalog Information','','','',$resdomain)); 556: &present_editable_metadata($r,$uri); 557: } else { 558: $r->print(&Apache::loncommon::bodytag 559: ('Catalog Information','','','',$resdomain)); 560: &present_uneditable_metadata($r,$uri); 561: } 562: $r->print('</body></html>'); 563: return OK; 564: } 565: 566: ##################################################### 567: ##################################################### 568: ### ### 569: ### Report Bombs ### 570: ### ### 571: ##################################################### 572: ##################################################### 573: sub report_bombs { 574: my ($r,$uri) = @_; 575: # Set document type 576: $uri =~ s:/adm/bombs/::; 577: $uri = &Apache::lonnet::declutter($uri); 578: $r->print('<h1>'.&Apache::lonnet::clutter($uri).'</h1>'); 579: my ($domain,$author)=($uri=~/^(\w+)\/(\w+)\//); 580: if (&Apache::loncacc::constructaccess('/~'.$author.'/',$domain)) { 581: my %brokenurls = 582: &Apache::lonmsg::all_url_author_res_msg($author,$domain); 583: foreach (sort(keys(%brokenurls))) { 584: if ($_=~/^\Q$uri\E/) { 585: $r->print 586: ('<a href="'.&Apache::lonnet::clutter($_).'">'.$_.'</a>'. 587: &Apache::lonmsg::retrieve_author_res_msg($_). 588: '<hr />'); 589: } 590: } 591: } else { 592: $r->print(&mt('Not authorized')); 593: } 594: return; 595: } 596: 597: ##################################################### 598: ##################################################### 599: ### ### 600: ### Uneditable Metadata Display ### 601: ### ### 602: ##################################################### 603: ##################################################### 604: sub present_uneditable_metadata { 605: my ($r,$uri) = @_; 606: # 607: my %content=(); 608: # Read file 609: foreach (split(/\,/,&Apache::lonnet::metadata($uri,'keys'))) { 610: $content{$_}=&Apache::lonnet::metadata($uri,$_); 611: } 612: # Render Output 613: # displayed url 614: my ($thisversion)=($uri=~/\.(\d+)\.(\w+)\.meta$/); 615: $uri=~s/\.meta$//; 616: my $disuri=&Apache::lonnet::clutter($uri); 617: # version 618: my $currentversion=&Apache::lonnet::getversion($disuri); 619: my $versiondisplay=''; 620: if ($thisversion) { 621: $versiondisplay=&mt('Version').': '.$thisversion. 622: ' ('.&mt('most recent version').': '. 623: ($currentversion>0 ? 624: $currentversion : 625: &mt('information not available')).')'; 626: } else { 627: $versiondisplay='Version: '.$currentversion; 628: } 629: # crumbify displayed URL uri target prefix form size 630: $disuri=&Apache::lonhtmlcommon::crumbs($disuri,undef, undef, undef,'+1'); 631: $disuri =~ s:<br />::g; 632: # obsolete 633: my $obsolete=$content{'obsolete'}; 634: my $obsoletewarning=''; 635: if (($obsolete) && ($env{'user.adv'})) { 636: $obsoletewarning='<p><font color="red">'. 637: &mt('This resource has been marked obsolete by the author(s)'). 638: '</font></p>'; 639: } 640: # 641: my %lt=&fieldnames(); 642: my $table=''; 643: my $title = $content{'title'}; 644: if (! defined($title)) { 645: $title = 'Untitled Resource'; 646: } 647: foreach ('title', 648: 'author', 649: 'subject', 650: 'keywords', 651: 'notes', 652: 'abstract', 653: 'lowestgradelevel', 654: 'highestgradelevel', 655: 'standards', 656: 'mime', 657: 'language', 658: 'creationdate', 659: 'lastrevisiondate', 660: 'owner', 661: 'copyright', 662: 'customdistributionfile', 663: 'sourceavail', 664: 'sourcerights', 665: 'obsolete', 666: 'obsoletereplacement') { 667: $table.='<tr><td bgcolor="#AAAAAA">'.$lt{$_}. 668: '</td><td bgcolor="#CCCCCC">'. 669: &prettyprint($_,$content{$_}).'</td></tr>'; 670: delete $content{$_}; 671: } 672: # 673: $r->print(<<ENDHEAD); 674: <h2>$title</h2> 675: <p> 676: $disuri<br /> 677: $obsoletewarning 678: $versiondisplay 679: </p> 680: <table cellspacing="2" border="0"> 681: $table 682: </table> 683: ENDHEAD 684: if ($env{'user.adv'}) { 685: &print_dynamic_metadata($r,$uri,\%content); 686: } 687: return; 688: } 689: 690: sub print_dynamic_metadata { 691: my ($r,$uri,$content) = @_; 692: # 693: my %content = %$content; 694: my %lt=&fieldnames(); 695: # 696: my $description = 'Dynamic Metadata (updated periodically)'; 697: $r->print('<h3>'.&mt($description).'</h3>'. 698: &mt('Processing')); 699: $r->rflush(); 700: my %items=&fieldnames(); 701: my %dynmeta=&dynamicmeta($uri); 702: # 703: # General Access and Usage Statistics 704: if (exists($dynmeta{'count'}) || 705: exists($dynmeta{'sequsage'}) || 706: exists($dynmeta{'comefrom'}) || 707: exists($dynmeta{'goto'}) || 708: exists($dynmeta{'course'})) { 709: $r->print('<h4>'.&mt('Access and Usage Statistics').'</h4>'. 710: '<table cellspacing="2" border="0">'); 711: foreach ('count', 712: 'sequsage','sequsage_list', 713: 'comefrom','comefrom_list', 714: 'goto','goto_list', 715: 'course','course_list') { 716: $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'. 717: '<td bgcolor="#CCCCCC">'. 718: &prettyprint($_,$dynmeta{$_})."</td></tr>\n"); 719: } 720: $r->print('</table>'); 721: } else { 722: $r->print('<h4>'.&mt('No Access or Usages Statistics are available for this resource.').'</h4>'); 723: } 724: # 725: # Assessment statistics 726: if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/) { 727: if (exists($dynmeta{'stdno'}) || 728: exists($dynmeta{'avetries'}) || 729: exists($dynmeta{'difficulty'}) || 730: exists($dynmeta{'disc'})) { 731: # This is an assessment, print assessment data 732: $r->print('<h4>'. 733: &mt('Overall Assessment Statistical Data'). 734: '</h4>'. 735: '<table cellspacing="2" border="0">'); 736: $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{'stdno'}.'</td>'. 737: '<td bgcolor="#CCCCCC">'. 738: &prettyprint('stdno',$dynmeta{'stdno'}). 739: '</td>'."</tr>\n"); 740: foreach ('avetries','difficulty','disc') { 741: $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'. 742: '<td bgcolor="#CCCCCC">'. 743: &prettyprint($_,sprintf('%5.2f',$dynmeta{$_})). 744: '</td>'."</tr>\n"); 745: } 746: $r->print('</table>'); 747: } 748: if (exists($dynmeta{'stats'})) { 749: # 750: # New assessment statistics 751: $r->print('<h4>'. 752: &mt('Detailed Assessment Statistical Data'). 753: '</h4>'); 754: my $table = '<table cellspacing="2" border="0">'. 755: '<tr>'. 756: '<th>Course</th>'. 757: '<th>Section(s)</th>'. 758: '<th>Num Students</th>'. 759: '<th>Mean Tries</th>'. 760: '<th>Degree of Difficulty</th>'. 761: '<th>Degree of Discrimination</th>'. 762: '<th>Time of computation</th>'. 763: '</tr>'.$/; 764: foreach my $identifier (sort(keys(%{$dynmeta{'stats'}}))) { 765: my $data = $dynmeta{'stats'}->{$identifier}; 766: my $course = $data->{'course'}; 767: my %courseinfo = &Apache::lonnet::coursedescription($course); 768: if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { 769: &Apache::lonnet::logthis('lookup for '.$course.' failed'); 770: next; 771: } 772: $table .= '<tr>'; 773: $table .= 774: '<td><nobr>'.$courseinfo{'description'}.'</nobr></td>'; 775: $table .= 776: '<td align="right">'.$data->{'sections'}.'</td>'; 777: $table .= 778: '<td align="right">'.$data->{'stdno'}.'</td>'; 779: foreach ('avetries','difficulty','disc') { 780: $table .= '<td align="right">'; 781: if (exists($data->{$_})) { 782: $table .= sprintf('%.2f',$data->{$_}).' '; 783: } else { 784: $table .= ''; 785: } 786: $table .= '</td>'; 787: } 788: $table .= 789: '<td><nobr>'. 790: &Apache::lonlocal::locallocaltime($data->{'timestamp'}). 791: '</nobr></td>'; 792: $table .= 793: '</tr>'.$/; 794: } 795: $table .= '</table>'.$/; 796: $r->print($table); 797: } else { 798: $r->print('No new dynamic data found.'); 799: } 800: } else { 801: $r->print('<h4>'. 802: &mt('No Assessment Statistical Data is available for this resource'). 803: '</h4>'); 804: } 805: 806: # 807: # 808: if (exists($dynmeta{'clear'}) || 809: exists($dynmeta{'depth'}) || 810: exists($dynmeta{'helpful'}) || 811: exists($dynmeta{'correct'}) || 812: exists($dynmeta{'technical'})){ 813: $r->print('<h4>'.&mt('Evaluation Data').'</h4>'. 814: '<table cellspacing="2" border="0">'); 815: foreach ('clear','depth','helpful','correct','technical') { 816: $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'. 817: '<td bgcolor="#CCCCCC">'. 818: &prettyprint($_,$dynmeta{$_})."</td></tr>\n"); 819: } 820: $r->print('</table>'); 821: } else { 822: $r->print('<h4>'.&mt('No Evaluation Data is available for this resource.').'</h4>'); 823: } 824: $uri=~/^\/res\/(\w+)\/(\w+)\//; 825: if ((($env{'user.domain'} eq $1) && ($env{'user.name'} eq $2)) 826: || ($env{'user.role.ca./'.$1.'/'.$2})) { 827: if (exists($dynmeta{'comments'})) { 828: $r->print('<h4>'.&mt('Evaluation Comments').' ('. 829: &mt('visible to author and co-authors only'). 830: ')</h4>'. 831: '<blockquote>'.$dynmeta{'comments'}.'</blockquote>'); 832: } else { 833: $r->print('<h4>'.&mt('There are no Evaluation Comments on this resource.').'</h4>'); 834: } 835: my $bombs = &Apache::lonmsg::retrieve_author_res_msg($uri); 836: if (defined($bombs) && $bombs ne '') { 837: $r->print('<a name="bombs" /><h4>'.&mt('Error Messages').' ('. 838: &mt('visible to author and co-authors only').')'. 839: '</h4>'.$bombs); 840: } else { 841: $r->print('<h4>'.&mt('There are currently no Error Messages for this resource.').'</h4>'); 842: } 843: } 844: # 845: # All other stuff 846: $r->print('<h3>'. 847: &mt('Additional Metadata (non-standard, parameters, exports)'). 848: '</h3><table border="0" cellspacing="1">'); 849: foreach (sort(keys(%content))) { 850: my $name=$_; 851: if ($name!~/\.display$/) { 852: my $display=&Apache::lonnet::metadata($uri, 853: $name.'.display'); 854: if (! $display) { 855: $display=$name; 856: }; 857: my $otherinfo=''; 858: foreach ('name','part','type','default') { 859: if (defined(&Apache::lonnet::metadata($uri, 860: $name.'.'.$_))) { 861: $otherinfo.=' '.$_.'='. 862: &Apache::lonnet::metadata($uri, 863: $name.'.'.$_).'; '; 864: } 865: } 866: $r->print('<tr><td bgcolor="#bbccbb"><font size="-1" color="#556655">'.$display.'</font></td><td bgcolor="#ccddcc"><font size="-1" color="#556655">'.$content{$name}); 867: if ($otherinfo) { 868: $r->print(' ('.$otherinfo.')'); 869: } 870: $r->print("</font></td></tr>\n"); 871: } 872: } 873: $r->print("</table>"); 874: return; 875: } 876: 877: ##################################################### 878: ##################################################### 879: ### ### 880: ### Editable metadata display ### 881: ### ### 882: ##################################################### 883: ##################################################### 884: sub present_editable_metadata { 885: my ($r,$uri, $file_type) = @_; 886: # Construction Space Call 887: # Header 888: my $disuri=$uri; 889: my $fn=&Apache::lonnet::filelocation('',$uri); 890: $disuri=~s/^\/\~/\/priv\//; 891: $disuri=~s/\.meta$//; 892: my $target=$uri; 893: $target=~s/^\/\~/\/res\/$env{'request.role.domain'}\//; 894: $target=~s/\.meta$//; 895: my $bombs=&Apache::lonmsg::retrieve_author_res_msg($target); 896: if ($bombs) { 897: if ($env{'form.delmsg'}) { 898: if (&Apache::lonmsg::del_url_author_res_msg($target) eq 'ok') { 899: $bombs=&mt('Messages deleted.'); 900: } else { 901: $bombs=&mt('Error deleting messages'); 902: } 903: } 904: my $del=&mt('Delete Messages'); 905: $r->print(<<ENDBOMBS); 906: <h1>$disuri</h1> 907: <form method="post" name="defaultmeta"> 908: <input type="submit" name="delmsg" value="$del" /> 909: <br />$bombs 910: ENDBOMBS 911: } else { 912: my $displayfile='Catalog Information for '.$disuri; 913: if ($disuri=~/\/default$/) { 914: my $dir=$disuri; 915: $dir=~s/default$//; 916: $displayfile= 917: &mt('Default Cataloging Information for Directory').' '. 918: $dir; 919: } 920: %Apache::lonpublisher::metadatafields=(); 921: %Apache::lonpublisher::metadatakeys=(); 922: my $result=&Apache::lonnet::getfile($fn); 923: if ($result == -1){ 924: $r->print('Creating new '.$fn); 925: } else { 926: &Apache::lonpublisher::metaeval($result); 927: } 928: $r->print(<<ENDEDIT); 929: <h1>$displayfile</h1> 930: <form method="post" name="defaultmeta"> 931: ENDEDIT 932: $r->print('<script language="JavaScript">'. 933: &Apache::loncommon::browser_and_searcher_javascript(). 934: '</script>'); 935: my %lt=&fieldnames($file_type); 936: my $output; 937: my @fields; 938: if ($file_type eq 'portfolio') { 939: @fields = ('author','title','subject','keywords','abstract','notes','lowestgradelevel', 940: 'highestgradelevel'); 941: } else { 942: @fields = ('author','title','subject','keywords','abstract','notes', 943: 'copyright','customdistributionfile','language', 944: 'standards', 945: 'lowestgradelevel','highestgradelevel','sourceavail','sourcerights', 946: 'obsolete','obsoletereplacement'); 947: } 948: foreach (@fields) { 949: if (defined($env{'form.new_'.$_})) { 950: $Apache::lonpublisher::metadatafields{$_}= 951: $env{'form.new_'.$_}; 952: } 953: if (! $Apache::lonpublisher::metadatafields{'copyright'}) { 954: $Apache::lonpublisher::metadatafields{'copyright'}= 955: 'default'; 956: } 957: $output.=('<p>'.$lt{$_}.': '. 958: &prettyinput($_, 959: $Apache::lonpublisher::metadatafields{$_}, 960: 'new_'.$_,'defaultmeta').'</p>'); 961: } 962: if ($env{'form.store'}) { 963: my $mfh; 964: my $formname='store'; 965: my $file_content; 966: foreach (sort keys %Apache::lonpublisher::metadatafields) { 967: next if ($_ =~ /\./); 968: my $unikey=$_; 969: $unikey=~/^([A-Za-z]+)/; 970: my $tag=$1; 971: $tag=~tr/A-Z/a-z/; 972: $file_content.= "\n\<$tag"; 973: foreach (split(/\,/, 974: $Apache::lonpublisher::metadatakeys{$unikey}) 975: ) { 976: my $value= 977: $Apache::lonpublisher::metadatafields{$unikey.'.'.$_}; 978: $value=~s/\"/\'\'/g; 979: $file_content.=' '.$_.'="'.$value.'"' ; 980: # print $mfh ' '.$_.'="'.$value.'"'; 981: } 982: $file_content.= '>'. 983: &HTML::Entities::encode 984: ($Apache::lonpublisher::metadatafields{$unikey}, 985: '<>&"'). 986: '</'.$tag.'>'; 987: } 988: if ($fn =~ /\/portfolio\//) { 989: $fn =~ /\/portfolio\/(.*)$/; 990: my $new_fn = '/'.$1; 991: $env{'form.'.$formname}=$file_content; 992: $env{'form.'.$formname.'.filename'}=$new_fn; 993: &Apache::lonnet::userfileupload('uploaddoc','', 994: 'portfolio'.$env{'form.currentpath'}); 995: my $status =&Apache::lonnet::userfileupload($formname,'','portfolio'); 996: if (&Apache::lonnet::userfileupload($formname,'','portfolio') eq 'error: no uploaded file') { 997: $r->print('<p><font color="red">'. 998: &mt('Could not write metadata').', '. 999: &mt('FAIL').'</font></p>'); 1000: } else { 1001: $r->print('<p><font color="blue">'.&mt('Wrote Metadata'). 1002: ' '.&Apache::lonlocal::locallocaltime(time). 1003: '</font></p>'); 1004: } 1005: } else { 1006: if (! ($mfh=Apache::File->new('>'.$fn))) { 1007: $r->print('<p><font color="red">'. 1008: &mt('Could not write metadata').', '. 1009: &mt('FAIL').'</font></p>'); 1010: } else { 1011: print $mfh $file_content; 1012: $r->print('<p><font color="blue">'.&mt('Wrote Metadata'). 1013: ' '.&Apache::lonlocal::locallocaltime(time). 1014: '</font></p>'); 1015: } 1016: } 1017: } 1018: $r->print($output.'<br /><input type="submit" name="store" value="'. 1019: &mt('Store Catalog Information').'">'); 1020: } 1021: $r->print('</form>'); 1022: return; 1023: } 1024: 1025: 1; 1026: __END__ 1027: 1028: