File:  [LON-CAPA] / loncom / publisher / lonpubdir.pm
Revision 1.161: download - view: text, annotated - select for diffs
Mon Oct 13 14:50:42 2014 UTC (9 years, 7 months ago) by goltermann
Branches: MAIN
CVS tags: HEAD
added search functionality to authoring space

- users can now search their author space for files. the search functions searches in the file name and title. use of regular expressions and case sensitivity can be enabled. the content table of the current directory will shrink so that only matching entries are shown. a second table appears underneath to show results in other directories.
- german translation has been added.

    1: # The LearningOnline Network with CAPA
    2: # Authoring Space Directory Lister
    3: #
    4: # $Id: lonpubdir.pm,v 1.161 2014/10/13 14:50:42 goltermann 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: 
   30: package Apache::lonpubdir;
   31: 
   32: use strict;
   33: use Apache::File;
   34: use File::Copy;
   35: use Apache::Constants qw(:common :http :methods);
   36: use Apache::loncommon();
   37: use Apache::lonhtmlcommon();
   38: use Apache::londiff();
   39: use Apache::lonlocal;
   40: use Apache::lonmsg;
   41: use Apache::lonmenu;
   42: use Apache::lonnet;
   43: use LONCAPA qw(:DEFAULT :match);
   44: 
   45: sub handler {
   46: 
   47:     my $r=shift;
   48: 
   49:     # Validate access to the construction space and get username:domain.
   50: 
   51:     my ($uname,$udom)=&Apache::lonnet::constructaccess($r->uri); 
   52:     unless (($uname) && ($udom)) {
   53:         return HTTP_NOT_ACCEPTABLE;
   54:     }
   55: 
   56: # ----------------------------------------------------------- Start page output
   57: 
   58:     my $fn=$r->filename;
   59:     $fn=~s/\/$//;
   60:     my $thisdisfn=$fn;
   61: 
   62:     my $docroot=$r->dir_config('lonDocRoot');     # Apache  londocument root.
   63:     if ($thisdisfn eq "$docroot/priv/$udom") {
   64:         if ((-d "/home/$uname/public_html/") && (!-e "$docroot/priv/$udom/$uname")) {
   65:             my ($version) = ($r->dir_config('lonVersion') =~ /^\'?(\d+\.\d+)\./);
   66:             &Apache::loncommon::content_type($r,'text/html');
   67:             $r->send_http_header;
   68: 
   69:             &Apache::lonhtmlcommon::clear_breadcrumbs();
   70:             $r->print(&Apache::loncommon::start_page('Authoring Space').
   71:                       '<div class="LC_error">'.
   72:                       '<br /><p>'.
   73:                       &mt('Your Authoring Space is currently in the location used by LON-CAPA version 2.10 and older, but your domain is using a newer LON-CAPA version ([_1]).',$version).'</p>'.
   74:                       '<p>'.
   75:                       &mt('Please ask your Domain Coordinator to move your Authoring Space to the new location.').
   76:                       '</p>'.
   77:                       '</div>'.
   78:                       &Apache::loncommon::end_page());
   79:             return OK;
   80:         }
   81:     }
   82:     $thisdisfn=~s/^\Q$docroot\E\/priv//;
   83:     
   84:     my $resdir=$docroot.'/res'.$thisdisfn; # Resource directory
   85:     my $targetdir='/res'.$thisdisfn; # Publication target directory.
   86:     my $linkdir='/priv'.$thisdisfn;      # Full URL name of constr space.
   87: 
   88:     my %bombs=&Apache::lonmsg::all_url_author_res_msg($uname,$udom);
   89: 
   90:     &startpage($r, $uname, $udom, $thisdisfn);  # Put out the start of page.
   91: 
   92:     if (!-d $fn) {
   93:         if (-e $fn) {
   94:             $r->print('<p class="LC_info">'.&mt('Requested item is a file not a directory.').'</p>');
   95:         } else {
   96:             $r->print('<p class="LC_info">'.&mt('The requested subdirectory does not exist.').'</p>');
   97:         }
   98:         $r->print(&Apache::loncommon::end_page());
   99:         return OK;
  100:     }
  101:     my @files;
  102:     if (opendir(DIR,$fn)) {
  103:         @files = grep(!/^\.+$/,readdir(DIR));
  104:         closedir(DIR);
  105:     } else {
  106:         $r->print('<p class="LC_error">'.&mt('Could not open directory.').'</p>');
  107:         $r->print(&Apache::loncommon::end_page());
  108:         return OK;
  109:     }
  110: 
  111:     &dircontrols($r,$uname,$udom,$thisdisfn);   # Put out actions for directory, 
  112:                                                 # browse/upload + new file page.
  113:     &resourceactions($r,$uname,$udom,$thisdisfn); # Put out form used for printing/deletion etc.
  114: 
  115:     my $numdir = 0;
  116:     my $numres = 0;
  117:   
  118:     if ((@files == 0) && ($thisdisfn =~ m{^/$match_domain/$match_username})) {
  119:         if ($thisdisfn =~ m{^/$match_domain/$match_username$}) {
  120:             $r->print('<p class="LC_info">'.&mt('This Authoring Space is currently empty.').'</p>');
  121:         } else {
  122:             $r->print('<p class="LC_info">'.&mt('This subdirectory is currently empty.').'</p>');
  123:         }
  124:         $r->print(&Apache::loncommon::end_page());
  125:         return OK;
  126:     }
  127: 
  128:     # Retrieving value for "sortby" and "sortorder" from QUERY_STRING
  129:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  130:         ['sortby','sortorder']);
  131: 
  132:     # Sort by name as default, not reversed
  133:     if (! exists($env{'form.sortby'})) { $env{'form.sortby'} = 'filename' }
  134:     if (! exists($env{'form.sortorder'})) { $env{'form.sortorder'} = '' }
  135:     my $sortby = $env{'form.sortby'};
  136:     my $sortorder = $env{'form.sortorder'};
  137: 
  138:     # Order in which columns are displayed from left to right
  139:     my @order = ('filetype','actions','filename','title',
  140:                     'pubstatus','cmtime','size');
  141: 
  142:     # Up and down arrows to indicate sort order
  143:     my @arrows = ('&nbsp;&#9650;','&nbsp;&#9660;','');
  144: 
  145:     # Default sort order and column title
  146:     my %columns = (
  147:         filetype =>     {
  148:                             order => 'ascending',
  149:                             text  => &mt('Type'),
  150:                         },
  151:         actions =>      {
  152:                             # Not sortable
  153:                             text  => &mt('Actions'),
  154:                         },
  155:         filename =>     {
  156:                             order => 'ascending',
  157:                             text  => &mt('Name'),
  158:                         },
  159:         title =>        {
  160:                             order => 'ascending',
  161:                             text  => &mt('Title'),
  162:                         },
  163:         pubstatus =>    {
  164:                             order => 'ascending',
  165:                             text  => &mt('Status'),
  166:                             colspan => '2',
  167:                         },
  168:         cmtime =>       {
  169:                             order => 'descending',
  170:                             text  => &mt('Last Modified'),
  171:                         },
  172:         size =>         {
  173:                             order => 'ascending',
  174:                             text  => &mt('Size').' (kB)',
  175:                         },
  176:     ); 
  177: 
  178:     # Print column headers
  179:     my $output = '';
  180:     foreach my $key (@order) {
  181:         my $idx;
  182:         # Append an up or down arrow to sorted column
  183:         if ($sortby eq $key) {
  184:             $idx = ($columns{$key}{order} eq 'ascending') ? 0:1;
  185:             if ($sortorder eq 'rev') { $idx ++; }
  186:             $idx = $idx%2;
  187:         } else { $idx = 2; } # No arrow if column is not sorted
  188:         $output .= (($columns{$key}{order}) ?
  189:             '<th'.($columns{$key}{colspan} ? ' colspan="'.$columns{$key}{colspan}.'"' : '')
  190:             .'><a href="'.$linkdir.'/?sortby='.$key.'&sortorder='
  191:             .((($sortby eq $key) && ($sortorder ne 'rev')) ? 'rev' : '').'">'
  192:             .$columns{$key}{text}.$arrows[$idx].'</a></th>' :
  193:             '<th>'.$columns{$key}{text}.'</th>');
  194:     }
  195: 
  196: my $result = "<script>
  197:     sessionStorage.setItem('CSTRcache','".&prepareJsonData($uname,$udom,$thisdisfn)."');
  198:     localStorage.setItem('CSTRtrans', '".&prepareJsonTranslations()."');
  199: </script>";
  200:     $r->print($result);
  201: 
  202:     $r->print('<div id="currentFolder">'.&Apache::loncommon::start_data_table()
  203:         .'<th colspan=8 id="searchtitle" style="display:none"></th>'
  204:         .&Apache::loncommon::start_data_table_header_row() . $output
  205:         .&Apache::loncommon::end_data_table_header_row()
  206:     );
  207: 
  208:     my $dirptr=16384;		# Mask indicating a directory in stat.cmode.
  209:     my $filehash = {};
  210:     foreach my $filename (@files) {
  211:         # Skip .DS_Store, .DAV and hidden files
  212:         my ($extension) = ($filename=~/\.(\w+)$/);
  213:         next if (($filename eq '.DS_Store')
  214:                 || ($filename eq '.DAV')
  215:                 || (&Apache::loncommon::fileembstyle($extension) eq 'hdn')
  216:                 || ($filename =~ /^\._/));
  217: 
  218:         my ($cmode,$csize,$cmtime)=(stat($fn.'/'.$filename))[2,7,9];
  219:         my $linkfilename = &HTML::Entities::encode('/priv'.$thisdisfn.'/'.$filename,'<>&"');
  220:         # Identify type of file according to icon used
  221:         my ($filetype) = (&Apache::loncommon::icon($filename) =~ m{/(\w+).gif$}); 
  222:         my $cstr_dir = $r->dir_config('lonDocRoot').'/priv'.$thisdisfn;
  223:         my $meta_same = &isMetaSame($cstr_dir, $resdir, $filename);
  224:         
  225:         # Store size, title, and status for files but not directories
  226:         my $size = (!($cmode&$dirptr)) ? $csize/1024. : 0;
  227:         my ($status, $pubstatus, $title, $fulltitle);
  228:         if (!($cmode&$dirptr)) {
  229:             ($status, $pubstatus) = &getStatus($resdir, $targetdir, $cstr_dir, 
  230:                 $filename, $linkfilename, $cmtime, $meta_same);
  231:             ($fulltitle, $title) = &getTitle($resdir, $targetdir, $filename, 
  232:                                         $linkfilename, $meta_same, \%bombs);
  233:         } else {
  234:             ($status, $pubstatus) = ('','');
  235:             ($fulltitle, $title) = ('','');
  236:         }
  237: 
  238:         # This hash will allow sorting
  239:         $filehash->{ $filename } = {
  240:             "cmtime"            => $cmtime,
  241:             "size"              => $size,
  242:             "cmode"             => $cmode,
  243:             "filetype"          => $filetype,
  244:             "title"             => $title,
  245:             "fulltitle"         => $fulltitle,
  246:             "status"            => $status,
  247:             "pubstatus"         => $pubstatus,
  248:             "linkfilename"      => $linkfilename,
  249:         }
  250:     }
  251:    
  252:     my @sorted_files;
  253:     # Sorting by something other than "Name".  Name is the secondary key.
  254:     if ($sortby =~ m{cmtime|size}) {    # Numeric fields
  255:         # First check if order should be reversed
  256:         if ($sortorder eq "rev") {
  257:             @sorted_files = sort {
  258:                 $filehash->{$a}->{$sortby} <=> $filehash->{$b}->{$sortby}
  259:                     or
  260:                 uc($a) cmp uc($b)
  261:             } (keys(%{$filehash}));
  262:         } else {
  263:             @sorted_files = sort {
  264:                 $filehash->{$b}->{$sortby} <=> $filehash->{$a}->{$sortby}
  265:                     or
  266:                 uc($a) cmp uc($b)
  267:             } (keys(%{$filehash}));
  268:         }
  269:     } elsif ($sortby =~ m{filetype|title|status}) {     # String fields
  270:         if ($sortorder eq "rev") {
  271:             @sorted_files = sort {
  272:                 $filehash->{$b}->{$sortby} cmp $filehash->{$a}->{$sortby}
  273:                     or
  274:                 uc($a) cmp uc($b)
  275:             } (keys(%{$filehash}));
  276:         } else {
  277:             @sorted_files = sort {
  278:                 $filehash->{$a}->{$sortby} cmp $filehash->{$b}->{$sortby}
  279:                     or
  280:                 uc($a) cmp uc($b)
  281:             } (keys(%{$filehash}));
  282:         }
  283: 
  284:     # Sort by "Name" is the default
  285:     } else { 
  286:         if ($sortorder eq "rev") {
  287:             @sorted_files = sort {uc($b) cmp uc($a)} (keys(%{$filehash}));
  288:         } else {
  289:             @sorted_files = sort {uc($a) cmp uc($b)} (keys(%{$filehash}));
  290:         }
  291:     }
  292: 
  293:     # Print the sorted resources
  294:     foreach my $filename (@sorted_files) {
  295:         if ($filehash->{$filename}->{"cmode"}&$dirptr) {        # Directories
  296:             &putdirectory($r, $thisdisfn, $linkdir, $filename, 
  297:                 $filehash->{$filename}->{"cmtime"}, 
  298:                 $targetdir, \%bombs, \$numdir);
  299:         } else {                                                # Files
  300:             &putresource($r, $udom, $uname, $filename, $thisdisfn, $resdir,
  301:                 $targetdir, $linkdir, $filehash->{$filename}->{"cmtime"}, 
  302:                 $filehash->{$filename}->{"size"}, \$numres, 
  303:                 $filehash->{$filename}->{"linkfilename"},
  304:                 $filehash->{$filename}->{"fulltitle"},
  305:                 $filehash->{$filename}->{"status"},
  306:                 $filehash->{$filename}->{"pubstatus"});
  307:         }
  308:     }
  309: 
  310:   $r->print(&Apache::loncommon::end_data_table()
  311:            .'</div><div id="otherplaces" style="display:none">'
  312:            .&Apache::loncommon::start_data_table()
  313:            .'<th colspan=7>'.&mt('Results in other directories:').'</th>'
  314:            .'<tr class="LC_header_row" id="otherplacestable">'
  315:            .'<th>'.&mt('Type').'</th>'
  316:            .'<th>'.&mt('Directory').'</th>'
  317:            .'<th>'.&mt('Name').'</th>'
  318:            .'<th>'.&mt('Title').'</th>'
  319:            .'<th colspan="2">'.&mt('Status').'</th>'
  320:            .'<th>'.&mt('Last Modified').'</th>'
  321:            .'</tr>'
  322:            .'</div>'
  323:            .&Apache::loncommon::end_page()
  324:   );
  325:   return OK;  
  326: }
  327: 
  328: 
  329: 
  330: #   Output the header of the page.  This includes:
  331: #   - The HTML header 
  332: #   - The H1/H3  stuff which includes the directory.
  333: #
  334: #     startpage($r, $uame, $udom, $thisdisfn);
  335: #      $r     - The apache request object.
  336: #      $uname - User name.
  337: #      $udom  - Domain name the user is logged in under.
  338: #      $thisdisfn - Displayable version of the filename.
  339: 
  340: sub startpage {
  341:     my ($r, $uname, $udom, $thisdisfn) = @_;
  342:     &Apache::loncommon::content_type($r,'text/html');
  343:     $r->send_http_header;
  344: 
  345:     my $formaction='/priv'.$thisdisfn.'/';
  346:     $formaction=~s|/+|/|g;
  347:     &Apache::lonhtmlcommon::store_recent('construct',$formaction,$formaction);
  348: 
  349:     &Apache::lonhtmlcommon::clear_breadcrumbs();
  350:     &Apache::lonhtmlcommon::add_breadcrumb({
  351:         'text'  => 'Authoring Space',
  352:         'href'  => &Apache::loncommon::authorspace($formaction),
  353:     });
  354:     # breadcrumbs (and tools) will be created 
  355:     # in start_page->bodytag->innerregister
  356: 
  357:     $env{'request.noversionuri'}=$formaction;
  358:     $r->print(&Apache::loncommon::start_page('Authoring Space'));
  359: 
  360:     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
  361:     my $current_disk_usage = &Apache::lonnet::diskusage($udom,$uname,"$londocroot/priv/$udom/$uname");
  362:     my $disk_quota = &Apache::loncommon::get_user_quota($uname,$udom,'author'); #expressed in MB
  363:     $disk_quota = 1000 * $disk_quota; # convert from MB to kB
  364: 
  365:     $r->print(&Apache::loncommon::head_subbox(
  366:                      '<div style="float:right;padding-top:0;margin-top;0">'
  367:                     .&Apache::lonhtmlcommon::display_usage($current_disk_usage,$disk_quota)
  368:                     .'</div>'
  369:                     .&Apache::loncommon::CSTR_pageheader()));
  370: 
  371:     my $esc_thisdisfn = &Apache::loncommon::escape_single($thisdisfn);
  372:     my $doctitle = 'LON-CAPA '.&mt('Authoring Space');
  373:     my $newname = &mt('New Name');
  374:     my $pubdirscript=(<<ENDPUBDIRSCRIPT);
  375: <script type="text/javascript">
  376: top.document.title = '$esc_thisdisfn/ - $doctitle';
  377: // Store directory location for menu bar to find
  378: 
  379: parent.lastknownpriv='/priv$esc_thisdisfn/';
  380: 
  381: // Confirmation dialogues
  382: 
  383:     function currdiract(theform) {
  384:         if (theform.dirtask.options[theform.dirtask.selectedIndex].value == 'publish') {
  385:             document.publishdir.filename.value = theform.filename.value;
  386: 	    document.publishdir.submit();
  387:         }
  388:         if (theform.dirtask.options[theform.dirtask.selectedIndex].value == 'editmeta') {
  389:             top.location=theform.filename.value+'default.meta'
  390:         }
  391:         if (theform.dirtask.options[theform.dirtask.selectedIndex].value == 'printdir' ) {
  392:             document.printdir.postdata.value=theform.filename.value
  393:             document.printdir.submit();
  394:         }
  395:         if (theform.dirtask.options[theform.dirtask.selectedIndex].value == "delete") {
  396:               var delform = document.delresource
  397:               delform.filename.value = theform.filename.value
  398:               delform.submit()
  399:         }
  400:     }
  401:   
  402:     function checkUpload(theform) {
  403:         if (theform.file == '') {
  404:             alert("Please use 'Browse..' to choose a file first, before uploading")
  405:             return 
  406:         }
  407:         theform.submit()  
  408:     }
  409: 
  410:     function SetPubDir(theform,printForm) {
  411:         if (theform.diraction.options[theform.diraction.selectedIndex].value == "open") {
  412:             top.location = theform.openname.value
  413:             return
  414:         }
  415:         if (theform.diraction.options[theform.diraction.selectedIndex].value == "publish") {
  416:             theform.submit();
  417:         }
  418:         if (theform.diraction.options[theform.diraction.selectedIndex].value == "editmeta") {
  419:             top.location=theform.filename.value+'default.meta'
  420:         }
  421:         if (theform.diraction.options[theform.diraction.selectedIndex].value == "printdir") {
  422:             theform.action = '/adm/printout'
  423:             theform.postdata.value = theform.filename.value
  424:             theform.submit()
  425:         }
  426:         if (theform.diraction.options[theform.diraction.selectedIndex].value == "delete") {
  427:               var delform = document.delresource
  428:               delform.filename.value = theform.filename.value
  429:               delform.submit()
  430:         }
  431:         return
  432:     }
  433:     function SetResChoice(theform) {
  434:       var activity = theform.reschoice.options[theform.reschoice.selectedIndex].value
  435:       if ((activity == 'rename') || (activity == 'copy') || (activity == 'move')) {
  436:           changename(theform,activity)
  437:       }
  438:       if (activity == 'publish') {
  439:           var pubform = document.pubresource
  440:           pubform.filename.value = theform.filename.value
  441:           pubform.submit()
  442:       }
  443:       if (activity == 'delete') {
  444:           var delform = document.delresource
  445:           delform.filename.value = theform.filename.value
  446:           delform.submit()
  447:       }
  448:       if (activity == 'obsolete') {
  449:           var pubform = document.pubresource
  450:           pubform.filename.value = theform.filename.value
  451:           pubform.makeobsolete.value=1;
  452:           pubform.submit()
  453:       }
  454:       if (activity == 'print') {
  455:           document.printresource.postdata.value = theform.filename.value
  456:           document.printresource.submit()
  457:       }
  458:       if (activity == 'retrieve') {
  459:           document.retrieveres.filename.value = theform.filename.value
  460:           document.retrieveres.submit()
  461:       }
  462:       if (activity == 'cleanup') {
  463:           document.cleanup.filename.value = theform.filename.value
  464:           document.cleanup.submit()
  465:       }
  466:       return
  467:     }
  468:     function changename(theform,activity) {
  469:         var oldname=theform.dispfilename.value;
  470:         var newname=prompt('$newname',oldname);
  471:         if (newname == "" || !newname || newname == oldname)  {
  472:             return
  473:         }
  474:         document.moveresource.newfilename.value = newname
  475:         document.moveresource.filename.value = theform.filename.value
  476:         document.moveresource.action.value = activity
  477:         document.moveresource.submit();
  478:     }
  479: </script>
  480: ENDPUBDIRSCRIPT
  481:     $r->print($pubdirscript);
  482: }
  483: 
  484: sub dircontrols {
  485:     my ($r,$uname,$udom,$thisdisfn) = @_;
  486:     my %lt=&Apache::lonlocal::texthash(
  487:                                        cnpd => 'Cannot publish directory',
  488:                                        cnrd => 'Cannot retrieve directory',
  489:                                        mcdi => 'Must create new subdirectory inside a directory',
  490:                                        pubr => 'Publish this Resource',
  491:                                        pubd => 'Publish this Directory',
  492:                                        dedr => 'Delete Directory',
  493:                                        rtrv => 'Retrieve Old Version',
  494:                                        list => 'List Directory',
  495:                                        uplo => 'Upload file',  
  496:                                        dele => 'Delete',
  497:                                        edit => 'Edit Metadata', 
  498:                                        sela => 'Select Action',
  499:                                        nfil => 'New file',
  500:                                        nhtm => 'New HTML file',
  501:                                        nprb => 'New problem',
  502:                                        npag => 'New assembled page',
  503:                                        nseq => 'New assembled sequence',
  504:                                        ncrf => 'New custom rights file',
  505:                                        nsty => 'New style file',
  506:                                        nlib => 'New library file',
  507:                                        nbt  => 'New bridgetask file',
  508:                                        nsub => 'New subdirectory',
  509:                                        renm => 'Rename current file to',
  510:                                        move => 'Move current file to',
  511:                                        copy => 'Copy current file to',
  512:                                        type => 'Type Name Here',
  513:                                        go   => 'Go',
  514:                                        prnt => 'Print contents of directory',
  515:                                        crea => 'Create a new directory or LON-CAPA document',
  516:                                        qs   => 'Quick Search',
  517:                                        cs   => 'Case Sensitive',
  518:                                        re   => 'Regular Expression',
  519: 				       acti => 'Actions for current directory',
  520: 				       updc => 'Upload a new document',
  521: 				       pick => 'Please select an action to perform using the new filename',
  522:                                       );
  523:     my $mytype = $lt{'type'}; # avoid conflict with " and ' in javascript
  524:     $r->printf(<<END,&Apache::loncommon::help_open_topic('Quicksearch'));
  525: <div class="LC_columnSection">
  526:   <div>
  527:     <form name="curractions" method="post" action="">
  528:       <fieldset>
  529:         <legend>$lt{'acti'}</legend>
  530:         <select name="dirtask" onchange="currdiract(this.form)">
  531:             <option>$lt{'sela'}</option>
  532:             <option value="publish">$lt{'pubd'}</option>
  533:             <option value="editmeta">$lt{'edit'}</option>
  534:             <option value="printdir">$lt{'prnt'}</option>
  535:             <option value="delete">$lt{'dedr'}</option>
  536:         </select>
  537:         <input type="hidden" name="filename" value="/priv$thisdisfn/" />
  538:       </fieldset>
  539:     </form>
  540:     <form name="publishdir" method="post" action="/adm/publish" target="_parent">
  541:       <input type="hidden" name="pubrec" value="" />
  542:       <input type="hidden" name="filename" value="" />
  543:     </form>
  544:     <form name="printdir" method="post" action="/adm/printout" target="_parent">
  545:       <input type="hidden" name="postdata" value="" />
  546:     </form>
  547:   </div>
  548: 
  549:   <div>
  550:     <form name="upublisher" enctype="multipart/form-data" method="post" action="/adm/upload" target="_parent">
  551:       <fieldset>
  552:         <legend>$lt{'updc'}</legend>
  553:         <input type="hidden" name="filename" value="/priv$thisdisfn/" />
  554:         <input type="file" name="upfile" size="20" />
  555:         <input type="button" value="$lt{'uplo'}"  onclick="checkUpload(this.form)" />
  556:       </fieldset>
  557:     </form>
  558:   </div>
  559: 
  560:   <div>
  561:     <form name="fileaction" method="post" action="/adm/cfile" target="_parent">
  562:       <fieldset>
  563:               <legend>$lt{'crea'}</legend>
  564: 	      <span class="LC_nobreak">
  565: 		<input type="hidden" name="filename" value="/priv$thisdisfn/" />
  566:                   <script type="text/javascript">
  567:                     function validate_go() {
  568:                         var selected = document.fileaction.action.selectedIndex;
  569:                         if (selected == 0) {
  570:                             alert('$lt{'pick'}');
  571:                         } else {
  572:                             document.fileaction.submit();
  573:                         }
  574:                     }
  575:                   </script>
  576: 		  <select name="action">
  577: 		    <option value="none">$lt{'sela'}</option>
  578: 		    <option value="newfile">$lt{'nfil'}:</option>
  579: 		    <option value="newhtmlfile">$lt{'nhtm'}:</option>
  580: 		    <option value="newproblemfile">$lt{'nprb'}:</option>
  581:                     <option value="newpagefile">$lt{'npag'}:</option>
  582:                     <option value="newsequencefile">$lt{'nseq'}:</option>
  583:                     <option value="newrightsfile">$lt{'ncrf'}:</option>
  584:                     <option value="newstyfile">$lt{'nsty'}:</option>
  585:                     <option value="newtaskfile">$lt{'nbt'}:</option>
  586:                     <option value="newlibraryfile">$lt{'nlib'}:</option>
  587: 	            <option value="newdir">$lt{'nsub'}:</option>
  588: 		  </select>&nbsp;<input type="text" name="newfilename" value="$lt{'type'}" onfocus="if (this.value == '$mytype') this.value=''" />&nbsp;<input type="button" value="Go" onclick="validate_go();" />
  589: 		 </span>
  590:       </fieldset>
  591:     </form>
  592:     </div>
  593:     <div>
  594:         <form>
  595:           <fieldset style="display:inline">
  596:                 <legend>$lt{'qs'}</legend>
  597:                     <script src="/adm/quicksearch/quicksearch.js"></script>
  598:                     <input type="text" id="quickfilter" placeholder="Enter search term" onkeyup="applyFilter()"/>
  599:                     <input type="button" value="Clear" onclick="document.getElementById(\'quickfilter\').value=\'\'; applyFilter()" />
  600:                     %s
  601:                     <br />
  602:                     <label><input type="checkbox" id="casesens" onchange="applyFilter()"/>$lt{'cs'}&nbsp;&nbsp;</label>
  603:                     <label><input type="checkbox" id="regex" onchange="applyFilter()"/>$lt{'re'}&nbsp;&nbsp;</label>
  604:             </fieldset>
  605:         </form>
  606:   </div>
  607: </div>
  608: END
  609: }
  610: 
  611: sub resourceactions {
  612:     my ($r,$uname,$udom,$thisdisfn) = @_;
  613:     $r->print(<<END);
  614:        <form name="moveresource" action="/adm/cfile" target="_parent" method="post">
  615:          <input type="hidden" name="filename" value="" />
  616:          <input type="hidden" name="newfilename" value="" />
  617:          <input type="hidden" name="action" value="" />
  618:        </form>
  619:        <form name="delresource" action="/adm/cfile" target="_parent" method="post">
  620:          <input type="hidden" name="filename" value="" />
  621:          <input type="hidden" name="action" value="delete" />
  622:        </form>
  623:        <form name="pubresource" action="/adm/publish" target="_parent" method="post">
  624:          <input type="hidden" name="filename" value="" />
  625:          <input type="hidden" name="makeobsolete" value="0" />
  626:        </form>
  627:        <form name="printresource" action="/adm/printout" target="_parent" method="post">
  628:            <input type="hidden" name="postdata" value="" />
  629:        </form>
  630:        <form name="retrieveres" action="/adm/retrieve" target="_parent" method="post">
  631:            <input type="hidden" name="filename" value="" />
  632:        </form>
  633:        <form name="cleanup" action="/adm/cleanup" target="_parent" method="post">
  634:            <input type="hidden" name="filename" value="" />
  635:        </form>
  636: END
  637: }
  638: 
  639: #
  640: #   Get the title string or "[untitled]" if the file has no title metadata:
  641: #   Without the latter substitution, it's impossible to examine metadata for
  642: #   untitled resources.  Resources may be legitimately untitled, to prevent
  643: #   searches from locating them.
  644: #
  645: #   $str = getTitleString($fullname);
  646: #       $fullname - Fully qualified filename to check.
  647: #
  648: sub getTitleString {
  649:     my $fullname = shift;
  650:     my $title    = &Apache::lonnet::metadata($fullname, 'title');
  651: 
  652:     unless ($title) {
  653: 	$title = "[".&mt('untitled')."]";
  654:     }
  655:     return $title;
  656: }
  657: 
  658: sub getCopyRightString {
  659:     my $fullname = shift;
  660:     return &Apache::lonnet::metadata($fullname, 'copyright');
  661: }
  662: 
  663: sub getSourceRightString {
  664:     my $fullname = shift;
  665:     return &Apache::lonnet::metadata($fullname, 'sourceavail');
  666: }
  667: #
  668: #  Put out a directory table row:
  669: #    putdirectory(r, base, here, dirname, modtime, targetdir, bombs, numdir)
  670: #      r         - Apache request object.
  671: #      reqfile   - File in request.
  672: #      here      - Where we are in directory tree.
  673: #      dirname   - Name of directory special file.
  674: #      modtime   - Encoded modification time.
  675: #      targetdir - Publication target directory.
  676: #      bombs     - Reference to hash of URLs with runtime error messages.
  677: #      numdir    - Reference to scalar used to track number of sub-directories
  678: #                  in directory (used in form name for each "actions" dropdown).
  679: #
  680: sub putdirectory {
  681:     my ($r, $reqfile, $here, $dirname, $modtime, $targetdir, $bombs, $numdir) = @_;
  682: 
  683: # construct the display filename: the directory name unless ..:
  684:    
  685:     my $actionitem;
  686:  
  687:     my $disfilename = $dirname;
  688: # Don't display directory itself, and there is no way up from root directory
  689:     unless ((($dirname eq '..') && ($reqfile=~/^\/[^\/]+\/[^\/]+$/)) || ($dirname eq '.')) {
  690:         my $kaputt=0;
  691:         if (ref($bombs) eq 'HASH') {
  692:             foreach my $key (keys(%{$bombs})) {
  693:                 my $currentdir = &Apache::lonnet::declutter("$targetdir/$disfilename");
  694:                 if (($key) =~ m{^\Q$currentdir\E/}) { $kaputt=1; last; }
  695:             }
  696:         }
  697: #
  698: # Get the metadata from that directory's default.meta to display titles
  699: #
  700: 	%Apache::lonpublisher::metadatafields=();
  701: 	%Apache::lonpublisher::metadatakeys=();
  702: 	&Apache::lonpublisher::metaeval(
  703:                  &Apache::lonnet::getfile($r->dir_config('lonDocRoot').$here.'/'.$dirname.'/default.meta')
  704:                                        );
  705:         if ($dirname eq '..') {
  706:             $actionitem = &mt('Go to ...');
  707:             $disfilename = '<i>'.&mt('Parent Directory').'</i>';
  708:         } else {
  709:             $actionitem = 
  710:                     '<form name="dirselect_'.$$numdir.
  711:                     '" action="/adm/publish" target="_parent">'.
  712:                     '<select name="diraction" onchange="SetPubDir(this.form,document)">'.
  713:                       '<option selected="selected">'.&mt('Select action').'</option>'.
  714:                       '<option value="open">'.&mt('Open').'</option>'.
  715:                       '<option value="publish">'.&mt('Publish').'</option>'.
  716:                       '<option value="editmeta">'.&mt('Edit Metadata').'</option>'.
  717:                       '<option value="printdir">'.&mt('Print directory').'</option>'.
  718:                       '<option value="delete">'.&mt('Delete directory').'</option>'.
  719:                     '</select>'.
  720:                      '<input type="hidden" name="filename" value="'.&HTML::Entities::encode($here.'/'.$dirname,'<>&"').'/" />'.
  721:                      '<input type="hidden" name="openname" value="'.$here.'/'.$dirname.'/" />'.
  722:                      '<input type="hidden" name="postdata" value="" />'.
  723:                    '</form>';
  724:             $$numdir ++;
  725:         }
  726: 	$r->print('<tr class="LC_browser_folder">'.
  727: 		  '<td><img src="'.
  728: 		  $Apache::lonnet::perlvar{'lonIconsURL'}.'/navmap.folder.closed.gif" alt="folder" /></td>'.
  729: 		  '<td>'.$actionitem.'</td>'.
  730: 		  '<td><span class="LC_filename"><a href="'.&HTML::Entities::encode($here.'/'.$dirname,'<>&"').'/" target="_parent">'.
  731: 		  $disfilename.'</a></span></td>'.
  732: 		        '<td colspan="3">'.($kaputt?&Apache::lonhtmlcommon::authorbombs($targetdir.'/'.$disfilename.'/'):'').$Apache::lonpublisher::metadatafields{'title'});
  733: 	if ($Apache::lonpublisher::metadatafields{'subject'} ne '') {
  734: 	    $r->print(' <i>'.
  735: 		      $Apache::lonpublisher::metadatafields{'subject'}.
  736: 		      '</i> ');
  737: 	}
  738: 	$r->print($Apache::lonpublisher::metadatafields{'keywords'}.'</td>'.
  739: 		  '<td>'.&Apache::lonlocal::locallocaltime($modtime).'</td>'.
  740: 	          '<td></td>'.
  741: 		  "</tr>\n");
  742:     }
  743:     return;
  744: }
  745: 
  746: sub getTitle {
  747:     my ($resdir, $targetdir, $filename, $linkfilename, $meta_same, $bombs) = @_;
  748:     my $title='';
  749:     my $titleString = &getTitleString($targetdir.'/'.$filename);
  750:     if (-e $resdir.'/'.$filename) {
  751: 	$title = '<a href="'.$targetdir.'/'.$filename.
  752: 	    '.meta" target="cat">'.$titleString.'</a>';
  753:         if (!$meta_same) {
  754: 	    $title = &mt('Metadata Modified').'<br />'.$title.
  755: 		'<br />'.
  756:                 &Apache::loncommon::modal_link(
  757:                     '/adm/diff?filename='.$linkfilename.'.meta'.'&amp;versiontwo=priv',
  758:                     &mt('Metadata Diffs'),600,500);
  759: 	    $title.="\n".'<br />'.
  760:                 &Apache::loncommon::modal_link(
  761:                     '/adm/retrieve?filename='.$linkfilename.'.meta&amp;inhibitmenu=yes&amp;add_modal=yes',
  762:                     &mt('Retrieve Metadata'),600,500);
  763:         } 
  764:     }
  765:     # Allow editing metadata of published and unpublished resources
  766:     $title .= "\n".'<br />' if ($title);
  767:     $title .= '<a href="'.$linkfilename.'.meta">'.
  768:               ($$bombs{&Apache::lonnet::declutter($targetdir.'/'.$filename)}?
  769:                   '<img src="/adm/lonMisc/bomb.gif" border="0" alt="'.&mt('bomb').'" />':
  770:                   &mt('Edit Metadata')).
  771:               '</a>';
  772: 
  773:     return ($title, $titleString);
  774: }
  775: 
  776: 
  777: sub isMetaSame {
  778:     my ($cstr_dir, $resdir, $filename) = @_;
  779:     my $meta_cmtime = (stat($cstr_dir.'/'.$filename.'.meta'))[9];
  780:     my $meta_rmtime = (stat($resdir.'/'.$filename.'.meta'))[9];
  781:     return (&Apache::londiff::are_different_files($resdir.'/'.$filename.'.meta',
  782:             $cstr_dir.'/'.$filename.'.meta') && $meta_rmtime < $meta_cmtime) 
  783:         ? 0 : 1;
  784: }
  785:     
  786: 
  787: sub getStatus {    
  788:     my ($resdir, $targetdir, $cstr_dir, $filename,  
  789:             $linkfilename, $cmtime, $meta_same) = @_;
  790:     my $pubstatus = 'unpublished';
  791:     my $status = &mt('Unpublished');
  792: 
  793:     if (-e $resdir.'/'.$filename) {
  794:         my $same = 0;
  795:         if ((stat($resdir.'/'.$filename))[9] >= $cmtime) {
  796:             $same = 1;
  797:         } else {
  798:            if (&Apache::londiff::are_different_files($resdir.'/'.$filename,
  799: 						     $cstr_dir.'/'.$filename)) {
  800:               $same = 0;
  801:            } else {
  802:               $same = 1;
  803:            }
  804:         }
  805: 
  806:         my $rights_status =
  807:             &mt(&getCopyRightString($targetdir.'/'.$filename)).', ';
  808: 
  809:         my %lt_SourceRight = &Apache::lonlocal::texthash(
  810:                'open'   => 'Source: open',
  811:                'closed' => 'Source: closed',
  812:         );
  813:         $rights_status .=
  814:             $lt_SourceRight{&getSourceRightString($targetdir.'/'.$filename)};
  815: 
  816: 	if ($same) {
  817: 	    if (&Apache::lonnet::metadata($targetdir.'/'.$filename,'obsolete')) {
  818:                 $pubstatus = 'obsolete';
  819: 		$status=&mt('Obsolete');
  820:             } else {
  821: 		if (!$meta_same) {
  822: 		    $pubstatus = 'metamodified';
  823: 		} else {
  824: 		    $pubstatus = 'published';
  825: 		}
  826: 		$status=&mt('Published').
  827: 		    '<br />'. $rights_status;
  828: 	    }
  829: 	} else {
  830:             $pubstatus = 'modified';
  831: 	    $status=&mt('Modified').
  832: 		'<br />'. $rights_status;
  833: 	    if (&Apache::loncommon::fileembstyle(($filename=~/\.(\w+)$/)) eq 'ssi') {
  834: 		$status.='<br />'.
  835:                          &Apache::loncommon::modal_link(
  836:                              '/adm/diff?filename='.$linkfilename.'&amp;versiontwo=priv',
  837:                              &mt('Diffs'),600,500);
  838: 	    }
  839: 	} 
  840: 
  841: 	$status.="\n".'<br />'.
  842:              &Apache::loncommon::modal_link(
  843:                  '/adm/retrieve?filename='.$linkfilename.'&amp;inhibitmenu=yes&amp;add_modal=yes',&mt('Retrieve'),600,500);
  844:     }
  845: 
  846:     return ($status, $pubstatus);
  847: }
  848: 
  849: 
  850: #
  851: #   Put a table row for a file resource.
  852: #
  853: sub putresource {
  854:     my ($r, $udom, $uname, $filename, $thisdisfn, $resdir, $targetdir, 
  855:             $linkdir, $cmtime, $size, $numres, $linkfilename, $title, 
  856:             $status, $pubstatus) = @_;
  857:     &Apache::lonnet::devalidate_cache_new('meta',$targetdir.'/'.$filename);
  858: 
  859:     my $editlink='';
  860:     my $editlink2='';
  861:     if ($filename=~/\.(xml|html|htm|xhtml|xhtm|sty)$/) {
  862: 	$editlink=' <br />(<a href="'.$linkdir.'/'.$filename.'?editmode=Edit&amp;problemmode=edit">'.&mt('Edit').'</a>)';
  863:     }
  864:     if ($filename=~/$LONCAPA::assess_re/) {
  865: 	$editlink=' (<a href="'.$linkdir.'/'.$filename.'?editmode=Edit&amp;problemmode=editxml">'.&mt('EditXML').'</a>)';
  866: 	$editlink2=' <br />(<a href="'.$linkdir.'/'.$filename.'?editmode=Edit&amp;problemmode=edit">'.&mt('Edit').'</a>)';
  867:     }
  868:     if ($filename=~/\.(problem|exam|quiz|assess|survey|form|library|xml|html|htm|xhtml|xhtm|sty)$/) {
  869: 	$editlink.=' (<a href="/adm/cleanup?filename='.$linkfilename.'" target="_parent">'.&mt('Clean Up').')</a>';
  870:     }
  871:     if ($filename=~/\.(zip|tar|bz2|gz|tar.gz|tar.bz2|tgz)$/) {
  872: 	$editlink=' (<a target="_parent" href="/adm/cfile?decompress='.$linkfilename.'">'.&mt('Decompress').'</a>)';
  873:     }
  874:     my $publish_button = (-e $resdir.'/'.$filename) ? &mt('Re-publish') : &mt('Publish');
  875:     my $pub_select = '';
  876:     &create_pubselect($r,\$pub_select,$udom,$uname,$thisdisfn,$filename,$resdir,$pubstatus,$publish_button,$numres);
  877:     $r->print(&Apache::loncommon::start_data_table_row().
  878: 	      '<td>'.($filename=~/[\#\~]$/?'&nbsp;':
  879: 		      '<img src="'.&Apache::loncommon::icon($filename).'" alt="" />').'</td>'.
  880:               '<td>'.$pub_select.'</td>'.
  881: 	      '<td><span class="LC_filename">'.
  882: 	      '<a href="'.$linkdir.'/'.$filename.'" target="_parent">'.
  883:                $filename.'</a></span>'.$editlink2.$editlink.
  884: 	      '</td>'.
  885: 	      '<td>'.$title.'</td>'.
  886:               '<td class="LC_browser_file_'.$pubstatus.'">&nbsp;&nbsp;</td>'. # Display publication status
  887:               '<td>'.$status.'</td>'.
  888: 	      '<td>'.&Apache::lonlocal::locallocaltime($cmtime).'</td>'.
  889: 	      '<td>'.sprintf("%.1f",$size).'</td>'.
  890: 	      &Apache::loncommon::end_data_table_row()
  891:     );
  892:     return;
  893: }
  894: 
  895: sub create_pubselect {
  896:     my ($r,$pub_select,$udom,$uname,$thisdisfn,$filename,$resdir,$pubstatus,$publish_button,$numres) = @_;
  897:     $$pub_select = '
  898: <form name="resselect_'.$$numres.'" action="">
  899: <select name="reschoice"  onchange="SetResChoice(this.form)">
  900: <option>'.&mt('Select action').'</option>'.
  901: '<option value="copy">'.&mt('Copy').'</option>';
  902:     if ($pubstatus eq 'obsolete' || $pubstatus eq 'unpublished') {
  903:         $$pub_select .= 
  904: '<option value="rename">'.&mt('Rename').'</option>'.
  905: '<option value="move">'.&mt('Move').'</option>'.
  906: '<option value="delete">'.&mt('Delete').'</option>';
  907:     } else {
  908:         $$pub_select .= '
  909: <option value="obsolete">'.&mt('Mark obsolete').'</option>';
  910:     }
  911: # check for versions
  912:     my $versions = &check_for_versions($r,'/'.$filename,$udom,$uname);
  913:     if ($versions > 0) {
  914:         $$pub_select .='
  915: <option value="retrieve">'.&mt('Retrieve old version').'</option>';
  916:     }
  917:     $$pub_select .= '
  918: <option value="publish">'.$publish_button.'</option>'.
  919: '<option value="cleanup">'.&mt('Clean up').'</option>'.
  920: '<option value="print">'.&mt('Print').'</option>'.
  921: '</select>
  922: <input type="hidden" name="filename" value="/priv'.
  923:  &HTML::Entities::encode($thisdisfn.'/'.$filename,'<>&"').'" />
  924:  <input type="hidden" name="dispfilename" value="'.
  925:  &HTML::Entities::encode($filename).'" /></form>';
  926:     $$numres ++;
  927: }
  928: 
  929: sub check_for_versions {
  930:     my ($r,$fn,$udom,$uname) = @_;
  931:     my $versions = 0;
  932:     my $docroot=$r->dir_config('lonDocRoot');
  933:     my $resfn=$docroot.'/res/'.$udom.'/'.$uname.$fn;
  934:     my $resdir=$resfn;
  935:     $resdir=~s/\/[^\/]+$/\//;
  936:     $fn=~/\/([^\/]+)\.(\w+)$/;
  937:     my $main=$1;
  938:     my $suffix=$2;
  939:     opendir(DIR,$resdir);
  940:     while (my $filename=readdir(DIR)) {
  941:         if ($filename=~/^\Q$main\E\.(\d+)\.\Q$suffix\E$/) {
  942:             $versions ++;        
  943:         }
  944:     }
  945:     closedir(DIR);
  946:     return $versions;
  947: }
  948: 
  949: sub prepareJsonTranslations {
  950:     my $json = 
  951:         '{"translations":{'.
  952:             '"edit":"'.&mt('Edit').'",'.
  953:             '"editxml":"'.&mt('EditXML').'",'.
  954:             '"editmeta":"'.&mt('Edit Metadata').'",'.
  955:             '"obsolete":"'.&mt('Obsolete').'",'.
  956:             '"modified":"'.&mt('Modified').'",'.
  957:             '"published":"'.&mt('Published').'",'.
  958:             '"unpublished":"'.&mt('Unpublished').'",'.
  959:             '"diff":"'.&mt('Diff').'",'.
  960:             '"retrieve":"'.&mt('Retrieve').'",'.
  961:             '"directory":"'.&mt('Directory').'",'.
  962:             '"results":"'.&mt('Show results for keyword:').'"'.
  963:         '}}';
  964: }
  965: 
  966: # gathers all files in the working directory except the ones that are already on screen
  967: sub prepareJsonData {
  968:     my ($uname, $udom, $pathToSkip) = @_;
  969:     my $path = "/home/httpd/html/priv/$udom/$uname/";
  970: 
  971:     # maximum number of entries, to limit workload and required storage space
  972:     my $entries = 100;
  973:     my $firstfile = 1;
  974:     my $firstdir = 1;
  975: 
  976:     my $json = '{"resources":[';
  977:     $json .= &prepareJsonData_rec($path, \$entries, \$firstfile, \$firstdir, $pathToSkip);
  978:     $json .= ']}';
  979: 
  980:     # if the json string is invalid the whole search breaks.
  981:     # so we want to make sure that the string is valid in any case.
  982:     $json =~ s/,\s*,/,/g;
  983:     $json =~ s/\}\s*\{/\},\{/g;
  984:     $json =~ s/\}\s*,\s*\]/\}\]/g;
  985:     return $json;
  986: }
  987: 
  988: # recursive part of json file gathering
  989: sub prepareJsonData_rec {
  990:     my ($path, $entries, $firstfile, $firstdir, $pathToSkip) = @_;
  991:     my $json;
  992:     my $skipThisFolder = $path =~ m/$pathToSkip\/$/?1:0;
  993: 
  994:     my @dirs;
  995:     my @resources;
  996:     my @ignored = qw(bak log meta save . ..);
  997: 
  998: # Phase 1: Gathering
  999:     opendir(DIR,$path);
 1000:     my @files=sort {uc($a) cmp uc($b)} (readdir(DIR));
 1001:     foreach my $filename (@files) {
 1002:         next if ($filename eq '.DS_Store');
 1003: 
 1004:         # gather all resources
 1005:         if ($filename !~ /\./) {
 1006:             # its a folder
 1007:             push(@dirs, $filename);
 1008:         } else {
 1009:             # only push files we dont want to ignore
 1010:             next if ($skipThisFolder);
 1011: 
 1012:             $filename =~ /\.(\w+?)$/;
 1013:             unless (grep /$1/, @ignored) {
 1014:                 push(@resources, $filename);
 1015:             }
 1016:         }
 1017:     }
 1018:     closedir(DIR);
 1019:     # nothing to do here if both lists are empty
 1020:     return unless ( @dirs || @resources );
 1021:     
 1022: # Phase 2: Working
 1023:     $$firstfile = 1;
 1024: 
 1025:     foreach (@dirs) {
 1026:         $json .= '{"name":"'.$_.'",'.
 1027:                   '"path":"'.$path.$_.'",'.
 1028:                   '"title":"",'.
 1029:                   '"status":"",'.
 1030:                   '"cmtime":""},';
 1031:     }
 1032: 
 1033:     foreach (@resources) {
 1034:         last if ($$entries < 1);
 1035:         my $title = &getTitleString($path.$_);
 1036: 
 1037:         my $privpath = $path.$_;
 1038:         my $respath = $privpath;
 1039:         $respath =~ s/httpd\/html\/priv\//httpd\/html\/res\//;
 1040: 
 1041:         my $cmtime = (stat($privpath))[9];
 1042:         my $rmtime = (stat($respath))[9];
 1043: 
 1044:         unless ($$firstfile) { $json .= ','; } else { $$firstfile = 0; }
 1045: 
 1046:         my $status = 'unpublished';
 1047: 
 1048:         # if a resource is published, the published version (/html/res/filepath) gets its own modification time
 1049:         # this is newer or equal then the version in your authoring space (/html/priv/filepath)
 1050:         if ($rmtime >= $cmtime) {
 1051:             # obsolete
 1052:             if (&Apache::lonnet::metadata($respath, 'obsolete')) {
 1053:                 $status = 'obsolete';
 1054:             }else{
 1055:                 $status = 'published';
 1056:             }
 1057:         } else {
 1058:             $status = 'modified';
 1059:         }
 1060: 
 1061:         $json .= '{"name":"'.$_.'",'.
 1062:                   '"path":"'.$path.'",'.
 1063:                   '"title":"'.$title.'",'.
 1064:                   '"status":"'.$status.'",'.
 1065:                   '"cmtime":"'.&Apache::lonlocal::locallocaltime($cmtime).'"}';
 1066:         $$entries--;
 1067:     }
 1068: 
 1069:     foreach(@dirs) {
 1070:         next if ($$entries < 1);
 1071:         $json .= ',';
 1072:         $json .= &prepareJsonData_rec
 1073:                     ($path.$_.'/', $entries, $firstfile, $firstdir, $pathToSkip);
 1074:     }
 1075:     return $json;
 1076: }
 1077: 1;
 1078: __END__
 1079: 
 1080: 
 1081: =head1 NAME
 1082: 
 1083: Apache::lonpubdir - Authoring space directory lister
 1084: 
 1085: =head1 SYNOPSIS
 1086: 
 1087: Invoked (for various locations) by /etc/httpd/conf/srm.conf:
 1088: 
 1089:  <LocationMatch "^/+priv.*/$">
 1090:  PerlAccessHandler       Apache::loncacc
 1091:  SetHandler perl-script
 1092:  PerlHandler Apache::lonpubdir
 1093:  ErrorDocument     403 /adm/login
 1094:  ErrorDocument     404 /adm/notfound.html
 1095:  ErrorDocument     406 /adm/unauthorized.html
 1096:  ErrorDocument	  500 /adm/errorhandler
 1097:  </LocationMatch>
 1098: 
 1099:  <Location /adm/pubdir>
 1100:  PerlAccessHandler       Apache::lonacc
 1101:  SetHandler perl-script
 1102:  PerlHandler Apache::lonpubdir
 1103:  ErrorDocument     403 /adm/login
 1104:  ErrorDocument     404 /adm/notfound.html
 1105:  ErrorDocument     406 /adm/unauthorized.html
 1106:  ErrorDocument	  500 /adm/errorhandler
 1107:  </Location>
 1108: 
 1109: =head1 INTRODUCTION
 1110: 
 1111: This module publishes a directory of files.
 1112: 
 1113: This is part of the LearningOnline Network with CAPA project
 1114: described at http://www.lon-capa.org.
 1115: 
 1116: =head1 HANDLER SUBROUTINE
 1117: 
 1118: This routine is called by Apache and mod_perl.
 1119: 
 1120: =over 4
 1121: 
 1122: =item *
 1123: 
 1124: read in information
 1125: 
 1126: =item *
 1127: 
 1128: start page output
 1129: 
 1130: =item *
 1131: 
 1132: run through list of files and attempt to publish unhidden files
 1133: 
 1134: =back
 1135: 
 1136: =head1 SUBROUTINES:
 1137: 
 1138: =over
 1139: 
 1140: =item startpage($r, $uame, $udom, $thisdisfn)
 1141: 
 1142: Output the header of the page.  This includes:
 1143:  - The HTML header 
 1144:  - The H1/H3  stuff which includes the directory.
 1145:  
 1146:     startpage($r, $uame, $udom, $thisdisfn);
 1147:         $r     - The apache request object.
 1148:         $uname - User name.
 1149:         $udom  - Domain name the user is logged in under.
 1150:         $thisdisfn - Displayable version of the filename.
 1151: 
 1152: =item getTitleString($fullname)
 1153: 
 1154:     Get the title string or "[untitled]" if the file has no title metadata:
 1155:     Without the latter substitution, it's impossible to examine metadata for
 1156:     untitled resources.  Resources may be legitimately untitled, to prevent
 1157:     searches from locating them.
 1158:     
 1159:     $str = getTitleString($fullname);
 1160:         $fullname - Fully qualified filename to check.
 1161: 
 1162: =item putdirectory($r, $base, $here, $dirname, $modtime, $targetdir, $bombs,
 1163:                    $numdir)
 1164: 
 1165:     Put out a directory table row:
 1166:     
 1167:         $r        - Apache request object.
 1168:         $reqfile  - File in request.
 1169:         $here     - Where we are in directory tree.
 1170:         $dirname  - Name of directory special file.
 1171:         $modtime  - Encoded modification time.
 1172:         targetdir - Publication target directory.
 1173:         bombs     - Reference to hash of URLs with runtime error messages.
 1174:         numdir    - Reference to scalar used to track number of sub-directories
 1175:                     in directory (used in form name for each "actions" dropdown).
 1176: 
 1177: =back
 1178: 
 1179: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>