--- loncom/interface/lonmeta.pm 2004/04/15 18:06:29 1.72 +++ loncom/interface/lonmeta.pm 2006/08/08 19:35:53 1.165 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Metadata display handler # -# $Id: lonmeta.pm,v 1.72 2004/04/15 18:06:29 matthew Exp $ +# $Id: lonmeta.pm,v 1.165 2006/08/08 19:35:53 banghart Exp $ # # Copyright Michigan State University Board of Trustees # @@ -17,7 +17,7 @@ # 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 # @@ -31,14 +31,80 @@ 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::lonhtmlcommon(); use Apache::lonmsg; use Apache::lonpublisher; use Apache::lonlocal; use Apache::lonmysql; use Apache::lonmsg; +use lib '/home/httpd/lib/perl/'; +use LONCAPA; + + +############################################################ +############################################################ +## +## &get_dynamic_metadata_from_sql($url) +## +## Queries sql database for dynamic metdata +## Returns a hash of hashes, with keys of urls which match $url +## Returned fields are given below. +## +## Examples: +## +## %DynamicMetadata = &Apache::lonmeta::get_dynmaic_metadata_from_sql +## ('/res/msu/korte/'); +## +## $DynamicMetadata{'/res/msu/korte/example.problem'}->{$field} +## +############################################################ +############################################################ +sub get_dynamic_metadata_from_sql { + my ($url) = shift(); + my ($authordom,$author)=($url=~m:^/res/(\w+)/(\w+)/:); + if (! defined($authordom)) { + $authordom = shift(); + } + if (! defined($author)) { + $author = shift(); + } + if (! defined($authordom) || ! defined($author)) { + return (); + } + my $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(map { &unescape($_) } split(/\,/,$result)); + foreach my $key (keys(%hash)) { + $ReturnHash{$hash{'url'}}->{$key}=$hash{$key}; + } + } + $finished = 1; + } + # + return %ReturnHash; +} # Fetch and evaluate dynamic metadata @@ -104,7 +170,7 @@ sub authordisplay { my ($aname,$adom)=@_; return &Apache::loncommon::aboutmewrapper (&Apache::loncommon::plainname($aname,$adom), - $aname,$adom,'preview').' <tt>['.$aname.'@'.$adom.']</tt>'; + $aname,$adom,'preview').' <tt>['.$aname.':'.$adom.']</tt>'; } # Pretty display @@ -155,19 +221,30 @@ sub diffgraph { # The field names sub fieldnames { - return &Apache::lonlocal::texthash - ( - 'title' => 'Title', + my $file_type=shift; + my %fields = + ('title' => 'Title', 'author' =>'Author(s)', 'authorspace' => 'Author Space', 'modifyinguser' => 'Last Modifying User', 'subject' => 'Subject', + 'standards' => 'Standards', 'keywords' => 'Keyword(s)', 'notes' => 'Notes', 'abstract' => 'Abstract', 'lowestgradelevel' => 'Lowest Grade Level', - 'highestgradelevel' => 'Highest Grade Level', - 'standards' => 'Standards', + 'highestgradelevel' => 'Highest Grade Level'); + + if (! defined($file_type) || $file_type ne 'portfolio') { + %fields = + (%fields, + 'courserestricted' => 'Course Restricting Metadata'); + } + + if (! defined($file_type) || $file_type ne 'portfolio') { + %fields = + (%fields, + 'domain' => 'Domain', 'mime' => 'MIME Type', 'language' => 'Language', 'creationdate' => 'Creation Date', @@ -175,6 +252,8 @@ sub fieldnames { 'owner' => 'Publisher/Owner', 'copyright' => 'Copyright/Distribution', 'customdistributionfile' => 'Custom Distribution File', + 'sourceavail' => 'Source Available', + 'sourcerights' => 'Source Custom Distribution File', 'obsolete' => 'Obsolete', 'obsoletereplacement' => 'Suggested Replacement for Obsolete File', 'count' => 'Network-wide number of accesses (hits)', @@ -193,14 +272,148 @@ sub fieldnames { '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' + 'difficulty' => 'Degree of difficulty', + 'disc' => 'Degree of discrimination', + 'dependencies' => 'Resources used by this resource', ); + } + return &Apache::lonlocal::texthash(%fields); +} + +sub portfolio_linked_path { + my ($path,$group,$port_path) = @_; + + my $start = 'portfolio'; + if ($group) { + $start = "groups/$group/".$start; + } + my %anchor_fields; + %anchor_fields = ( + 'selectfile' => $start, + 'currentpath' => '/' + ); + my $result = &Apache::portfolio::make_anchor($port_path,\%anchor_fields,$start); + my $fullpath = '/'; + my (undef,@tree) = split('/',$path); + my $filename = pop(@tree); + foreach my $dir (@tree) { + $fullpath .= $dir.'/'; + $result .= '/'; + my %anchor_fields = (); + %anchor_fields = ( + 'selectfile' => $dir, + 'currentpath' => $fullpath + ); + $result .= &Apache::portfolio::make_anchor($port_path,\%anchor_fields,$dir); + } + $result .= "/$filename"; + return $result; } +sub get_port_path_and_group { + my ($uri)=@_; + + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + + my ($port_path,$group); + if ($uri =~ m{^/editupload/\Q$cdom\E/\Q$cnum\E/groups/}) { + $group = (split('/',$uri))[5]; + $port_path = '/adm/coursegrp_portfolio'; + } else { + $port_path = '/adm/portfolio'; + } + if ($env{'form.group'} ne $group) { + $env{'form.group'} = $group; + } + return ($port_path,$group); +} + +sub portfolio_display_uri { + my ($uri,$as_links)=@_; + + my ($port_path,$group) = &get_port_path_and_group($uri); + + $uri =~ s|.*/(portfolio/.*)$|$1|; + my ($res_uri,$meta_uri) = ($uri,$uri); + if ($uri =~ /\.meta$/) { + $res_uri =~ s/\.meta//; + } else { + $meta_uri .= '.meta'; + } + + my ($path) = ($res_uri =~ m|^portfolio(.*/)[^/]*$|); + if ($as_links) { + $res_uri = &portfolio_linked_path($res_uri,$group,$port_path); + $meta_uri = &portfolio_linked_path($meta_uri,$group,$port_path); + } + return ($res_uri,$meta_uri,$path); +} + +sub pre_select_course { + my ($r,$uri) = @_; + my $output; + my $fn=&Apache::lonnet::filelocation('',$uri); + my ($res_uri,$meta_uri,$path) = &portfolio_display_uri($uri); + %Apache::lonpublisher::metadatafields=(); + %Apache::lonpublisher::metadatakeys=(); + my $result=&Apache::lonnet::getfile($fn); + if ($result == -1){ + $r->print(&mt('Creating new file [_1]'),$meta_uri); + } else { + &Apache::lonpublisher::metaeval($result); + } + $r->print('<hr /><form method="post" action="" >'); + $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>'); + $output = &select_course(); + $r->print($output.'<br /><input type="submit" name="store" value="'. + &mt('Associate Resource With Selected Course').'">'); + $r->print('</form>'); + + my ($port_path,$group) = &get_port_path_and_group($uri); + $r->print('<br /><br /><form method="POST" action="'.$port_path.'">'. + '<input type="hidden" name="currentpath" value="'.$path.'" />'. + '<input type="hidden" name="group" value="'.$group.'" />'. + '<input type="submit" name="cancel" value="'.&mt('Cancel').'">'. + '</form>'); + + return; +} +sub select_course { + my $output=$/; + my $current_restriction= + $Apache::lonpublisher::metadatafields{'courserestricted'}; + my $selected = ($current_restriction eq 'none' ? 'selected="selected"' + : ''); + + $output .= '<select name="new_courserestricted" >'; + $output .= '<option value="none" '.$selected.'>'. + &mt('None').'</option>'.$/; + my %courses; + foreach my $key (keys(%env)) { + if ($key !~ m/^course\.(.+)\.description$/) { next; } + my $cid = $1; + if ($env{$key} !~ /\S/) { next; } + $courses{$key} = $cid; + } + foreach my $key (sort { lc($env{$a}) cmp lc($env{$b}) } (keys(%courses))) { + my $cid = 'course.'.$courses{$key}; + my $selected = ($current_restriction eq $cid ? 'selected="selected"' + : ''); + if ($env{$key} !~ /\S/) { next; } + $output .= '<option value="'.$cid.'" '.$selected.'>'; + $output .= $env{$key}; + $output .= '</option>'.$/; + $selected = ''; + } + $output .= '</select><br />'; + return ($output); +} # Pretty printing of metadata field sub prettyprint { - my ($type,$value)=@_; + my ($type,$value,$target,$prefix,$form,$noformat)=@_; +# $target,$prefix,$form are optional and for filecrumbs only if (! defined($value)) { return ' '; } @@ -223,6 +436,10 @@ sub prettyprint { if ($type eq 'copyright') { return &Apache::loncommon::copyrightdescription($value); } + # Copyright + if ($type eq 'sourceavail') { + return &Apache::loncommon::source_copyrightdescription($value); + } # MIME if ($type eq 'mime') { return '<img src="'.&Apache::loncommon::icon($value).'" /> '. @@ -242,7 +459,7 @@ sub prettyprint { return &Apache::loncommon::gradeleveldescription($value); } # Only for advance users below - if (! $ENV{'user.adv'}) { + if (! $env{'user.adv'}) { return '<i>- '.&mt('not displayed').' -</i>'; } # File @@ -250,8 +467,9 @@ sub prettyprint { ($type eq 'obsoletereplacement') || ($type eq 'goto_list') || ($type eq 'comefrom_list') || - ($type eq 'sequsage_list')) { - return join('<br />',map { + ($type eq 'sequsage_list') || + ($type eq 'dependencies')) { + return '<font size="-1"><ul>'.join("\n",map { my $url = &Apache::lonnet::clutter($_); my $title = &Apache::lonnet::gettitle($url); if ($title eq '') { @@ -268,11 +486,10 @@ sub prettyprint { $title .= ' Syllabus'; } } - $_ = '<b>'.$title.'</b> '. - '<a href="'.$url.'" target="preview">'. - '<font size="-1">'.$url.'</font>'. - '</a>' - } split(/\s*\,\s*/,$value)); + $_ = '<li>'.$title.' '. + &Apache::lonhtmlcommon::crumbs($url,$target,$prefix,$form,'-1',$noformat). + '</li>' + } split(/\s*\,\s*/,$value)).'</ul></font>'; } # Evaluations if (($type eq 'clear') || @@ -283,24 +500,25 @@ sub prettyprint { return &evalgraph($value); } # Difficulty - if ($type eq 'difficulty') { + if ($type eq 'difficulty' || $type eq 'disc') { return &diffgraph($value); } # List of courses if ($type=~/\_list/) { my @Courses = split(/\s*\,\s*/,$value); - my $Str; + my $Str='<font size="-1"><ul>'; foreach my $course (@Courses) { - my %courseinfo = &Apache::lonnet::coursedescription($course); + my %courseinfo = + &Apache::lonnet::coursedescription($course, + {'one_time' => 1}); if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { next; } - if ($Str ne '') { $Str .= '<br />'; } - $Str .= '<a href="/public/'.$courseinfo{'domain'}.'/'. + $Str .= '<li><a href="/public/'.$courseinfo{'domain'}.'/'. $courseinfo{'num'}.'/syllabus" target="preview">'. - $courseinfo{'description'}.'</a>'; + $courseinfo{'description'}.'</a></li>'; } - return $Str; + return $Str.'</ul></font>'; } # No pretty print found return $value; @@ -344,7 +562,72 @@ sub relatedfield { sub prettyinput { my ($type,$value,$fieldname,$formname, - $relatedsearchflag,$relatedsep,$relatedvalue)=@_; + $relatedsearchflag,$relatedsep,$relatedvalue,$size,$course_key)=@_; + if (! defined($size)) { + $size = 80; + } + my $output; + if (defined($course_key) + && exists($env{$course_key.'.metadata.'.$type.'.options'})) { + my $stu_add; + my $only_one; + my %meta_options; + my @cur_values_inst; + my $cur_values_stu; + my $values = $env{$course_key.'.metadata.'.$type.'.values'}; + if ($env{$course_key.'.metadata.'.$type.'.options'} =~ m/stuadd/) { + $stu_add = 'true'; + } + if ($env{$course_key.'.metadata.'.$type.'.options'} =~ m/onlyone/) { + $only_one = 'true'; + } + # need to take instructor values out of list where instructor and student + # values may be mixed. + if ($values) { + foreach my $item (split(/,/,$values)) { + $item =~ s/^\s+//; + $meta_options{$item} = $item; + } + foreach my $item (split(/,/,$value)) { + $item =~ s/^\s+//; + if ($meta_options{$item}) { + push(@cur_values_inst,$item); + } else { + $cur_values_stu .= $item.','; + } + } + } else { + $cur_values_stu = $value; + } + if ($type eq 'courserestricted') { + return (&select_course()); + # return ('<input type="hidden" name="new_courserestricted" value="'.$course_key.'" />'); + } + if (($type eq 'keywords') || ($type eq 'subject') + || ($type eq 'author')||($type eq 'notes') + || ($type eq 'abstract')|| ($type eq 'title')|| ($type eq 'standards')) { + if ($values) { + if ($only_one) { + $output .= (&Apache::loncommon::select_form($cur_values_inst[0],'new_'.$type,%meta_options)); + } else { + $output .= (&Apache::loncommon::multiple_select_form('new_'.$type,\@cur_values_inst,undef,\%meta_options)); + } + } + if ($stu_add) { + $output .= '<input type="text" name="'.$fieldname.'" size="'.$size.'" '. + 'value="'.$cur_values_stu.'" />'. + &relatedfield(1,$relatedsearchflag,$relatedsep,$fieldname, + $relatedvalue); + } + return ($output); + } + if (($type eq 'lowestgradelevel') || + ($type eq 'highestgradelevel')) { + return &Apache::loncommon::select_level_form($value,$fieldname). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + return(); + } # Language if ($type eq 'language') { return &selectbox($fieldname, @@ -361,6 +644,14 @@ sub prettyinput { (&Apache::loncommon::copyrightids)). &relatedfield(0,$relatedsearchflag,$relatedsep); } + # Source Copyright + if ($type eq 'sourceavail') { + return &selectbox($fieldname, + $value, + \&Apache::loncommon::source_copyrightdescription, + (&Apache::loncommon::source_copyrightids)). + &relatedfield(0,$relatedsearchflag,$relatedsep); + } # Gradelevels if (($type eq 'lowestgradelevel') || ($type eq 'highestgradelevel')) { @@ -389,6 +680,19 @@ sub prettyinput { ",'rights')\">".&mt('Select').'</a>'. &relatedfield(0,$relatedsearchflag,$relatedsep); } + # Source Customdistribution file + if ($type eq 'sourcerights') { + return '<input type="text" name="'.$fieldname. + '" size="60" value="'.$value.'" /><a href="javascript:openbrowser'. + "('".$formname."','".$fieldname."'". + ",'rights')\">".&mt('Select').'</a>'. + &relatedfield(0,$relatedsearchflag,$relatedsep); + } + if ($type eq 'courserestricted') { + return (&select_course()); + #return ('<input type="hidden" name="new_courserestricted" value="'.$course_key.'" />'); + } + # Dates if (($type eq 'creationdate') || ($type eq 'lastrevisiondate')) { @@ -400,9 +704,9 @@ sub prettyinput { $value=~s/^\s+//gs; $value=~s/\s+$//gs; $value=~s/\s+/ /gs; - $value=~s/\"/\&quod\;/gs; + $value=~s/\"/\"\;/gs; return - '<input type="text" name="'.$fieldname.'" size="80" '. + '<input type="text" name="'.$fieldname.'" size="'.$size.'" '. 'value="'.$value.'" />'. &relatedfield(1,$relatedsearchflag,$relatedsep,$fieldname, $relatedvalue); @@ -414,44 +718,41 @@ sub handler { # my $uri=$r->uri; # - # Check to see if this server is overloaded - my $loaderror=&Apache::lonnet::overloaderror($r); - if ($loaderror) { - return $loaderror; - } - # - # Check to see if original resource server is overloaded - my ($resdomain,$resuser)= - (&Apache::lonnet::declutter($uri)=~/^(\w+)\/(\w+)\//); - $loaderror=&Apache::lonnet::overloaderror - ($r,&Apache::lonnet::homeserver($resuser,$resdomain)); - if ($loaderror) { - return $loaderror; - } - # # Set document type &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK if $r->header_only; # - $r->print('<html><head><title>'. - 'Catalog Information'. - '</title></head>'); + my ($resdomain,$resuser)= + (&Apache::lonnet::declutter($uri)=~/^(\w+)\/(\w+)\//); if ($uri=~m:/adm/bombs/(.*)$:) { - $r->print(&Apache::loncommon::bodytag('Error Messages')); + $r->print(&Apache::loncommon::start_page('Error Messages')); # Looking for all bombs? &report_bombs($r,$uri); - } elsif ($uri=~/^\/\~/) { + } elsif ($uri=~m|^/editupload/[^/]+/[^/]+/portfolio/|) { + ($resdomain,$resuser)= + (&Apache::lonnet::declutter($uri)=~m|^(\w+)/(\w+)/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 { + &pre_select_course($r,$uri); + } + } elsif ($uri=~m|^/~|) { # Construction space - $r->print(&Apache::loncommon::bodytag - ('Edit Catalog Information','','','',$resdomain)); + $r->print(&Apache::loncommon::start_page('Edit Catalog nformation', + undef, + {'domain' => $resdomain,})); &present_editable_metadata($r,$uri); } else { - $r->print(&Apache::loncommon::bodytag - ('Catalog Information','','','',$resdomain)); + $r->print(&Apache::loncommon::start_page('Catalog Information', + undef, + {'domain' => $resdomain,})); &present_uneditable_metadata($r,$uri); } - $r->print('</body></html>'); + $r->print(&Apache::loncommon::end_page()); return OK; } @@ -470,6 +771,15 @@ sub report_bombs { $r->print('<h1>'.&Apache::lonnet::clutter($uri).'</h1>'); my ($domain,$author)=($uri=~/^(\w+)\/(\w+)\//); if (&Apache::loncacc::constructaccess('/~'.$author.'/',$domain)) { + if ($env{'form.clearbombs'}) { + &Apache::lonmsg::clear_author_res_msg($uri); + } + my $clear=&mt('Clear all Messages in Subdirectory'); + $r->print(<<ENDCLEAR); +<form method="post"> +<input type="submit" name="clearbombs" value="$clear" /> +</form> +ENDCLEAR my %brokenurls = &Apache::lonmsg::all_url_author_res_msg($author,$domain); foreach (sort(keys(%brokenurls))) { @@ -496,6 +806,7 @@ sub report_bombs { sub present_uneditable_metadata { my ($r,$uri) = @_; # + my $uploaded = ($uri =~ m|/uploaded/|); my %content=(); # Read file foreach (split(/\,/,&Apache::lonnet::metadata($uri,'keys'))) { @@ -506,17 +817,20 @@ sub present_uneditable_metadata { my ($thisversion)=($uri=~/\.(\d+)\.(\w+)\.meta$/); $uri=~s/\.meta$//; my $disuri=&Apache::lonnet::clutter($uri); + $disuri=~s/^\/adm\/wrapper//; # version - my $currentversion=&Apache::lonnet::getversion($disuri); my $versiondisplay=''; - if ($thisversion) { - $versiondisplay=&mt('Version').': '.$thisversion. - ' ('.&mt('most recent version').': '. - ($currentversion>0 ? - $currentversion : - &mt('information not available')).')'; - } else { - $versiondisplay='Version: '.$currentversion; + 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'); @@ -524,7 +838,7 @@ sub present_uneditable_metadata { # obsolete my $obsolete=$content{'obsolete'}; my $obsoletewarning=''; - if (($obsolete) && ($ENV{'user.adv'})) { + if (($obsolete) && ($env{'user.adv'})) { $obsoletewarning='<p><font color="red">'. &mt('This resource has been marked obsolete by the author(s)'). '</font></p>'; @@ -536,28 +850,38 @@ sub present_uneditable_metadata { if (! defined($title)) { $title = 'Untitled Resource'; } - foreach ('title', - 'author', - 'subject', - 'keywords', - 'notes', - 'abstract', - 'lowestgradelevel', - 'highestgradelevel', - 'standards', - 'mime', - 'language', - 'creationdate', - 'lastrevisiondate', - 'owner', - 'copyright', - 'customdistributionfile', - 'obsolete', - 'obsoletereplacement') { - $table.='<tr><td bgcolor="#AAAAAA">'.$lt{$_}. + 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.='<tr><td bgcolor="#AAAAAA">'.$lt{$field}. '</td><td bgcolor="#CCCCCC">'. - &prettyprint($_,$content{$_}).'</td></tr>'; - delete $content{$_}; + &prettyprint($field,$content{$field}).'</td></tr>'; + delete($content{$field}); } # $r->print(<<ENDHEAD); @@ -567,11 +891,11 @@ $disuri<br /> $obsoletewarning $versiondisplay </p> -<table cellspacing=2 border=0> +<table cellspacing="2" border="0"> $table </table> ENDHEAD - if ($ENV{'user.adv'}) { + if (!$uploaded && $env{'user.adv'}) { &print_dynamic_metadata($r,$uri,\%content); } return; @@ -597,7 +921,7 @@ sub print_dynamic_metadata { exists($dynmeta{'goto'}) || exists($dynmeta{'course'})) { $r->print('<h4>'.&mt('Access and Usage Statistics').'</h4>'. - '<table cellspacing=2 border=0>'); + '<table cellspacing="2" border="0">'); foreach ('count', 'sequsage','sequsage_list', 'comefrom','comefrom_list', @@ -613,30 +937,97 @@ sub print_dynamic_metadata { } # # Assessment statistics - if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/ && - (exists($dynmeta{'stdno'}) || - exists($dynmeta{'avetries'}) || - exists($dynmeta{'difficulty'}))) { - # This is an assessment, print assessment data - $r->print('<h4>'.&mt('Assessment Statistical Data').'</h4>'. - '<table cellspacing=2 border=0>'); - foreach ('stdno','avetries','difficulty') { - $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'. + if ($uri=~/\.(problem|exam|quiz|assess|survey|form)$/) { + if (exists($dynmeta{'stdno'}) || + exists($dynmeta{'avetries'}) || + exists($dynmeta{'difficulty'}) || + exists($dynmeta{'disc'})) { + # This is an assessment, print assessment data + $r->print('<h4>'. + &mt('Overall Assessment Statistical Data'). + '</h4>'. + '<table cellspacing="2" border="0">'); + $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{'stdno'}.'</td>'. '<td bgcolor="#CCCCCC">'. - &prettyprint($_,sprintf('%5.2f',$dynmeta{$_})).'</td>'. - "</tr>\n"); + &prettyprint('stdno',$dynmeta{'stdno'}). + '</td>'."</tr>\n"); + foreach ('avetries','difficulty','disc') { + $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'. + '<td bgcolor="#CCCCCC">'. + &prettyprint($_,sprintf('%5.2f',$dynmeta{$_})). + '</td>'."</tr>\n"); + } + $r->print('</table>'); + } + if (exists($dynmeta{'stats'})) { + # + # New assessment statistics + $r->print('<h4>'. + &mt('Detailed Assessment Statistical Data'). + '</h4>'); + my $table = '<table cellspacing="2" border="0">'. + '<tr>'. + '<th>Course</th>'. + '<th>Section(s)</th>'. + '<th>Num Students</th>'. + '<th>Mean Tries</th>'. + '<th>Degree of Difficulty</th>'. + '<th>Degree of Discrimination</th>'. + '<th>Time of computation</th>'. + '</tr>'.$/; + foreach my $identifier (sort(keys(%{$dynmeta{'stats'}}))) { + my $data = $dynmeta{'stats'}->{$identifier}; + my $course = $data->{'course'}; + my %courseinfo = + &Apache::lonnet::coursedescription($course, + {'one_time' => 1}); + if (! exists($courseinfo{'num'}) || $courseinfo{'num'} eq '') { + &Apache::lonnet::logthis('lookup for '.$course.' failed'); + next; + } + $table .= '<tr>'; + $table .= + '<td><nobr>'.$courseinfo{'description'}.'</nobr></td>'; + $table .= + '<td align="right">'.$data->{'sections'}.'</td>'; + $table .= + '<td align="right">'.$data->{'stdno'}.'</td>'; + foreach ('avetries','difficulty','disc') { + $table .= '<td align="right">'; + if (exists($data->{$_})) { + $table .= sprintf('%.2f',$data->{$_}).' '; + } else { + $table .= ''; + } + $table .= '</td>'; + } + $table .= + '<td><nobr>'. + &Apache::lonlocal::locallocaltime($data->{'timestamp'}). + '</nobr></td>'; + $table .= + '</tr>'.$/; + } + $table .= '</table>'.$/; + $r->print($table); + } else { + $r->print('No new dynamic data found.'); } - $r->print('</table>'); } else { - $r->print('<h4>'.&mt('No Assessment Statistical Data is available for this resource').'</h4>'); + $r->print('<h4>'. + &mt('No Assessment Statistical Data is available for this resource'). + '</h4>'); } + + # + # if (exists($dynmeta{'clear'}) || exists($dynmeta{'depth'}) || exists($dynmeta{'helpful'}) || exists($dynmeta{'correct'}) || exists($dynmeta{'technical'})){ $r->print('<h4>'.&mt('Evaluation Data').'</h4>'. - '<table cellspacing=2 border=0>'); + '<table cellspacing="2" border="0">'); foreach ('clear','depth','helpful','correct','technical') { $r->print('<tr><td bgcolor="#AAAAAA">'.$lt{$_}.'</td>'. '<td bgcolor="#CCCCCC">'. @@ -647,8 +1038,8 @@ sub print_dynamic_metadata { $r->print('<h4>'.&mt('No Evaluation Data is available for this resource.').'</h4>'); } $uri=~/^\/res\/(\w+)\/(\w+)\//; - if ((($ENV{'user.domain'} eq $1) && ($ENV{'user.name'} eq $2)) - || ($ENV{'user.role.ca./'.$1.'/'.$2})) { + if ((($env{'user.domain'} eq $1) && ($env{'user.name'} eq $2)) + || ($env{'user.role.ca./'.$1.'/'.$2})) { if (exists($dynmeta{'comments'})) { $r->print('<h4>'.&mt('Evaluation Comments').' ('. &mt('visible to author and co-authors only'). @@ -670,7 +1061,7 @@ sub print_dynamic_metadata { # All other stuff $r->print('<h3>'. &mt('Additional Metadata (non-standard, parameters, exports)'). - '</h3>'); + '</h3><table border="0" cellspacing="1">'); foreach (sort(keys(%content))) { my $name=$_; if ($name!~/\.display$/) { @@ -688,16 +1079,19 @@ sub print_dynamic_metadata { $name.'.'.$_).'; '; } } - $r->print('<b>'.$display.':</b> '.$content{$name}); + $r->print('<tr><td bgcolor="#bbccbb"><font size="-1" color="#556655">'.$display.'</font></td><td bgcolor="#ccddcc"><font size="-1" color="#556655">'.$content{$name}); if ($otherinfo) { $r->print(' ('.$otherinfo.')'); } - $r->print("<br />\n"); + $r->print("</font></td></tr>\n"); } } + $r->print("</table>"); return; } + + ##################################################### ##################################################### ### ### @@ -706,32 +1100,58 @@ sub print_dynamic_metadata { ##################################################### ##################################################### sub present_editable_metadata { - my ($r,$uri) = @_; + my ($r,$uri, $file_type) = @_; # Construction Space Call # Header my $disuri=$uri; my $fn=&Apache::lonnet::filelocation('',$uri); - $disuri=~s/^\/\~/\/priv\//; + $disuri=~s{^/\~}{/priv/}; $disuri=~s/\.meta$//; + my $meta_uri = $disuri; + my $path; + if ($disuri =~ m|/portfolio/|) { + ($disuri, $meta_uri, $path) = &portfolio_display_uri($disuri,1); + } my $target=$uri; - $target=~s/^\/\~/\/res\/$ENV{'request.role.domain'}\//; + $target=~s{^/\~}{/res/$env{'request.role.domain'}/}; $target=~s/\.meta$//; my $bombs=&Apache::lonmsg::retrieve_author_res_msg($target); if ($bombs) { - if ($ENV{'form.delmsg'}) { + my $showdel=1; + if ($env{'form.delmsg'}) { if (&Apache::lonmsg::del_url_author_res_msg($target) eq 'ok') { $bombs=&mt('Messages deleted.'); + $showdel=0; } else { $bombs=&mt('Error deleting messages'); } } - my $del=&mt('Delete Messages'); + if ($env{'form.clearmsg'}) { + my $cleardir=$target; + $cleardir=~s/\/[^\/]+$/\//; + if (&Apache::lonmsg::clear_author_res_msg($cleardir) eq 'ok') { + $bombs=&mt('Messages cleared.'); + $showdel=0; + } else { + $bombs=&mt('Error clearing messages'); + } + } + my $del=&mt('Delete Messages for this Resource'); + my $clear=&mt('Clear all Messages in Subdirectory'); + my $goback=&mt('Back to Source File'); $r->print(<<ENDBOMBS); <h1>$disuri</h1> <form method="post" name="defaultmeta"> -<input type="submit" name="delmsg" value="$del" /> -<br />$bombs ENDBOMBS + if ($showdel) { + $r->print(<<ENDDEL); +<input type="submit" name="delmsg" value="$del" /> +<input type="submit" name="clearmsg" value="$clear" /> +ENDDEL + } else { + $r->print('<a href="'.$disuri.'" />'.$goback.'</a>'); + } + $r->print('<br />'.$bombs); } else { my $displayfile='Catalog Information for '.$disuri; if ($disuri=~/\/default$/) { @@ -741,76 +1161,179 @@ ENDBOMBS &mt('Default Cataloging Information for Directory').' '. $dir; } - my $bodytag= - &Apache::loncommon::bodytag('Edit Catalog Information'); %Apache::lonpublisher::metadatafields=(); %Apache::lonpublisher::metadatakeys=(); - &Apache::lonpublisher::metaeval(&Apache::lonnet::getfile($fn)); + my $result=&Apache::lonnet::getfile($fn); + if ($result == -1){ + $r->print(&mt('Creating new file [_1]'),$meta_uri); + } else { + &Apache::lonpublisher::metaeval($result); + } $r->print(<<ENDEDIT); -<html><head><title>Edit Catalog Information</title></head> -$bodytag <h1>$displayfile</h1> <form method="post" name="defaultmeta"> ENDEDIT $r->print('<script language="JavaScript">'. - &Apache::loncommon::browser_and_searcher_javascript. + &Apache::loncommon::browser_and_searcher_javascript(). '</script>'); - my %lt=&fieldnames(); - foreach ('author','title','subject','keywords','abstract','notes', + my %lt=&fieldnames($file_type); + my $output; + my @fields; + if ($file_type eq 'portfolio') { + @fields = ('author','title','subject','keywords','abstract', + 'notes','lowestgradelevel', + 'highestgradelevel','standards'); + } else { + @fields = ('author','title','subject','keywords','abstract','notes', 'copyright','customdistributionfile','language', 'standards', - 'lowestgradelevel','highestgradelevel', - 'obsolete','obsoletereplacement') { - if (defined($ENV{'form.new_'.$_})) { - $Apache::lonpublisher::metadatafields{$_}= - $ENV{'form.new_'.$_}; - } - if (! $Apache::lonpublisher::metadatafields{'copyright'}) { + 'lowestgradelevel','highestgradelevel','sourceavail','sourcerights', + 'obsolete','obsoletereplacement'); + } + if ((! $Apache::lonpublisher::metadatafields{'courserestricted'}) && + (! $env{'form.new_courserestricted'})) { + $Apache::lonpublisher::metadatafields{'courserestricted'}= + 'none'; + } elsif ($env{'form.new_courserestricted'}) { + $Apache::lonpublisher::metadatafields{'courserestricted'}= + $env{'form.new_courserestricted'}; + } + if (! $Apache::lonpublisher::metadatafields{'copyright'}) { $Apache::lonpublisher::metadatafields{'copyright'}= - 'default'; + 'default'; + } + if ($file_type eq 'portfolio') { + if (! $Apache::lonpublisher::metadatafields{'mime'}) { + ($Apache::lonpublisher::metadatafields{'mime'}) = + ( $target=~/\.(\w+)$/ ); + } + if (! $Apache::lonpublisher::metadatafields{'owner'}) { + $Apache::lonpublisher::metadatafields{'owner'} = + $env{'user.name'}.':'.$env{'user.domain'}; + } + + if ($Apache::lonpublisher::metadatafields{'courserestricted'} ne 'none') { + $r->print(&mt('Associated with course [_1]','<strong>'.$env{$Apache::lonpublisher::metadatafields{'courserestricted'}.".description"}. + '</strong>').'<br />'); + } else { + $r->print("This resource is not associated with a course.<br />"); + } + } + foreach my $field_name (@fields) { + + if (defined($env{'form.new_'.$field_name})) { + $Apache::lonpublisher::metadatafields{$field_name}= + join(',',&Apache::loncommon::get_env_multiple('form.new_'.$field_name)); } - $r->print('<p>'.$lt{$_}.': '. - &prettyinput - ($_,$Apache::lonpublisher::metadatafields{$_}, - 'new_'.$_,'defaultmeta').'</p>'); - } - if ($ENV{'form.store'}) { - my $mfh; - if (! ($mfh=Apache::File->new('>'.$fn))) { - $r->print('<p><font color=red>'. - &mt('Could not write metadata').', '. - &mt('FAIL').'</font>'); + if ($Apache::lonpublisher::metadatafields{'courserestricted'} ne 'none' + && exists($env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.'.$field_name.'.options'})) { + # handle restrictions here + if (($env{$Apache::lonpublisher::metadatafields{'courserestricted'}.'.metadata.'.$field_name.'.options'} =~ m/active/) || + ($field_name eq 'courserestricted')){ + $output.=("\n".'<p>'.$lt{$field_name}.': '. + &prettyinput($field_name, + $Apache::lonpublisher::metadatafields{$field_name}, + 'new_'.$field_name,'defaultmeta', + undef,undef,undef,undef, + $Apache::lonpublisher::metadatafields{'courserestricted'}).'</p>'."\n"); + } } else { - foreach (sort keys %Apache::lonpublisher::metadatafields) { - next if ($_ =~ /\./); - my $unikey=$_; - $unikey=~/^([A-Za-z]+)/; - my $tag=$1; - $tag=~tr/A-Z/a-z/; - print $mfh "\n\<$tag"; - foreach (split(/\,/, - $Apache::lonpublisher::metadatakeys{$unikey}) - ) { - my $value= - $Apache::lonpublisher::metadatafields{$unikey.'.'.$_}; - $value=~s/\"/\'\'/g; - print $mfh ' '.$_.'="'.$value.'"'; - } - print $mfh '>'. - &HTML::Entities::encode - ($Apache::lonpublisher::metadatafields{$unikey}, - '<>&"'). - '</'.$tag.'>'; - } - $r->print('<p>'.&mt('Wrote Metadata')); + + $output.=('<p>'.$lt{$field_name}.': '. + &prettyinput($field_name, + $Apache::lonpublisher::metadatafields{$field_name}, + 'new_'.$field_name,'defaultmeta').'</p>'); + } } - $r->print('<br /><input type="submit" name="store" value="'. + if ($env{'form.store'}) { + my $mfh; + my $formname='store'; + my $file_content; + if (&Apache::loncommon::get_env_multiple('form.new_keywords')) { + $Apache::lonpublisher::metadatafields{'keywords'} = + join (',', &Apache::loncommon::get_env_multiple('form.new_keywords')); + } + + foreach (sort keys %Apache::lonpublisher::metadatafields) { + next if ($_ =~ /\./); + my $unikey=$_; + $unikey=~/^([A-Za-z]+)/; + my $tag=$1; + $tag=~tr/A-Z/a-z/; + $file_content.= "\n\<$tag"; + foreach (split(/\,/, + $Apache::lonpublisher::metadatakeys{$unikey}) + ) { + my $value= + $Apache::lonpublisher::metadatafields{$unikey.'.'.$_}; + $value=~s/\"/\'\'/g; + $file_content.=' '.$_.'="'.$value.'"' ; + # print $mfh ' '.$_.'="'.$value.'"'; + } + $file_content.= '>'. + &HTML::Entities::encode + ($Apache::lonpublisher::metadatafields{$unikey}, + '<>&"'). + '</'.$tag.'>'; + } + if ($fn =~ m|^$Apache::lonnet::perlvar{'lonDocRoot'}/userfiles/portfolio/|) { + my ($path, $new_fn) = ($fn =~ m|/(portfolio.*)/([^/]*)$|); + $r->print(&store_portfolio_metadata($formname,$file_content,$path, + $new_fn)); + } elsif ($fn =~ m|^$Apache::lonnet::perlvar{'lonDocRoot'}/userfiles/groups/\w+/portfolio/|) { + my ($path, $new_fn) = ($fn =~ m|/(groups/\w+/portfolio.*)/([^/]*)$|); + $r->print(&store_portfolio_metadata($formname,$file_content,$path,$new_fn)); + } else { + if (! ($mfh=Apache::File->new('>'.$fn))) { + $r->print('<p><font color="red">'. + &mt('Could not write metadata').', '. + &mt('FAIL').'</font></p>'); + } else { + print $mfh $file_content; + $r->print('<p><font color="blue">'.&mt('Wrote Metadata'). + ' '.&Apache::lonlocal::locallocaltime(time). + '</font></p>'); + } + } + } + + $r->print($output.'<br /><input type="submit" name="store" value="'. &mt('Store Catalog Information').'">'); + + if ($file_type eq 'portfolio') { + my ($port_path,$group) = &get_port_path_and_group($uri); + if ($group) { + $r->print('<input type="hidden" name="group" value="'.$group.'" />'); + } + $r->print('</form> + <br /><br /><form method="POST" action="'.$port_path.'">'. + '<input type="hidden" name="group" value="'.$group.'" />'. + '<input type="hidden" name="currentpath" value="'.$path.'" />'. + '<input type="submit" name="cancel" value="'.&mt('Discard Edits and Return to Portfolio').'">'); + } } + $r->print('</form>'); + return; } +sub store_portfolio_metadata { + my ($formname,$content,$path,$new_fn) = @_; + $env{'form.'.$formname}=$content."\n"; + $env{'form.'.$formname.'.filename'}=$new_fn; + my $result =&Apache::lonnet::userfileupload($formname,'',$path); + if ($result =~ /(error|notfound)/) { + return '<p><font color="red">'. + &mt('Could not write metadata').', '. + &mt('FAIL').'</font></p>'; + } else { + return '<p><font color="blue">'.&mt('Wrote Metadata'). + ' '.&Apache::lonlocal::locallocaltime(time).'</font></p>'; + } +} + 1; __END__ +