![]() ![]() | ![]() |
- Remove duplicate concatenation operators.
1: # The LearningOnline Network with CAPA 2: # Metadata display handler 3: # 4: # $Id: lonmeta.pm,v 1.212.2.4 2008/12/17 18:47:08 raeburn 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: use LONCAPA qw(:DEFAULT :match); 43: 44: 45: ############################################################ 46: ############################################################ 47: ## 48: ## &get_dynamic_metadata_from_sql($url) 49: ## 50: ## Queries sql database for dynamic metdata 51: ## Returns a hash of hashes, with keys of urls which match $url 52: ## Returned fields are given below. 53: ## 54: ## Examples: 55: ## 56: ## %DynamicMetadata = &Apache::lonmeta::get_dynmaic_metadata_from_sql 57: ## ('/res/msu/korte/'); 58: ## 59: ## $DynamicMetadata{'/res/msu/korte/example.problem'}->{$field} 60: ## 61: ############################################################ 62: ############################################################ 63: sub get_dynamic_metadata_from_sql { 64: my ($url) = shift(); 65: my ($authordom,$author)=($url=~m{^/res/($match_domain)/($match_username)/}); 66: if (! defined($authordom)) { 67: $authordom = shift(); 68: } 69: if (! defined($author)) { 70: $author = shift(); 71: } 72: if (! defined($authordom) || ! defined($author)) { 73: return (); 74: } 75: my $query = 'SELECT * FROM metadata WHERE url LIKE "'.$url.'%"'; 76: my $server = &Apache::lonnet::homeserver($author,$authordom); 77: my $reply = &Apache::lonnet::metadata_query($query,undef,undef, 78: ,[$server]); 79: return () if (! defined($reply) || ref($reply) ne 'HASH'); 80: my $filename = $reply->{$server}; 81: if (! defined($filename) || $filename =~ /^error/) { 82: return (); 83: } 84: my $max_time = time + 10; # wait 10 seconds for results at most 85: my %ReturnHash; 86: # 87: # Look for results 88: my $finished = 0; 89: while (! $finished && time < $max_time) { 90: my $datafile=$Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/'.$filename; 91: if (! -e "$datafile.end") { next; } 92: my $fh; 93: if (!($fh=Apache::File->new($datafile))) { next; } 94: while (my $result = <$fh>) { 95: chomp($result); 96: next if (! $result); 97: my %hash=&LONCAPA::lonmetadata::metadata_col_to_hash('metadata', 98: map { &unescape($_) } split(/\,/,$result)); 99: foreach my $key (keys(%hash)) { 100: $ReturnHash{$hash{'url'}}->{$key}=$hash{$key}; 101: } 102: } 103: $finished = 1; 104: } 105: # 106: return %ReturnHash; 107: } 108: 109: 110: # Fetch and evaluate dynamic metadata 111: sub dynamicmeta { 112: my $url=&Apache::lonnet::declutter(shift); 113: $url=~s/\.meta$//; 114: my ($adomain,$aauthor)=($url=~/^($match_domain)\/($match_username)\//); 115: my $regexp=$url; 116: $regexp=~s/(\W)/\\$1/g; 117: $regexp='___'.$regexp.'___'; 118: my %evaldata=&Apache::lonnet::dump('nohist_resevaldata',$adomain, 119: $aauthor,$regexp); 120: my %DynamicData = &LONCAPA::lonmetadata::process_reseval_data(\%evaldata); 121: my %Data = &LONCAPA::lonmetadata::process_dynamic_metadata($url, 122: \%DynamicData); 123: # 124: # Deal with 'count' separately 125: $Data{'count'} = &access_count($url,$aauthor,$adomain); 126: # 127: # Debugging code I will probably need later 128: if (0) { 129: &Apache::lonnet::logthis('Dynamic Metadata'); 130: while(my($k,$v)=each(%Data)){ 131: &Apache::lonnet::logthis(' "'.$k.'"=>"'.$v.'"'); 132: } 133: &Apache::lonnet::logthis('-------------------'); 134: } 135: return %Data; 136: } 137: 138: sub access_count { 139: my ($src,$author,$adomain) = @_; 140: my %countdata=&Apache::lonnet::dump('nohist_accesscount',$adomain, 141: $author,$src); 142: if (! exists($countdata{$src})) { 143: return &mt('Not Available'); 144: } else { 145: return $countdata{$src}; 146: } 147: } 148: 149: # Try to make an alt tag if there is none 150: sub alttag { 151: my ($base,$src)=@_; 152: my $fullpath=&Apache::lonnet::hreflocation($base,$src); 153: my $alttag=&Apache::lonnet::metadata($fullpath,'title').' '. 154: &Apache::lonnet::metadata($fullpath,'subject').' '. 155: &Apache::lonnet::metadata($fullpath,'abstract'); 156: $alttag=~s/\s+/ /gs; 157: $alttag=~s/\"//gs; 158: $alttag=~s/\'//gs; 159: $alttag=~s/\s+$//gs; 160: $alttag=~s/^\s+//gs; 161: if ($alttag) { 162: return $alttag; 163: } else { 164: return &mt('No information available'); 165: } 166: } 167: 168: # Author display 169: sub authordisplay { 170: my ($aname,$adom)=@_; 171: return &Apache::loncommon::aboutmewrapper 172: (&Apache::loncommon::plainname($aname,$adom), 173: $aname,$adom,'preview').' <tt>['.$aname.':'.$adom.']</tt>'; 174: } 175: 176: # Pretty display 177: sub evalgraph { 178: my $value=shift; 179: if (! $value) { 180: return ''; 181: } 182: my $val=int($value*10.+0.5)-10; 183: my $output='<table border="0" cellpadding="0" cellspacing="0"><tr>'; 184: if ($val>=20) { 185: $output.='<td width="20" bgcolor="#555555">'.(' ' x2).'</td>'; 186: } else { 187: $output.='<td width="'.($val).'" bgcolor="#555555"> </td>'. 188: '<td width="'.(20-$val).'" bgcolor="#FF3333"> </td>'; 189: } 190: $output.='<td bgcolor="#FFFF33"> </td>'; 191: if ($val>20) { 192: $output.='<td width="'.($val-20).'" bgcolor="#33FF33"> </td>'. 193: '<td width="'.(40-$val).'" bgcolor="#555555"> </td>'; 194: } else { 195: $output.='<td width="20" bgcolor="#555555">'.(' ' x2).'</td>'; 196: } 197: $output.='<td> ('.sprintf("%5.2f",$value).') </td></tr></table>'; 198: return $output; 199: } 200: 201: sub diffgraph { 202: my $value=shift; 203: if (! $value) { 204: return ''; 205: } 206: my $val=int(40.0*$value+0.5); 207: my @colors=('#FF9933','#EEAA33','#DDBB33','#CCCC33', 208: '#BBDD33','#CCCC33','#DDBB33','#EEAA33'); 209: my $output='<table border="0" cellpadding="0" cellspacing="0"><tr>'; 210: for (my $i=0;$i<8;$i++) { 211: if ($val>$i*5) { 212: $output.='<td width="5" bgcolor="'.$colors[$i].'"> </td>'; 213: } else { 214: $output.='<td width="5" bgcolor="#555555"> </td>'; 215: } 216: } 217: $output.='<td> ('.sprintf("%3.2f",$value).') </td></tr></table>'; 218: return $output; 219: } 220: 221: 222: # The field names 223: sub fieldnames { 224: my $file_type=shift; 225: my %fields = 226: ('title' => 'Title', 227: 'author' =>'Author(s)', 228: 'authorspace' => 'Author Space', 229: 'modifyinguser' => 'Last Modifying User', 230: 'subject' => 'Subject', 231: 'standards' => 'Standards', 232: 'keywords' => 'Keyword(s)', 233: 'notes' => 'Notes', 234: 'abstract' => 'Abstract', 235: 'lowestgradelevel' => 'Lowest Grade Level', 236: 'highestgradelevel' => 'Highest Grade Level'); 237: 238: if ( !defined($file_type) || ($file_type ne 'portfolio' && $file_type ne 'groups') ) { 239: %fields = 240: (%fields, 241: 'domain' => 'Domain', 242: 'mime' => 'MIME Type', 243: 'language' => 'Language', 244: 'creationdate' => 'Creation Date', 245: 'lastrevisiondate' => 'Last Revision Date', 246: 'owner' => 'Publisher/Owner', 247: 'copyright' => 'Copyright/Distribution', 248: 'customdistributionfile' => 'Custom Distribution File', 249: 'sourceavail' => 'Source Available', 250: 'sourcerights' => 'Source Custom Distribution File', 251: 'obsolete' => 'Obsolete', 252: 'obsoletereplacement' => 'Suggested Replacement for Obsolete File', 253: 'count' => 'Network-wide number of accesses (hits)', 254: 'course' => 'Network-wide number of courses using resource', 255: 'course_list' => 'Network-wide courses using resource', 256: 'sequsage' => 'Number of resources using or importing resource', 257: 'sequsage_list' => 'Resources using or importing resource', 258: 'goto' => 'Number of resources that follow this resource in maps', 259: 'goto_list' => 'Resources that follow this resource in maps', 260: 'comefrom' => 'Number of resources that lead up to this resource in maps', 261: 'comefrom_list' => 'Resources that lead up to this resource in maps', 262: 'clear' => 'Material presented in clear way', 263: 'depth' => 'Material covered with sufficient depth', 264: 'helpful' => 'Material is helpful', 265: 'correct' => 'Material appears to be correct', 266: 'technical' => 'Resource is technically correct', 267: 'avetries' => 'Average number of tries till solved', 268: 'stdno' => 'Statistics calculated for number of students', 269: 'difficulty' => 'Degree of difficulty', 270: 'disc' => 'Degree of discrimination', 271: 'dependencies' => 'Resources used by this resource', 272: ); 273: } 274: return &Apache::lonlocal::texthash(%fields); 275: } 276: 277: sub portfolio_linked_path { 278: my ($path,$group,$port_path) = @_; 279: 280: my $start = 'portfolio'; 281: if ($group) { 282: $start = "groups/$group/".$start; 283: } 284: my %anchor_fields = ( 285: 'selectfile' => $start, 286: 'currentpath' => '/' 287: ); 288: my $result = &Apache::portfolio::make_anchor($port_path,\%anchor_fields,$start); 289: my $fullpath = '/'; 290: my (undef,@tree) = split('/',$path); 291: my $filename = pop(@tree); 292: foreach my $dir (@tree) { 293: $fullpath .= $dir.'/'; 294: $result .= '/'; 295: my %anchor_fields = ( 296: 'selectfile' => $dir, 297: 'currentpath' => $fullpath 298: ); 299: $result .= &Apache::portfolio::make_anchor($port_path,\%anchor_fields,$dir); 300: } 301: $result .= "/$filename"; 302: return $result; 303: } 304: 305: sub get_port_path_and_group { 306: my ($uri)=@_; 307: 308: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; 309: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; 310: 311: my ($port_path,$group); 312: if ($uri =~ m{^/editupload/\Q$cdom\E/\Q$cnum\E/groups/}) { 313: $group = (split('/',$uri))[5]; 314: $port_path = '/adm/coursegrp_portfolio'; 315: } else { 316: $port_path = '/adm/portfolio'; 317: } 318: if ($env{'form.group'} ne $group) { 319: $env{'form.group'} = $group; 320: } 321: return ($port_path,$group); 322: } 323: 324: sub portfolio_display_uri { 325: my ($uri,$as_links)=@_; 326: 327: my ($port_path,$group) = &get_port_path_and_group($uri); 328: 329: $uri =~ s|.*/(portfolio/.*)$|$1|; 330: my ($res_uri,$meta_uri) = ($uri,$uri); 331: if ($uri =~ /\.meta$/) { 332: $res_uri =~ s/\.meta//; 333: } else { 334: $meta_uri .= '.meta'; 335: } 336: 337: my ($path) = ($res_uri =~ m|^portfolio(.*/)[^/]*$|); 338: if ($as_links) { 339: $res_uri = &portfolio_linked_path($res_uri,$group,$port_path); 340: $meta_uri = &portfolio_linked_path($meta_uri,$group,$port_path); 341: } 342: return ($res_uri,$meta_uri,$path); 343: } 344: 345: sub pre_select_course { 346: my ($r,$uri) = @_; 347: my $output; 348: my $fn=&Apache::lonnet::filelocation('',$uri); 349: my ($res_uri,$meta_uri,$path) = &portfolio_display_uri($uri); 350: %Apache::lonpublisher::metadatafields=(); 351: %Apache::lonpublisher::metadatakeys=(); 352: my $result=&Apache::lonnet::getfile($fn); 353: if ($result == -1){ 354: $r->print(&mt('Creating new file [_1]'),$meta_uri); 355: } else { 356: &Apache::lonpublisher::metaeval($result); 357: } 358: $r->print('<hr /><form method="post" action="" >'); 359: $r->print('<p>'.&mt('If you would like to associate this resource ([_1]) with a current or previous course, please select one from the list below, otherwise select, \'None\'','<tt>'.$res_uri.'</tt>').'</p>'); 360: $output = &select_course(); 361: $r->print($output.'<br /><input type="submit" name="store" value="'. 362: &mt('Associate Resource With Selected Course').'" />'); 363: $r->print('<input type="hidden" name="currentpath" value="'.$env{'form.currentpath'}.'" />'); 364: $r->print('<input type="hidden" name="associate" value="true" />'); 365: $r->print('</form>'); 366: 367: my ($port_path,$group) = &get_port_path_and_group($uri); 368: my $group_input; 369: if ($group) { 370: $group_input = '<input type="hidden" name="group" value="'.$group.'" />'; 371: } 372: $r->print('<br /><br /><form method="post" action="'.$port_path.'">'. 373: '<input type="hidden" name="currentpath" value="'.$path.'" />'. 374: $group_input. 375: '<input type="submit" name="cancel" value="'.&mt('Cancel').'" />'. 376: '</form>'); 377: 378: return; 379: } 380: sub select_course { 381: my $output=$/; 382: my $current_restriction= 383: $Apache::lonpublisher::metadatafields{'courserestricted'}; 384: my $selected = ($current_restriction eq 'none' ? 'selected="selected"' 385: : ''); 386: if ($current_restriction =~ /^course\.($match_domain\_$match_courseid)$/) { 387: my $assoc_crs = $1; 388: my $added_metadata_fields = &Apache::lonparmset::get_added_meta_fieldnames($assoc_crs); 389: if (ref($added_metadata_fields) eq 'HASH') { 390: if (keys(%{$added_metadata_fields}) > 0) { 391: my $transfernotes; 392: foreach my $field_name (keys(%{$added_metadata_fields})) { 393: my $value = $Apache::lonpublisher::metadatafields{$field_name}; 394: if ($value) { 395: $transfernotes .= 396: &Apache::loncommon::start_data_table_row(). 397: '<td><input type="checkbox" name="transfer_'. 398: $field_name.'" value="1" /></td><td>'. 399: $field_name.'</td><td>'.$value.'</td>'. 400: &Apache::loncommon::end_data_table_row(); 401: } 402: } 403: if ($transfernotes ne '') { 404: my %courseinfo = &Apache::lonnet::coursedescription($assoc_crs,{'one_time' => 1}); 405: my $assoc_crs_description = $courseinfo{'description'}; 406: $output .= &mt('This resource is currently associated with a course ([_1]) which includes added metadata fields specific to the course.',$assoc_crs_description).'<br />'."\n". 407: &mt('You can choose to transfer data from the added fields to the "Notes" field if you are planning to change the course association.').'<br /><br />'. 408: &Apache::loncommon::start_data_table(). 409: &Apache::loncommon::start_data_table_header_row(). 410: '<th>Copy to notes?</th>'."\n". 411: '<th>Field name</th>'."\n". 412: '<th>Values</th>'."\n". 413: &Apache::loncommon::end_data_table_header_row(). 414: $transfernotes. 415: &Apache::loncommon::end_data_table().'<br />'; 416: } 417: } 418: } 419: } 420: $output .= '<select name="new_courserestricted" >'; 421: $output .= '<option value="none" '.$selected.'>'. 422: &mt('None').'</option>'.$/; 423: my %courses; 424: foreach my $key (keys(%env)) { 425: if ($key !~ m/^course\.(.+)\.description$/) { next; } 426: my $cid = $1; 427: if ($env{$key} !~ /\S/) { next; } 428: $courses{$key} = $cid; 429: } 430: foreach my $key (sort { lc($env{$a}) cmp lc($env{$b}) } (keys(%courses))) { 431: my $cid = 'course.'.$courses{$key}; 432: my $selected = ($current_restriction eq $cid ? 'selected="selected"' 433: : ''); 434: if ($env{$key} !~ /\S/) { next; } 435: $output .= '<option value="'.$cid.'" '.$selected.'>'; 436: $output .= $env{$key}; 437: $output .= '</option>'.$/; 438: $selected = ''; 439: } 440: $output .= '</select><br />'; 441: return ($output); 442: } 443: # Pretty printing of metadata field 444: 445: sub prettyprint { 446: my ($type,$value,$target,$prefix,$form,$noformat)=@_; 447: # $target,$prefix,$form are optional and for filecrumbs only 448: if (! defined($value)) { 449: return ' '; 450: } 451: # Title 452: if ($type eq 'title') { 453: return '<font size="+1" face="arial">'.$value.'</font>'; 454: } 455: # Dates 456: if (($type eq 'creationdate') || 457: ($type eq 'lastrevisiondate')) { 458: return ($value?&Apache::lonlocal::locallocaltime( 459: &Apache::lonmysql::unsqltime($value)): 460: &mt('not available')); 461: } 462: # Language 463: if ($type eq 'language') { 464: return &Apache::loncommon::languagedescription($value); 465: } 466: # Copyright 467: if ($type eq 'copyright') { 468: return &Apache::loncommon::copyrightdescription($value); 469: } 470: # Copyright 471: if ($type eq 'sourceavail') { 472: return &Apache::loncommon::source_copyrightdescription($value); 473: } 474: # MIME 475: if ($type eq 'mime') { 476: return '<img src="'.&Apache::loncommon::icon($value).'" /> '. 477: &Apache::loncommon::filedescription($value); 478: } 479: # Person 480: if (($type eq 'author') || 481: ($type eq 'owner') || 482: ($type eq 'modifyinguser') || 483: ($type eq 'authorspace')) { 484: $value=~s/($match_username)(\:|\@)($match_domain)/&authordisplay($1,$3)/gse; 485: return $value; 486: } 487: # Gradelevel 488: if (($type eq 'lowestgradelevel') || 489: ($type eq 'highestgradelevel')) { 490: return &Apache::loncommon::gradeleveldescription($value); 491: } 492: # Only for advance users below 493: if (! $env{'user.adv'}) { 494: return '<i>- '.&mt('not displayed').' -</i>'; 495: } 496: # File 497: if (($type eq 'customdistributionfile') || 498: ($type eq 'obsoletereplacement') || 499: ($type eq 'goto_list') || 500: ($type eq 'comefrom_list') || 501: ($type eq 'sequsage_list') || 502: ($type eq 'dependencies')) { 503: return '<font size="-1"><ul>'.join("\n",map { 504: my $url = &Apache::lonnet::clutter_with_no_wrapper($_); 505: my $title = &Apache::lonnet::gettitle($url); 506: if ($title eq '') { 507: $title = 'Untitled'; 508: if ($url =~ /\.sequence$/) { 509: $title .= ' Sequence'; 510: } elsif ($url =~ /\.page$/) { 511: $title .= ' Page'; 512: } elsif ($url =~ /\.problem$/) { 513: $title .= ' Problem'; 514: } elsif ($url =~ /\.html$/) { 515: $title .= ' HTML document'; 516: } elsif ($url =~ m:/syllabus$:) { 517: $title .= ' Syllabus'; 518: } 519: } 520: $_ = '<li>'.$title.' '. 521: &Apache::lonhtmlcommon::crumbs($url,$target,$prefix,$form,'-1',$noformat). 522: '</li>' 523: } split(/\s*\,\s*/,$value)).'</ul></font>'; 524: } 525: # Evaluations 526: if (($type eq 'clear') || 527: ($type eq 'depth') || 528: ($type eq 'helpful') || 529: ($type eq 'correct') || 530: ($type eq 'technical')) { 531: return &evalgraph($value); 532: } 533: # Difficulty 534: if ($type eq 'difficulty' || $type eq 'disc') { 535: return &diffgraph($value); 536: } 537: # List of courses 538: if ($type=~/\_list/) { 539: my @Courses = split(/\s*\,\s*/,$value); 540: my $Str='<font size="-1"><ul>'; 541: my %descriptions; 542: foreach my $course (@Courses) { 543: my %courseinfo = 544: &Apache::lonnet::coursedescription($course, 545: {'one_time' => 1}); 546: if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { 547: next; 548: } 549: $descriptions{join('\0',@courseinfo{'domain','description'})} .= 550: '<li><a href="/public/'.$courseinfo{'domain'}.'/'. 551: $courseinfo{'num'}.'/syllabus" target="preview">'. 552: $courseinfo{'description'}.' ('.$courseinfo{'domain'}. 553: ')</a></li>'; 554: } 555: foreach my $course (sort {lc($a) cmp lc($b)} (keys(%descriptions))) { 556: $Str .= $descriptions{$course}; 557: } 558: 559: return $Str.'</ul></font>'; 560: } 561: # No pretty print found 562: return $value; 563: } 564: 565: # Pretty input of metadata field 566: sub direct { 567: return shift; 568: } 569: 570: sub selectbox { 571: my ($name,$value,$functionref,@idlist)=@_; 572: if (! defined($functionref)) { 573: $functionref=\&direct; 574: } 575: my $selout='<select name="'.$name.'">'; 576: foreach my $id (@idlist) { 577: $selout.='<option value="'.$id.'"'; 578: if ($id eq $value) { 579: $selout.=' selected>'.&{$functionref}($_).'</option>'; 580: } else { 581: $selout.='>'.&{$functionref}($id).'</option>'; 582: } 583: } 584: return $selout.'</select>'; 585: } 586: 587: sub relatedfield { 588: my ($show,$relatedsearchflag,$relatedsep,$fieldname,$relatedvalue)=@_; 589: if (! $relatedsearchflag) { 590: return ''; 591: } 592: if (! defined($relatedsep)) { 593: $relatedsep=' '; 594: } 595: if (! $show) { 596: return $relatedsep.' '; 597: } 598: return $relatedsep.'<input type="checkbox" name="'.$fieldname.'_related"'. 599: ($relatedvalue?' checked="1"':'').' />'; 600: } 601: 602: sub prettyinput { 603: my ($type,$value,$fieldname,$formname, 604: $relatedsearchflag,$relatedsep,$relatedvalue,$size,$course_key)=@_; 605: if (! defined($size)) { 606: $size = 80; 607: } 608: my $output; 609: if (defined($course_key) 610: && exists($env{$course_key.'.metadata.'.$type.'.options'})) { 611: my $stu_add; 612: my $only_one; 613: my %meta_options; 614: my @cur_values_inst; 615: my $cur_values_stu; 616: my $values = $env{$course_key.'.metadata.'.$type.'.values'}; 617: if ($env{$course_key.'.metadata.'.$type.'.options'} =~ m/stuadd/) { 618: $stu_add = 'true'; 619: } 620: if ($env{$course_key.'.metadata.'.$type.'.options'} =~ m/onlyone/) { 621: $only_one = 'true'; 622: } 623: # need to take instructor values out of list where instructor and student 624: # values may be mixed. 625: if ($values) { 626: foreach my $item (split(/,/,$values)) { 627: $item =~ s/^\s+//; 628: $meta_options{$item} = $item; 629: } 630: foreach my $item (split(/,/,$value)) { 631: $item =~ s/^\s+//; 632: if ($meta_options{$item}) { 633: push(@cur_values_inst,$item); 634: } else { 635: if ($item ne '') { 636: $cur_values_stu .= $item.','; 637: } 638: } 639: } 640: $cur_values_stu =~ s/,$//; 641: my @key_order = sort(keys(%meta_options)); 642: unshift(@key_order,''); 643: $meta_options{''} = 'Not specified'; 644: $meta_options{'select_form_order'} = \@key_order; 645: } else { 646: $cur_values_stu = $value; 647: } 648: if ($type eq 'courserestricted') { 649: return (&select_course()); 650: # return ('<input type="hidden" name="new_courserestricted" value="'.$course_key.'" />'); 651: } 652: if (($type eq 'keywords') || ($type eq 'subject') 653: || ($type eq 'author')||($type eq 'notes') 654: || ($type eq 'abstract')|| ($type eq 'title')|| ($type eq 'standards') 655: || (exists($env{$course_key.'.metadata.'.$type.'.added'}))) { 656: 657: if ($values) { 658: if ($only_one) { 659: $output .= (&Apache::loncommon::select_form($cur_values_inst[0],'new_'.$type,%meta_options)); 660: } else { 661: $output .= (&Apache::loncommon::multiple_select_form('new_'.$type,\@cur_values_inst,undef,\%meta_options)); 662: } 663: } 664: if ($stu_add) { 665: $output .= '<input type="text" name="'.$fieldname.'" size="'.$size.'" '. 666: 'value="'.$cur_values_stu.'" />'. 667: &relatedfield(1,$relatedsearchflag,$relatedsep,$fieldname, 668: $relatedvalue); 669: } 670: return ($output); 671: } 672: if (($type eq 'lowestgradelevel') || 673: ($type eq 'highestgradelevel')) { 674: return &Apache::loncommon::select_level_form($value,$fieldname). 675: &relatedfield(0,$relatedsearchflag,$relatedsep); 676: } 677: return(); 678: } 679: # Language 680: if ($type eq 'language') { 681: return &selectbox($fieldname, 682: $value, 683: \&Apache::loncommon::languagedescription, 684: (&Apache::loncommon::languageids)). 685: &relatedfield(0,$relatedsearchflag,$relatedsep); 686: } 687: # Copyright 688: if ($type eq 'copyright') { 689: return &selectbox($fieldname, 690: $value, 691: \&Apache::loncommon::copyrightdescription, 692: (&Apache::loncommon::copyrightids)). 693: &relatedfield(0,$relatedsearchflag,$relatedsep); 694: } 695: # Source Copyright 696: if ($type eq 'sourceavail') { 697: return &selectbox($fieldname, 698: $value, 699: \&Apache::loncommon::source_copyrightdescription, 700: (&Apache::loncommon::source_copyrightids)). 701: &relatedfield(0,$relatedsearchflag,$relatedsep); 702: } 703: # Gradelevels 704: if (($type eq 'lowestgradelevel') || 705: ($type eq 'highestgradelevel')) { 706: return &Apache::loncommon::select_level_form($value,$fieldname). 707: &relatedfield(0,$relatedsearchflag,$relatedsep); 708: } 709: # Obsolete 710: if ($type eq 'obsolete') { 711: return '<input type="checkbox" name="'.$fieldname.'"'. 712: ($value?' checked="1"':'').' />'. 713: &relatedfield(0,$relatedsearchflag,$relatedsep); 714: } 715: # Obsolete replacement file 716: if ($type eq 'obsoletereplacement') { 717: return '<input type="text" name="'.$fieldname. 718: '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. 719: "('".$formname."','".$fieldname."'". 720: ",'')\">".&mt('Select').'</a>'. 721: &relatedfield(0,$relatedsearchflag,$relatedsep); 722: } 723: # Customdistribution file 724: if ($type eq 'customdistributionfile') { 725: return '<input type="text" name="'.$fieldname. 726: '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. 727: "('".$formname."','".$fieldname."'". 728: ",'rights')\">".&mt('Select').'</a>'. 729: &relatedfield(0,$relatedsearchflag,$relatedsep); 730: } 731: # Source Customdistribution file 732: if ($type eq 'sourcerights') { 733: return '<input type="text" name="'.$fieldname. 734: '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. 735: "('".$formname."','".$fieldname."'". 736: ",'rights')\">".&mt('Select').'</a>'. 737: &relatedfield(0,$relatedsearchflag,$relatedsep); 738: } 739: if ($type eq 'courserestricted') { 740: return (&select_course()); 741: #return ('<input type="hidden" name="new_courserestricted" value="'.$course_key.'" />'); 742: } 743: 744: # Dates 745: if (($type eq 'creationdate') || 746: ($type eq 'lastrevisiondate')) { 747: return 748: &Apache::lonhtmlcommon::date_setter($formname,$fieldname,$value). 749: &relatedfield(0,$relatedsearchflag,$relatedsep); 750: } 751: # No pretty input found 752: $value=~s/^\s+//gs; 753: $value=~s/\s+$//gs; 754: $value=~s/\s+/ /gs; 755: $value=~s/\"/\"\;/gs; 756: return 757: '<input type="text" name="'.$fieldname.'" size="'.$size.'" '. 758: 'value="'.$value.'" />'. 759: &relatedfield(1,$relatedsearchflag,$relatedsep,$fieldname, 760: $relatedvalue); 761: } 762: 763: # Main Handler 764: sub handler { 765: my $r=shift; 766: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, 767: ['currentpath','changecourse']); 768: my $uri=$r->uri; 769: # 770: # Set document type 771: &Apache::loncommon::content_type($r,'text/html'); 772: $r->send_http_header; 773: return OK if $r->header_only; 774: my ($resdomain,$resuser)= 775: (&Apache::lonnet::declutter($uri)=~/^($match_domain)\/($match_username)\//); 776: if ($uri=~m:/adm/bombs/(.*)$:) { 777: $r->print(&Apache::loncommon::start_page('Error Messages')); 778: # Looking for all bombs? 779: &report_bombs($r,$uri); 780: } elsif ($uri=~m|^/editupload/[^/]+/[^/]+/portfolio/|) { 781: ($resdomain,$resuser)= 782: (&Apache::lonnet::declutter($uri)=~m|^($match_domain)/($match_name)/portfolio|); 783: $r->print(&Apache::loncommon::start_page('Edit Portfolio File Catalog Information', 784: undef, 785: {'domain' => $resdomain,})); 786: if ($env{'form.store'}) { 787: &present_editable_metadata($r,$uri,'portfolio'); 788: } else { 789: my $fn=&Apache::lonnet::filelocation('',$uri); 790: %Apache::lonpublisher::metadatafields=(); 791: %Apache::lonpublisher::metadatakeys=(); 792: my $result=&Apache::lonnet::getfile($fn); 793: &Apache::lonpublisher::metaeval($result); 794: if ((!$Apache::lonpublisher::metadatafields{'courserestricted'}) || 795: ($env{'form.changecourse'} eq 'true')) { 796: &pre_select_course($r,$uri); 797: } else { 798: &present_editable_metadata($r,$uri,'portfolio'); 799: } 800: } 801: } elsif ($uri=~m|^/editupload/[^/]+/[^/]+/groups/|) { 802: $r->print(&Apache::loncommon::start_page('Edit Group Portfolio File Catalog Information', 803: undef, 804: {'domain' => $resdomain,})); 805: &present_editable_metadata($r,$uri,'groups'); 806: } elsif ($uri=~m|^/~|) { 807: # Construction space 808: $r->print(&Apache::loncommon::start_page('Edit Catalog Information', 809: "\n".'<script type="text/javascript">'."\n". 810: &Apache::loncommon::browser_and_searcher_javascript(). 811: "\n".'</script>', 812: {'domain' => $resdomain,})); 813: &present_editable_metadata($r,$uri); 814: } else { 815: $r->print(&Apache::loncommon::start_page('Catalog Information', 816: undef, 817: {'domain' => $resdomain,})); 818: &present_uneditable_metadata($r,$uri); 819: } 820: $r->print(&Apache::loncommon::end_page()); 821: return OK; 822: } 823: 824: ##################################################### 825: ##################################################### 826: ### ### 827: ### Report Bombs ### 828: ### ### 829: ##################################################### 830: ##################################################### 831: sub report_bombs { 832: my ($r,$uri) = @_; 833: # Set document type 834: $uri =~ s:/adm/bombs/::; 835: $uri = &Apache::lonnet::declutter($uri); 836: $r->print('<h1>'.&Apache::lonnet::clutter($uri).'</h1>'); 837: my ($domain,$author)=($uri=~/^($match_domain)\/($match_username)\//); 838: if (&Apache::loncacc::constructaccess('/~'.$author.'/',$domain)) { 839: if ($env{'form.clearbombs'}) { 840: &Apache::lonmsg::clear_author_res_msg($uri); 841: } 842: my $clear=&mt('Clear all Messages in Subdirectory'); 843: my $cancel=&mt('Back to Directory'); 844: my $cancelurl=$uri; 845: $cancelurl=~s/^\Q$domain\E/\/priv/; 846: $r->print(<<ENDCLEAR); 847: <form method="post"> 848: <input type="submit" name="clearbombs" value="$clear" /> 849: <a href="$cancelurl">$cancel</a> 850: </form><hr /> 851: ENDCLEAR 852: my %brokenurls = 853: &Apache::lonmsg::all_url_author_res_msg($author,$domain); 854: foreach my $key (sort(keys(%brokenurls))) { 855: if ($key=~/^\Q$uri\E/) { 856: $r->print 857: ('<a href="'.&Apache::lonnet::clutter($key).'">'.$key.'</a>'. 858: &Apache::lonmsg::retrieve_author_res_msg($key). 859: '<hr />'); 860: } 861: } 862: } else { 863: $r->print(&mt('Not authorized')); 864: } 865: return; 866: } 867: 868: ##################################################### 869: ##################################################### 870: ### ### 871: ### Uneditable Metadata Display ### 872: ### ### 873: ##################################################### 874: ##################################################### 875: sub present_uneditable_metadata { 876: my ($r,$uri) = @_; 877: # 878: my $uploaded = ($uri =~ m|/uploaded/|); 879: my %content=(); 880: # Read file 881: foreach my $key (split(/\,/,&Apache::lonnet::metadata($uri,'keys'))) { 882: $content{$key}=&Apache::lonnet::metadata($uri,$key); 883: } 884: # Render Output 885: # displayed url 886: my ($thisversion)=($uri=~/\.(\d+)\.(\w+)\.meta$/); 887: $uri=~s/\.meta$//; 888: my $disuri=&Apache::lonnet::clutter_with_no_wrapper($uri); 889: # version 890: my $versiondisplay=''; 891: if (!$uploaded) { 892: my $currentversion=&Apache::lonnet::getversion($disuri); 893: if ($thisversion) { 894: $versiondisplay=&mt('Version').': '.$thisversion. 895: ' ('.&mt('most recent version').': '. 896: ($currentversion>0 ? 897: $currentversion : 898: &mt('information not available')).')'; 899: } else { 900: $versiondisplay='Version: '.$currentversion; 901: } 902: } 903: # crumbify displayed URL uri target prefix form size 904: $disuri=&Apache::lonhtmlcommon::crumbs($disuri,undef, undef, undef,'+1'); 905: $disuri =~ s:<br />::g; 906: # obsolete 907: my $obsolete=$content{'obsolete'}; 908: my $obsoletewarning=''; 909: if (($obsolete) && ($env{'user.adv'})) { 910: $obsoletewarning='<p><span class="LC_warning">'. 911: &mt('This resource has been marked obsolete by the author(s)'). 912: '</span></p>'; 913: } 914: # 915: my %lt=&fieldnames(); 916: my $table=''; 917: my $title = $content{'title'}; 918: if (! defined($title)) { 919: $title = 'Untitled Resource'; 920: } 921: my @fields; 922: if ($uploaded) { 923: @fields = ('title','author','subject','keywords','notes','abstract', 924: 'lowestgradelevel','highestgradelevel','standards','mime', 925: 'owner'); 926: } else { 927: @fields = ('title', 928: 'author', 929: 'subject', 930: 'keywords', 931: 'notes', 932: 'abstract', 933: 'lowestgradelevel', 934: 'highestgradelevel', 935: 'standards', 936: 'mime', 937: 'language', 938: 'creationdate', 939: 'lastrevisiondate', 940: 'owner', 941: 'copyright', 942: 'customdistributionfile', 943: 'sourceavail', 944: 'sourcerights', 945: 'obsolete', 946: 'obsoletereplacement'); 947: } 948: my $rownum = 0; 949: foreach my $field (@fields) { 950: my $lastrow = ''; 951: $rownum ++; 952: $lastrow = 1 if ($rownum == @fields); 953: $table.=&Apache::lonhtmlcommon::row_title($lt{$field}) 954: .&prettyprint($field,$content{$field}) 955: .&Apache::lonhtmlcommon::row_closure($lastrow); 956: delete($content{$field}); 957: } 958: # 959: $r->print("<h2>$title</h2>" 960: .'<p>' 961: .$disuri.'<br />' 962: .$obsoletewarning 963: .$versiondisplay 964: .'</p>' 965: .&Apache::lonhtmlcommon::start_pick_box() 966: .$table 967: .&Apache::lonhtmlcommon::end_pick_box() 968: ); 969: if (!$uploaded && $env{'user.adv'}) { 970: &print_dynamic_metadata($r,$uri,\%content); 971: } 972: return; 973: } 974: 975: sub print_dynamic_metadata { 976: my ($r,$uri,$content) = @_; 977: # 978: my %content = %$content; 979: my %lt=&fieldnames(); 980: # 981: my $description = 'Dynamic Metadata (updated periodically)'; 982: $r->print('<h3>'.&mt($description).'</h3>'. 983: &mt('Processing')); 984: $r->rflush(); 985: my %items=&fieldnames(); 986: my %dynmeta=&dynamicmeta($uri); 987: # 988: # General Access and Usage Statistics 989: if (exists($dynmeta{'count'}) || 990: exists($dynmeta{'sequsage'}) || 991: exists($dynmeta{'comefrom'}) || 992: exists($dynmeta{'goto'}) || 993: exists($dynmeta{'course'})) { 994: $r->print('<h4>'.&mt('Access and Usage Statistics').'</h4>'. 995: &Apache::lonhtmlcommon::start_pick_box()); 996: my @counts = ('count','sequsage','sequsage_list', 997: 'comefrom','comefrom_list','goto', 998: 'goto_list','course','course_list'); 999: my $rownum = 0; 1000: foreach my $item (@counts) { 1001: my $lastrow = ''; 1002: $rownum ++; 1003: $lastrow = 1 if ($rownum == @counts); 1004: $r->print(&Apache::lonhtmlcommon::row_title($lt{$item}) 1005: .&prettyprint($item,$dynmeta{$item}) 1006: .&Apache::lonhtmlcommon::row_closure($lastrow) 1007: ); 1008: } 1009: $r->print(&Apache::lonhtmlcommon::end_pick_box()); 1010: } else { 1011: $r->print('<h4>'.&mt('No Access or Usages Statistics are available for this resource.').'</h4>'); 1012: } 1013: # 1014: # Assessment statistics 1015: if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/) { 1016: if (exists($dynmeta{'stdno'}) || 1017: exists($dynmeta{'avetries'}) || 1018: exists($dynmeta{'difficulty'}) || 1019: exists($dynmeta{'disc'})) { 1020: # This is an assessment, print assessment data 1021: $r->print('<h4>'. 1022: &mt('Overall Assessment Statistical Data'). 1023: '</h4>'. 1024: &Apache::lonhtmlcommon::start_pick_box()); 1025: $r->print(&Apache::lonhtmlcommon::row_title($lt{'stdno'}) 1026: .&prettyprint('stdno',$dynmeta{'stdno'}) 1027: .&Apache::lonhtmlcommon::row_closure() 1028: ); 1029: my @stats = ('avetries','difficulty','disc'); 1030: my $rownum = 0; 1031: foreach my $item (@stats) { 1032: my $lastrow = ''; 1033: $rownum ++; 1034: $lastrow = 1 if ($rownum == @stats); 1035: $r->print(&Apache::lonhtmlcommon::row_title($lt{$item}) 1036: .&prettyprint($item,sprintf('%5.2f',$dynmeta{$item})) 1037: .&Apache::lonhtmlcommon::row_closure($lastrow) 1038: ); 1039: } 1040: $r->print(&Apache::lonhtmlcommon::end_pick_box()); 1041: } 1042: if (exists($dynmeta{'stats'})) { 1043: # 1044: # New assessment statistics 1045: $r->print('<h4>'. 1046: &mt('Recent Detailed Assessment Statistical Data'). 1047: '</h4>'); 1048: my $table=&Apache::loncommon::start_data_table() 1049: .&Apache::loncommon::start_data_table_header_row() 1050: .'<th>'.&mt('Course').'</th>' 1051: .'<th>'.&mt('Section(s)').'</th>' 1052: .'<th>'.&mt('Num Student').'s</th>' 1053: .'<th>'.&mt('Mean Tries').'</th>' 1054: .'<th>'.&mt('Degree of Difficulty').'</th>' 1055: .'<th>'.&mt('Degree of Discrimination').'</th>' 1056: .'<th>'.&mt('Time of computation').'</th>' 1057: .&Apache::loncommon::end_data_table_header_row().$/; 1058: foreach my $identifier (sort(keys(%{$dynmeta{'stats'}}))) { 1059: my $data = $dynmeta{'stats'}->{$identifier}; 1060: my $course = $data->{'course'}; 1061: my %courseinfo = 1062: &Apache::lonnet::coursedescription($course, 1063: {'one_time' => 1}); 1064: if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { 1065: &Apache::lonnet::logthis('lookup for '.$course.' failed'); 1066: next; 1067: } 1068: $table .= &Apache::loncommon::start_data_table_row(); 1069: $table .= 1070: '<td><span class="LC_nobreak">'.$courseinfo{'description'}.'</span></td>'; 1071: $table .= 1072: '<td align="right">'.$data->{'sections'}.'</td>'; 1073: $table .= 1074: '<td align="right">'.$data->{'stdno'}.'</td>'; 1075: foreach my $item ('avetries','difficulty','disc') { 1076: $table .= '<td align="right">'; 1077: if (exists($data->{$item})) { 1078: $table .= sprintf('%.2f',$data->{$item}).' '; 1079: } else { 1080: $table .= ''; 1081: } 1082: $table .= '</td>'; 1083: } 1084: $table .= 1085: '<td><span class="LC_nobreak">'. 1086: &Apache::lonlocal::locallocaltime($data->{'timestamp'}). 1087: '</span></td>'; 1088: $table .= &Apache::loncommon::end_data_table_row().$/; 1089: } 1090: $table .= &Apache::loncommon::end_data_table().$/; 1091: $r->print($table); 1092: } else { 1093: $r->print(&mt('No new dynamic data found.')); 1094: } 1095: } else { 1096: $r->print('<h4>'. 1097: &mt('No Assessment Statistical Data is available for this resource'). 1098: '</h4>'); 1099: } 1100: 1101: # 1102: # 1103: if (exists($dynmeta{'clear'}) || 1104: exists($dynmeta{'depth'}) || 1105: exists($dynmeta{'helpful'}) || 1106: exists($dynmeta{'correct'}) || 1107: exists($dynmeta{'technical'})){ 1108: $r->print('<h4>'.&mt('Evaluation Data').'</h4>'. 1109: &Apache::lonhtmlcommon::start_pick_box()); 1110: my @criteria = ('clear','depth','helpful','correct','technical'); 1111: my $rownum = 0; 1112: foreach my $item (@criteria) { 1113: my $lastrow = ''; 1114: $rownum ++; 1115: $lastrow = 1 if ($rownum == @criteria); 1116: $r->print(&Apache::lonhtmlcommon::row_title($lt{$item}) 1117: .&prettyprint($item,$dynmeta{$item}) 1118: .&Apache::lonhtmlcommon::row_closure($lastrow) 1119: ); 1120: } 1121: $r->print(&Apache::lonhtmlcommon::end_pick_box()); 1122: } else { 1123: $r->print('<h4>'.&mt('No Evaluation Data is available for this resource.').'</h4>'); 1124: } 1125: $uri=~/^\/res\/($match_domain)\/($match_username)\//; 1126: if ((($env{'user.domain'} eq $1) && ($env{'user.name'} eq $2)) 1127: || ($env{'user.role.ca./'.$1.'/'.$2})) { 1128: if (exists($dynmeta{'comments'})) { 1129: $r->print('<h4>'.&mt('Evaluation Comments').' ('. 1130: &mt('visible to author and co-authors only'). 1131: ')</h4>'. 1132: '<blockquote>'.$dynmeta{'comments'}.'</blockquote>'); 1133: } else { 1134: $r->print('<h4>'.&mt('There are no Evaluation Comments on this resource.').'</h4>'); 1135: } 1136: my $bombs = &Apache::lonmsg::retrieve_author_res_msg($uri); 1137: if (defined($bombs) && $bombs ne '') { 1138: $r->print('<a name="bombs" /><h4>'.&mt('Error Messages').' ('. 1139: &mt('visible to author and co-authors only').')'. 1140: '</h4>'.$bombs); 1141: } else { 1142: $r->print('<h4>'.&mt('There are currently no Error Messages for this resource.').'</h4>'); 1143: } 1144: } 1145: # 1146: # All other stuff 1147: $r->print('<h3>'. 1148: &mt('Additional Metadata (non-standard, parameters, exports)'). 1149: '</h3>'); 1150: $r->print(&Apache::lonhtmlcommon::start_pick_box()); 1151: my @names; 1152: foreach my $key (sort(keys(%content))) { 1153: if ($key!~/\.display$/) { 1154: push(@names,$key); 1155: } 1156: } 1157: if (@names > 0) { 1158: my $rownum = 0; 1159: foreach my $name (@names) { 1160: my $lastrow = ''; 1161: $rownum ++; 1162: $lastrow = 1 if ($rownum == @names); 1163: 1164: my $display=&Apache::lonnet::metadata($uri, 1165: $name.'.display'); 1166: if (! $display) { 1167: $display=$name; 1168: }; 1169: my $otherinfo=''; 1170: foreach my $item ('name','part','type','default') { 1171: if (defined(&Apache::lonnet::metadata($uri, 1172: $name.'.'.$item))) { 1173: $otherinfo.=' '.$item.'='. 1174: &Apache::lonnet::metadata($uri, 1175: $name.'.'.$item).'; '; 1176: } 1177: } 1178: $r->print(&Apache::lonhtmlcommon::row_title($display) 1179: .$content{$name}); 1180: if ($otherinfo) { 1181: $r->print(' ('.$otherinfo.')'); 1182: } 1183: $r->print(&Apache::lonhtmlcommon::row_closure($lastrow)); 1184: } 1185: } 1186: $r->print(&Apache::lonhtmlcommon::end_pick_box()); 1187: return; 1188: } 1189: 1190: 1191: 1192: ##################################################### 1193: ##################################################### 1194: ### ### 1195: ### Editable metadata display ### 1196: ### ### 1197: ##################################################### 1198: ##################################################### 1199: sub present_editable_metadata { 1200: my ($r,$uri,$file_type) = @_; 1201: # Construction Space Call 1202: # Header 1203: my $disuri=$uri; 1204: my $fn=&Apache::lonnet::filelocation('',$uri); 1205: $disuri=~s{^/\~}{/priv/}; 1206: $disuri=~s/\.meta$//; 1207: my $meta_uri = $disuri; 1208: my $path; 1209: if ($disuri =~ m|/portfolio/|) { 1210: ($disuri, $meta_uri, $path) = &portfolio_display_uri($disuri,1); 1211: } 1212: my $target=$uri; 1213: $target=~s{^/\~}{/res/$env{'request.role.domain'}/}; 1214: $target=~s/\.meta$//; 1215: my $bombs=&Apache::lonmsg::retrieve_author_res_msg($target); 1216: if ($bombs) { 1217: my $showdel=1; 1218: if ($env{'form.delmsg'}) { 1219: if (&Apache::lonmsg::del_url_author_res_msg($target) eq 'ok') { 1220: $bombs=&mt('Messages deleted.'); 1221: $showdel=0; 1222: } else { 1223: $bombs=&mt('Error deleting messages'); 1224: } 1225: } 1226: if ($env{'form.clearmsg'}) { 1227: my $cleardir=$target; 1228: $cleardir=~s/\/[^\/]+$/\//; 1229: if (&Apache::lonmsg::clear_author_res_msg($cleardir) eq 'ok') { 1230: $bombs=&mt('Messages cleared.'); 1231: $showdel=0; 1232: } else { 1233: $bombs=&mt('Error clearing messages'); 1234: } 1235: } 1236: my $del=&mt('Delete Messages for this Resource'); 1237: my $clear=&mt('Clear all Messages in Subdirectory'); 1238: my $goback=&mt('Back to Source File'); 1239: $r->print(<<ENDBOMBS); 1240: <h1>$disuri</h1> 1241: <form method="post" action="" name="defaultmeta"> 1242: ENDBOMBS 1243: if ($showdel) { 1244: $r->print(<<ENDDEL); 1245: <input type="submit" name="delmsg" value="$del" /> 1246: <input type="submit" name="clearmsg" value="$clear" /> 1247: ENDDEL 1248: } else { 1249: $r->print('<p><a href="'.$disuri.'">'.$goback.'</a></p>'); 1250: if ($env{'form.clearmsg'}) { 1251: my ($diruri) = ($disuri =~ m{(.*/)[^/]*}); 1252: $r->print('<p><a href="'.$diruri.'">'. 1253: &mt('Back To Directory').'</a></p>'); 1254: } 1255: } 1256: $r->print('<br />'.$bombs); 1257: } else { 1258: my $displayfile=&mt('Catalog Information for [_1]',$disuri); 1259: if ($disuri=~/\/default$/) { 1260: my $dir=$disuri; 1261: $dir=~s/default$//; 1262: $displayfile=&mt('Default Cataloging Information for Directory [_1]',$dir); 1263: } 1264: %Apache::lonpublisher::metadatafields=(); 1265: %Apache::lonpublisher::metadatakeys=(); 1266: my $result=&Apache::lonnet::getfile($fn); 1267: if ($result == -1){ 1268: $r->print(&mt('Creating new file [_1]'),$meta_uri); 1269: } else { 1270: &Apache::lonpublisher::metaeval($result); 1271: } 1272: if ($env{'form.new_courserestricted'}) { 1273: my $new_assoc_course = $env{'form.new_courserestricted'}; 1274: my $prev_courserestricted = $Apache::lonpublisher::metadatafields{'courserestricted'}; 1275: if (($prev_courserestricted) && 1276: ($prev_courserestricted ne $new_assoc_course)) { 1277: my $transfers = []; 1278: foreach my $key (keys(%env)) { 1279: if ($key =~ /^form\.transfer_(.+)$/) { 1280: push(@{$transfers},$1); 1281: } 1282: } 1283: if (@{$transfers} > 0) { 1284: &store_transferred_addedfields($fn,$uri,$transfers); 1285: } 1286: } 1287: } 1288: $r->print(<<ENDEDIT); 1289: <h1>$displayfile</h1> 1290: <form method="post" action="" name="defaultmeta"> 1291: ENDEDIT 1292: my %lt=&fieldnames($file_type); 1293: my $output; 1294: my @fields; 1295: my $added_metadata_fields; 1296: my @added_order; 1297: if ($file_type eq 'groups') { 1298: $Apache::lonpublisher::metadatafields{'courserestricted'}= 1299: 'course.'.$env{'request.course.id'}; 1300: } 1301: if ((! $Apache::lonpublisher::metadatafields{'courserestricted'}) && 1302: (! $env{'form.new_courserestricted'}) && (! $file_type eq 'groups')) { 1303: $Apache::lonpublisher::metadatafields{'courserestricted'}= 1304: 'none'; 1305: } elsif ($env{'form.new_courserestricted'}) { 1306: $Apache::lonpublisher::metadatafields{'courserestricted'}= 1307: $env{'form.new_courserestricted'}; 1308: } 1309: if ($file_type eq 'portfolio' || $file_type eq 'groups') { 1310: if(exists ($env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.fieldlist'})) { 1311: # retrieve fieldnames (in order) from the course restricted list 1312: @fields = (split(/,/,$env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.fieldlist'})); 1313: } else { 1314: # no saved field list, use default list 1315: @fields = ('author','title','subject','keywords','abstract', 1316: 'notes','lowestgradelevel', 1317: 'highestgradelevel','standards'); 1318: if ($Apache::lonpublisher::metadatafields{'courserestricted'} =~ /^course\.($match_domain\_$match_courseid)$/) { 1319: my $assoc_crs = $1; 1320: $added_metadata_fields = &Apache::lonparmset::get_added_meta_fieldnames($assoc_crs); 1321: if ($env{'course.'.$assoc_crs.'.metadata.addedorder'}) { 1322: @added_order = split(/,/,$env{'course.'.$assoc_crs.'.metadata.addedorder'}); 1323: } 1324: $env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.fieldlist'} = join(",",@fields); 1325: } 1326: } 1327: } else { 1328: @fields = ('author','title','subject','keywords','abstract','notes', 1329: 'copyright','customdistributionfile','language', 1330: 'standards', 1331: 'lowestgradelevel','highestgradelevel','sourceavail','sourcerights', 1332: 'obsolete','obsoletereplacement'); 1333: } 1334: if (! $Apache::lonpublisher::metadatafields{'copyright'}) { 1335: $Apache::lonpublisher::metadatafields{'copyright'}= 1336: 'default'; 1337: } 1338: if (($file_type eq 'portfolio') || ($file_type eq 'groups')) { 1339: if (! $Apache::lonpublisher::metadatafields{'mime'}) { 1340: ($Apache::lonpublisher::metadatafields{'mime'}) = 1341: ( $target=~/\.(\w+)$/ ); 1342: } 1343: if (! $Apache::lonpublisher::metadatafields{'owner'}) { 1344: $Apache::lonpublisher::metadatafields{'owner'} = 1345: $env{'user.name'}.':'.$env{'user.domain'}; 1346: } 1347: if (! $Apache::lonpublisher::metadatafields{'author'}) { 1348: $Apache::lonpublisher::metadatafields{'author'} = 1349: &Apache::loncommon::plainname($env{'user.name'}, 1350: $env{'user.domain'}); 1351: } 1352: if ($Apache::lonpublisher::metadatafields{'courserestricted'} ne 'none') { 1353: 1354: if ($file_type eq 'portfolio') { 1355: $r->print(&mt('Associated with course [_1]', 1356: '<strong><a href="'.$uri.'?changecourse=true">'. 1357: $env{$Apache::lonpublisher::metadatafields{'courserestricted'}. 1358: ".description"}. 1359: '</a></strong>').'<br />'); 1360: } else { 1361: $r->print(&mt('Associated with course [_1]', 1362: '<strong>'. 1363: $env{$Apache::lonpublisher::metadatafields{'courserestricted'}. 1364: ".description"}.'</strong>').'<br />'); 1365: } 1366: } else { 1367: $r->print('<a href="'.$uri.'?changecourse=true">'.&mt('This resource is not associated with a course.').'</a><br />'); 1368: } 1369: } 1370: if (@added_order) { 1371: foreach my $field_name (@added_order) { 1372: push(@fields,$field_name); 1373: $lt{$field_name} = $$added_metadata_fields{$field_name}; 1374: } 1375: } else { 1376: foreach my $field_name (keys(%$added_metadata_fields)) { 1377: push(@fields,$field_name); 1378: $lt{$field_name} = $$added_metadata_fields{$field_name}; 1379: } 1380: } 1381: $output .= &Apache::loncommon::start_data_table(); 1382: my $row_alt = 1; 1383: foreach my $field_name (@fields) { 1384: if (defined($env{'form.new_'.$field_name})) { 1385: my @values = &Apache::loncommon::get_env_multiple('form.new_'.$field_name); 1386: my $newvalue = ''; 1387: foreach my $item (@values) { 1388: if ($item ne '') { 1389: $newvalue .= $item.','; 1390: } 1391: } 1392: $newvalue =~ s/,$//; 1393: $Apache::lonpublisher::metadatafields{$field_name}=$newvalue; 1394: } 1395: if ($Apache::lonpublisher::metadatafields{'courserestricted'} ne 'none' 1396: && exists($env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.'.$field_name.'.options'})) { 1397: # handle restrictions here 1398: if ((($env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.'.$field_name.'.options'} =~ m/active/) || 1399: ($field_name eq 'courserestricted'))&& 1400: (!($env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.'.$field_name.'.options'} =~ m/deleted/))){ 1401: 1402: $output .= "\n".&Apache::loncommon::start_data_table_row(); 1403: $output .= ('<td><span class="LC_metadata">'.$lt{$field_name}.':</span></td><td> '. 1404: &prettyinput($field_name, 1405: $Apache::lonpublisher::metadatafields{$field_name}, 1406: 'new_'.$field_name,'defaultmeta', 1407: undef,undef,undef,undef, 1408: $Apache::lonpublisher::metadatafields{'courserestricted'}).'</td>'); 1409: $output .= &Apache::loncommon::end_data_table_row(); 1410: } 1411: } else { 1412: 1413: $output.=(&Apache::loncommon::start_data_table_row().'<td><span class="LC_metadata">'.$lt{$field_name}.':</span></td><td> '. 1414: &prettyinput($field_name, 1415: $Apache::lonpublisher::metadatafields{$field_name}, 1416: 'new_'.$field_name,'defaultmeta').'</td>'.&Apache::loncommon::end_data_table_row()); 1417: 1418: } 1419: } 1420: $output .= &Apache::loncommon::end_data_table(); 1421: if ($env{'form.store'}) { 1422: my ($outcome,$result) = &store_metadata($fn,$uri,'store'); 1423: $r->print($result); 1424: } 1425: $r->print($output.'<br /><input type="submit" name="store" value="'. 1426: &mt('Save Catalog Information').'" />'); 1427: 1428: if ($file_type eq 'portfolio' || $file_type eq 'groups') { 1429: my ($port_path,$group) = &get_port_path_and_group($uri); 1430: if ($group ne '') { 1431: $r->print('<input type="hidden" name="group" value="'.$group.'" />'); 1432: } 1433: $r->print('<input type="hidden" name="currentpath" value="'.$env{'form.currentpath'}.'" />'); 1434: $r->print('</form><br /><br /><form method="post" action="'.$port_path.'">'); 1435: if ($group ne '') { 1436: $r->print('<input type="hidden" name="group" value="'.$group.'" />'); 1437: } 1438: $r->print('<input type="hidden" name="currentpath" value="'.$path.'" />'. 1439: '<input type="submit" name="cancel" value="'.&mt('Discard Edits and Return to Portfolio').'" />'); 1440: } 1441: } 1442: 1443: $r->print('</form>'); 1444: 1445: return; 1446: } 1447: 1448: sub store_metadata { 1449: my ($fn,$uri,$caller) = @_; 1450: my $mfh; 1451: my $formname='store'; 1452: my ($file_content,$output,$outcome); 1453: if (&Apache::loncommon::get_env_multiple('form.new_keywords')) { 1454: $Apache::lonpublisher::metadatafields{'keywords'} = 1455: join (',', &Apache::loncommon::get_env_multiple('form.new_keywords')); 1456: } 1457: foreach my $field (sort(keys(%Apache::lonpublisher::metadatafields))) { 1458: next if ($field =~ /\./); 1459: my $unikey=$field; 1460: $unikey=~/^([A-Za-z_]+)/; 1461: my $tag=$1; 1462: $tag=~tr/A-Z/a-z/; 1463: $file_content.= "\n\<$tag"; 1464: foreach my $key (split(/\,/,$Apache::lonpublisher::metadatakeys{$unikey})) { 1465: my $value = $Apache::lonpublisher::metadatafields{$unikey.'.'.$key}; 1466: $value=~s/\"/\'\'/g; 1467: $file_content.=' '.$key.'="'.$value.'"' ; 1468: } 1469: $file_content.= '>'. 1470: &HTML::Entities::encode 1471: ($Apache::lonpublisher::metadatafields{$unikey},'<>&"'). 1472: '</'.$tag.'>'; 1473: } 1474: if ($fn =~ m|^$Apache::lonnet::perlvar{'lonDocRoot'}/userfiles|) { 1475: my ($path, $new_fn); 1476: if ($fn =~ m|$match_name/groups/\w+/portfolio/|) { 1477: ($path, $new_fn) = ($fn =~ m|/(groups/\w+/portfolio.*)/([^/]*)$|); 1478: } else { 1479: ($path, $new_fn) = ($fn =~ m|/(portfolio.*)/([^/]*)$|); 1480: } 1481: ($outcome,my $result) = 1482: &store_portfolio_metadata($formname,$file_content, 1483: $path,$new_fn,$uri,$caller); 1484: $output .= $result; 1485: } else { 1486: if (! ($mfh=Apache::File->new('>'.$fn))) { 1487: $output .= '<p><font color="red">'; 1488: if ($caller eq 'transfer') { 1489: $output .= &mt('Could not transfer data in added fields to notes'); 1490: } else { 1491: $output .= &mt('Could not write metadata'); 1492: } 1493: $output .= ', '.&mt('FAIL').'</font></p>'; 1494: $outcome = 'fail'; 1495: } else { 1496: print $mfh ($file_content); 1497: close($mfh); 1498: &update_metadata_table($uri); 1499: $output .= '<p><font color="blue">'; 1500: if ($caller eq 'transfer') { 1501: $output .= &mt('Transferred data in added fields to notes'); 1502: } else { 1503: $output .= &mt('Wrote Metadata'); 1504: } 1505: $output .= ' '.&Apache::lonlocal::locallocaltime(time). 1506: '</font></p>'; 1507: $outcome = 'ok'; 1508: } 1509: } 1510: return ($outcome,$output); 1511: } 1512: 1513: sub store_transferred_addedfields { 1514: my ($fn,$uri,$transfers) = @_; 1515: foreach my $item (@{$transfers}) { 1516: $Apache::lonpublisher::metadatafields{'notes'} .= 1517: ' '.$item.' = '.$Apache::lonpublisher::metadatafields{$item}; 1518: } 1519: my ($outcome,$output) = &store_metadata($fn,$uri,'transfer'); 1520: if ($outcome eq 'ok') { 1521: foreach my $item (@{$transfers}) { 1522: delete($Apache::lonpublisher::metadatafields{$item}); 1523: } 1524: } 1525: } 1526: 1527: sub store_portfolio_metadata { 1528: my ($formname,$content,$path,$new_fn,$uri,$caller) = @_; 1529: my ($outcome,$output); 1530: $env{'form.'.$formname}=$content."\n"; 1531: $env{'form.'.$formname.'.filename'}=$new_fn; 1532: my $result =&Apache::lonnet::userfileupload($formname,'',$path); 1533: if ($result =~ /(error|notfound)/) { 1534: $output = '<p><font color="red">'; 1535: if ($caller eq 'transfer') { 1536: $output .= 1537: &mt('Could not transfer data in added fields to notes'); 1538: } else { 1539: $output .= &mt('Could not write metadata'); 1540: } 1541: $output .= ', '.&mt('FAIL').'</font></p>'; 1542: $outcome = 'fail'; 1543: } else { 1544: &update_metadata_table($uri); 1545: $output = '<p><font color="blue">'; 1546: if ($caller eq 'transfer') { 1547: $output .= &mt('Transferred data in added fields to notes'); 1548: } else { 1549: $output .= &mt('Wrote Metadata'); 1550: } 1551: $output .= ' '.&Apache::lonlocal::locallocaltime(time). 1552: '</font></p>'; 1553: $outcome = 'ok'; 1554: } 1555: return ($outcome,$output); 1556: } 1557: 1558: sub update_metadata_table { 1559: my ($uri) = @_; 1560: my ($type,$udom,$uname,$file_name,$group) = 1561: &Apache::lonnet::parse_portfolio_url($uri); 1562: $file_name =~ s/\.meta$//; 1563: my $current_permissions = 1564: &Apache::lonnet::get_portfile_permissions($udom,$uname); 1565: my %access_controls = 1566: &Apache::lonnet::get_access_controls($current_permissions,$group, 1567: $file_name); 1568: my $access_hash = $access_controls{$file_name}; 1569: my $available = 0; 1570: if (ref($access_hash) eq 'HASH') { 1571: foreach my $key (keys(%{$access_hash})) { 1572: my ($num,$scope,$end,$start) = 1573: ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/); 1574: if ($scope eq 'public' || $scope eq 'guest') { 1575: $available = 1; 1576: last; 1577: } 1578: } 1579: } 1580: if ($available) { 1581: my $result = 1582: &Apache::lonnet::update_portfolio_table($uname,$udom, 1583: $file_name,'portfolio_metadata',$group,'update'); 1584: } 1585: } 1586: 1587: 1588: 1; 1589: __END__ 1590: