Annotation of loncom/interface/londocs.pm, revision 1.293
1.1 www 1: # The LearningOnline Network
1.2 www 2: # Documents
1.1 www 3: #
1.293 ! albertel 4: # $Id: londocs.pm,v 1.292 2007/07/14 00:10:13 albertel Exp $
1.1 www 5: #
1.3 www 6: # Copyright Michigan State University Board of Trustees
1.1 www 7: #
1.3 www 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
1.1 www 9: #
1.3 www 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.
1.1 www 14: #
1.3 www 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:
1.2 www 29: package Apache::londocs;
1.1 www 30:
31: use strict;
1.28 www 32: use Apache::Constants qw(:common :http);
1.158 raeburn 33: use Apache::imsexport;
1.4 www 34: use Apache::lonnet;
35: use Apache::loncommon;
1.245 albertel 36: use LONCAPA::map();
37: use Apache::lonratedt();
1.15 www 38: use Apache::lonxml;
1.244 albertel 39: use Apache::lonclonecourse;
1.138 raeburn 40: use Apache::lonnavmaps;
1.38 www 41: use HTML::Entities;
1.27 www 42: use GDBM_File;
1.81 www 43: use Apache::lonlocal;
1.143 raeburn 44: use Cwd;
1.264 albertel 45: use LONCAPA qw(:DEFAULT :match);
1.7 www 46:
1.8 www 47: my $iconpath;
1.7 www 48:
1.27 www 49: my %hash;
50:
51: my $hashtied;
1.29 www 52: my %alreadyseen=();
1.27 www 53:
1.40 www 54: my $hadchanges;
55:
1.47 www 56: # Available help topics
57:
58: my %help=();
59:
1.245 albertel 60: # Mapread read maps into LONCAPA::map:: global arrays
1.10 www 61: # @order and @resources, determines status
1.7 www 62: # sets @order - pointer to resources in right order
63: # sets @resources - array with the resources with correct idx
64: #
65:
66: sub mapread {
67: my ($coursenum,$coursedom,$map)=@_;
68: return
1.245 albertel 69: &LONCAPA::map::mapread('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
70: $map);
1.7 www 71: }
72:
73: sub storemap {
74: my ($coursenum,$coursedom,$map)=@_;
1.104 albertel 75: my ($outtext,$errtext)=
1.245 albertel 76: &LONCAPA::map::storemap('/uploaded/'.$coursedom.'/'.$coursenum.'/'.
77: $map,1);
1.104 albertel 78: if ($errtext) { return ($errtext,2); }
79:
80: $hadchanges=1;
81: return ($errtext,0);
1.7 www 82: }
83:
1.74 www 84: # ----------------------------------------- Return hash with valid author names
85:
86: sub authorhosts {
87: my %outhash=();
88: my $home=0;
89: my $other=0;
1.174 albertel 90: foreach (keys %env) {
1.74 www 91: if ($_=~/^user\.role\.(au|ca)\.(.+)$/) {
92: my $role=$1;
93: my $realm=$2;
1.174 albertel 94: my ($start,$end)=split(/\./,$env{$_});
1.74 www 95: if (($start) && ($start>time)) { next; }
96: if (($end) && (time>$end)) { next; }
97: my $ca; my $cd;
98: if ($1 eq 'au') {
1.174 albertel 99: $ca=$env{'user.name'};
100: $cd=$env{'user.domain'};
1.74 www 101: } else {
1.264 albertel 102: ($cd,$ca)=($realm=~/^\/($match_domain)\/($match_username)$/);
1.74 www 103: }
1.107 albertel 104: my $allowed=0;
105: my $myhome=&Apache::lonnet::homeserver($ca,$cd);
106: my @ids=&Apache::lonnet::current_machine_ids();
107: foreach my $id (@ids) { if ($id eq $myhome) { $allowed=1; } }
108: if ($allowed) {
1.74 www 109: $home++;
110: $outhash{'home_'.$ca.'@'.$cd}=1;
111: } else {
1.107 albertel 112: $outhash{'otherhome_'.$ca.'@'.$cd}=$myhome;
1.74 www 113: $other++;
114: }
115: }
116: }
117: return ($home,$other,%outhash);
118: }
119: # ------------------------------------------------------ Generate "dump" button
120:
121: sub dumpbutton {
122: my ($home,$other,%outhash)=&authorhosts();
1.230 albertel 123: my $type = &Apache::loncommon::course_type();
1.74 www 124: if ($home+$other==0) { return ''; }
125: if ($home) {
1.283 albertel 126: return '<div>'.
1.81 www 127: '<input type="submit" name="dumpcourse" value="'.
1.230 albertel 128: &mt('Dump '.$type.' DOCS to Construction Space').'" />'.
1.283 albertel 129: &Apache::loncommon::help_open_topic('Docs_Dump_Course_Docs').
130: '</div>';
1.74 www 131: } else {
1.283 albertel 132: return '<div>'.
1.230 albertel 133: &mt('Dump '.$type.
1.283 albertel 134: ' DOCS to Construction Space: available on other servers').
135: '</div>';
1.74 www 136: }
137: }
138:
1.164 albertel 139: sub clean {
140: my ($title)=@_;
141: $title=~s/[^\w\/\!\$\%\^\*\-\_\=\+\;\:\,\\\|\`\~]+/\_/gs;
142: return $title;
143: }
1.74 www 144: # -------------------------------------------------------- Actually dump course
145:
146: sub dumpcourse {
1.224 albertel 147: my ($r) = @_;
1.230 albertel 148: my $type = &Apache::loncommon::course_type();
149: $r->print(&Apache::loncommon::start_page('Dump '.$type.' DOCS to Construction Space').
150: '<form name="dumpdoc" method="post">');
1.257 www 151: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Dump '.$type.' DOCS to Construction Space'));
1.74 www 152: my ($home,$other,%outhash)=&authorhosts();
1.75 www 153: unless ($home) { return ''; }
1.174 albertel 154: my $origcrsid=$env{'request.course.id'};
1.76 www 155: my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid);
1.174 albertel 156: if (($env{'form.authorspace'}) && ($env{'form.authorfolder'}=~/\w/)) {
1.76 www 157: # Do the dumping
1.174 albertel 158: unless ($outhash{'home_'.$env{'form.authorspace'}}) { return ''; }
159: my ($ca,$cd)=split(/\@/,$env{'form.authorspace'});
1.87 www 160: $r->print('<h3>'.&mt('Copying Files').'</h3>');
1.174 albertel 161: my $title=$env{'form.authorfolder'};
1.164 albertel 162: $title=&clean($title);
1.79 www 163: my %replacehash=();
1.174 albertel 164: foreach (keys %env) {
1.79 www 165: if ($_=~/^form\.namefor\_(.+)/) {
1.174 albertel 166: $replacehash{$1}=$env{$_};
1.79 www 167: }
168: }
1.174 albertel 169: my $crs='/uploaded/'.$env{'request.course.id'}.'/';
1.79 www 170: $crs=~s/\_/\//g;
171: foreach (keys %replacehash) {
172: my $newfilename=$title.'/'.$replacehash{$_};
1.205 albertel 173: $newfilename=~s/\.(\w+)$//;
174: my $ext=$1;
1.164 albertel 175: $newfilename=&clean($newfilename);
1.205 albertel 176: $newfilename.='.'.$ext;
1.79 www 177: my @dirs=split(/\//,$newfilename);
178: my $path='/home/'.$ca.'/public_html';
179: my $makepath=$path;
180: my $fail=0;
181: for (my $i=0;$i<$#dirs;$i++) {
182: $makepath.='/'.$dirs[$i];
183: unless (-e $makepath) {
184: unless(mkdir($makepath,0777)) { $fail=1; }
185: }
186: }
187: $r->print('<br /><tt>'.$_.'</tt> => <tt>'.$newfilename.'</tt>: ');
188: if (my $fh=Apache::File->new('>'.$path.'/'.$newfilename)) {
189: if ($_=~/\.(sequence|page|html|htm|xml|xhtml)$/) {
1.244 albertel 190: print $fh &Apache::lonclonecourse::rewritefile(
191: &Apache::lonclonecourse::readfile($env{'request.course.id'},$_),
1.79 www 192: (%replacehash,$crs => '')
193: );
194: } else {
195: print $fh
1.244 albertel 196: &Apache::lonclonecourse::readfile($env{'request.course.id'},$_);
1.79 www 197: }
198: $fh->close();
199: } else {
200: $fail=1;
201: }
202: if ($fail) {
1.283 albertel 203: $r->print('<span class="LC_error">'.&mt('fail').'</span>');
1.79 www 204: } else {
1.283 albertel 205: $r->print('<span class="LC_success">'.&mt('ok').'</span>');
1.79 www 206: }
207: }
1.76 www 208: } else {
209: # Input form
210: unless ($home==1) {
211: $r->print(
1.81 www 212: '<h3>'.&mt('Select the Construction Space').'</h3><select name="authorspace">');
1.76 www 213: }
214: foreach (sort keys %outhash) {
215: if ($_=~/^home_(.+)$/) {
216: if ($home==1) {
217: $r->print(
218: '<input type="hidden" name="authorspace" value="'.$1.'" />');
219: } else {
1.133 www 220: $r->print('<option value="'.$1.'">'.$1.' - '.
221: &Apache::loncommon::plainname(split(/\@/,$1)).'</option>');
1.76 www 222: }
223: }
224: }
225: unless ($home==1) {
226: $r->print('</select>');
227: }
228: my $title=$origcrsdata{'description'};
1.227 albertel 229: $title=~s/[\/\s]+/\_/gs;
1.164 albertel 230: $title=&clean($title);
1.81 www 231: $r->print('<h3>'.&mt('Folder in Construction Space').'</h3><input type="text" size="50" name="authorfolder" value="'.$title.'" /><br />');
1.76 www 232: &tiehash();
1.81 www 233: $r->print('<h3>'.&mt('Filenames in Construction Space').'</h3><table border="2"><tr><th>'.&mt('Internal Filename').'</th><th>'.&mt('Title').'</th><th>'.&mt('Save as ...').'</th></tr>');
1.244 albertel 234: foreach (&Apache::lonclonecourse::crsdirlist($origcrsid,'userfiles')) {
1.78 www 235: $r->print('<tr><td>'.$_.'</td>');
236: my ($ext)=($_=~/\.(\w+)$/);
237: my $title=$hash{'title_'.$hash{
238: 'ids_/uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'.$_}};
239: $r->print('<td>'.($title?$title:' ').'</td>');
1.235 albertel 240: if (!$title) {
1.78 www 241: $title=$_;
1.235 albertel 242: } else {
243: $title=~s|/|_|g;
1.78 www 244: }
245: $title=~s/\.(\w+)$//;
1.164 albertel 246: $title=&clean($title);
1.78 www 247: $title.='.'.$ext;
1.79 www 248: $r->print("\n<td><input type='text' size='60' name='namefor_".$_."' value='".$title."' /></td></tr>\n");
1.76 www 249: }
1.78 www 250: $r->print("</table>\n");
1.76 www 251: &untiehash();
252: $r->print(
1.229 raeburn 253: '<p><input type="submit" name="dumpcourse" value="'.&mt('Dump [_1] DOCS',$type).'" /></p></form>');
1.75 www 254: }
1.74 www 255: }
1.76 www 256:
1.138 raeburn 257: # ------------------------------------------------------ Generate "export" button
258:
259: sub exportbutton {
1.230 albertel 260: my $type = &Apache::loncommon::course_type();
1.283 albertel 261: return '<div>'.
1.138 raeburn 262: '<input type="submit" name="exportcourse" value="'.
1.230 albertel 263: &mt('Export '.$type.' to IMS').'" />'.
1.283 albertel 264: &Apache::loncommon::help_open_topic('Docs_Export_Course_Docs').'</div>';
1.138 raeburn 265: }
266:
267: sub exportcourse {
268: my $r=shift;
1.230 albertel 269: my $type = &Apache::loncommon::course_type();
1.138 raeburn 270: my %discussiontime = &Apache::lonnet::dump('discussiontimes',
1.174 albertel 271: $env{'course.'.$env{'request.course.id'}.'.domain'}, $env{'course.'.$env{'request.course.id'}.'.num'});
1.138 raeburn 272: my $numdisc = keys %discussiontime;
273: my $navmap = Apache::lonnavmaps::navmap->new();
274: my $it=$navmap->getIterator(undef,undef,undef,1,undef,undef);
275: my $curRes;
1.143 raeburn 276: my $outcome;
1.138 raeburn 277:
278: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
279: ['finishexport']);
1.174 albertel 280: if ($env{'form.finishexport'}) {
1.138 raeburn 281: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
282: ['archive','discussion']);
283:
1.175 albertel 284: my @exportitems = &Apache::loncommon::get_env_multiple('form.archive');
285: my @discussions = &Apache::loncommon::get_env_multiple('form.discussion');
1.143 raeburn 286: if (@exportitems == 0 && @discussions == 0) {
287: $outcome = '<br />As you did not select any content items or discussions for export, an IMS package has not been created. Please <a href="javascript:history.go(-1)">go back</a> to select either content items or discussions for export';
288: } else {
289: my $now = time;
290: my %symbs;
291: my $manifestok = 0;
292: my $imsresources;
293: my $tempexport;
294: my $copyresult;
295: my $ims_manifest = &create_ims_store($now,\$manifestok,\$outcome,\$tempexport);
296: if ($manifestok) {
1.157 raeburn 297: &build_package($now,$navmap,\@exportitems,\@discussions,\$outcome,$tempexport,\$copyresult,$ims_manifest);
1.143 raeburn 298: close($ims_manifest);
299:
300: #Create zip file in prtspool
301: my $imszipfile = '/prtspool/'.
1.174 albertel 302: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.143 raeburn 303: time.'_'.rand(1000000000).'.zip';
304: my $cwd = &Cwd::getcwd();
305: my $imszip = '/home/httpd/'.$imszipfile;
306: chdir $tempexport;
307: open(OUTPUT, "zip -r $imszip * 2> /dev/null |");
308: close(OUTPUT);
309: chdir $cwd;
1.230 albertel 310: $outcome .= &mt('Download the zip file from <a href="[_1]">IMS '.lc($type).' archive</a><br />',$imszipfile,);
1.143 raeburn 311: if ($copyresult) {
312: $outcome .= 'The following errors occurred during export - '.$copyresult;
1.138 raeburn 313: }
1.143 raeburn 314: } else {
315: $outcome = '<br />Unfortunately you will not be able to retrieve an IMS archive of this posts at this time, because there was a problem creating a manifest file.<br />';
1.138 raeburn 316: }
317: }
1.229 raeburn 318: $r->print(&Apache::loncommon::start_page('Export '.lc($type).' to IMS content package'));
1.257 www 319: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Export '.lc($type).' to IMS content package'));
1.143 raeburn 320: $r->print($outcome);
1.224 albertel 321: $r->print(&Apache::loncommon::end_page());
1.138 raeburn 322: } else {
323: my $display;
324: $display = '<form name="exportdoc" method="post">'."\n";
1.230 albertel 325: $display .= &mt('Choose which items you wish to export from your '.$type.'.<br /><br />');
1.138 raeburn 326: $display .= '<table border="0" cellspacing="0" cellpadding="3">'.
327: '<tr><td><fieldset><legend> <b>Content items</b></legend>'.
328: '<input type="button" value="check all" '.
329: 'onclick="javascript:checkAll(document.exportdoc.archive)" />'.
330: ' <input type="button" value="uncheck all"'.
331: ' onclick="javascript:uncheckAll(document.exportdoc.archive)" /></fieldset></td>'.
332: '<td> </td><td> </td>'.
333: '<td align="right"><fieldset><legend> <b>Discussion posts'.
334: '</b></legend><input type="button" value="check all"'.
335: ' onclick="javascript:checkAll(document.exportdoc.discussion)" />'.
336: ' <input type="button" value="uncheck all"'.
337: ' onclick="javascript:uncheckAll(document.exportdoc.discussion)" /></fieldset></td>'.
338: '</tr></table>';
339: my $curRes;
340: my $depth = 0;
341: my $count = 0;
342: my $boards = 0;
343: my $startcount = 5;
344: my %parent = ();
345: my %children = ();
346: my $lastcontainer = $startcount;
347: my @bgcolors = ('#F6F6F6','#FFFFFF');
348: $display .= '<table cellspacing="0"><tr>'.
349: '<td><b>Export content item?<br /></b></td><td> </td><td align="right">'."\n";
350: if ($numdisc > 0) {
351: $display.='<b>Export discussion posts?</b>'."\n";
352: }
353: $display.=' </td></tr>';
354: while ($curRes = $it->next()) {
355: if (ref($curRes)) {
356: $count ++;
357: }
358: if ($curRes == $it->BEGIN_MAP()) {
359: $depth++;
360: $parent{$depth} = $lastcontainer;
361: }
362: if ($curRes == $it->END_MAP()) {
363: $depth--;
364: $lastcontainer = $parent{$depth};
365: }
366: if (ref($curRes)) {
367: my $symb = $curRes->symb();
1.158 raeburn 368: my $ressymb = $symb;
1.264 albertel 369: if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
1.158 raeburn 370: unless ($ressymb =~ m|adm/wrapper/adm|) {
371: $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
372: }
373: }
1.138 raeburn 374: my $color = $count%2;
375: $display .='<tr bgcolor='.$bgcolors[$color].'><td>'."\n".
376: '<input type="checkbox" name="archive" value="'.$count.'" ';
377: if (($curRes->is_sequence()) || ($curRes->is_page())) {
378: my $checkitem = $count + $boards + $startcount;
379: $display .= 'onClick="javascript:propagateCheck('."'$checkitem'".')"';
380: }
381: $display .= ' />'."\n";
382: for (my $i=0; $i<$depth; $i++) {
1.282 albertel 383: $display .= '<img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" /><img src="/adm/lonIcons/whitespace1.gif" class="LC_docs_spacer" />'."\n";
1.138 raeburn 384: }
385: if ($curRes->is_sequence()) {
386: $display .= '<img src="/adm/lonIcons/navmap.folder.open.gif"> '."\n";
387: $lastcontainer = $count + $startcount + $boards;
388: } elsif ($curRes->is_page()) {
389: $display .= '<img src="/adm/lonIcons/navmap.page.open.gif"> '."\n";
390: $lastcontainer = $count + $startcount + $boards;
391: }
392: my $currelem = $count+$boards+$startcount;
393: $children{$parent{$depth}} .= $currelem.':';
394: $display .= ' '.$curRes->title().'</td>';
1.158 raeburn 395: if ($discussiontime{$ressymb} > 0) {
1.138 raeburn 396: $boards ++;
397: $currelem = $count+$boards+$startcount;
398: $display .= '<td> </td><td align="right"><input type="checkbox" name="discussion" value="'.$count.'" /> </td>'."\n";
399: } else {
400: $display .= '<td colspan="2"> </td>'."\n";
401: }
402: }
403: }
404: my $scripttag = qq|
405: <script>
406:
407: function checkAll(field) {
1.158 raeburn 408: if (field.length > 0) {
409: for (i = 0; i < field.length; i++) {
410: field[i].checked = true ;
411: }
412: } else {
413: field.checked = true
414: }
1.138 raeburn 415: }
1.158 raeburn 416:
1.138 raeburn 417: function uncheckAll(field) {
1.158 raeburn 418: if (field.length > 0) {
419: for (i = 0; i < field.length; i++) {
420: field[i].checked = false ;
421: }
422: } else {
423: field.checked = false ;
424: }
1.138 raeburn 425: }
426:
427: function propagateCheck(item) {
428: if (document.exportdoc.elements[item].checked == true) {
429: containerCheck(item)
430: }
431: }
432:
433: function containerCheck(item) {
434: document.exportdoc.elements[item].checked = true
435: var numitems = $count + $boards + $startcount
436: var parents = new Array(numitems)
437: for (var i=$startcount; i<numitems; i++) {
438: parents[i] = new Array
439: }
440: |;
441:
442: foreach my $container (sort { $a <=> $b } keys %children) {
443: my @contents = split/:/,$children{$container};
444: for (my $i=0; $i<@contents; $i ++) {
445: $scripttag .= ' parents['.$container.']['.$i.'] = '.$contents[$i]."\n";
446: }
447: }
448:
449: $scripttag .= qq|
450: if (parents[item].length > 0) {
451: for (var j=0; j<parents[item].length; j++) {
452: containerCheck(parents[item][j])
453: }
454: }
455: }
456:
457: </script>
458: |;
1.229 raeburn 459: $r->print(&Apache::loncommon::start_page('Export '.lc($type).' to IMS content package',
1.224 albertel 460: $scripttag));
1.257 www 461: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Export '.lc($type).' to IMS content package'));
1.224 albertel 462: $r->print($display.'</table>'.
1.138 raeburn 463: '<p><input type="hidden" name="finishexport" value="1">'.
464: '<input type="submit" name="exportcourse" value="'.
1.230 albertel 465: &mt('Export '.$type.' DOCS').'" /></p></form>'.
1.224 albertel 466: &Apache::loncommon::end_page());
1.138 raeburn 467: }
468: }
469:
1.143 raeburn 470: sub create_ims_store {
471: my ($now,$manifestok,$outcome,$tempexport) = @_;
472: $$tempexport = $Apache::lonnet::perlvar{'lonDaemons'}.'/tmp/ims_exports';
473: my $ims_manifest;
474: if (!-e $$tempexport) {
475: mkdir($$tempexport,0700);
476: }
477: $$tempexport .= '/'.$now;
478: if (!-e $$tempexport) {
479: mkdir($$tempexport,0700);
480: }
1.174 albertel 481: $$tempexport .= '/'.$env{'user.domain'}.'_'.$env{'user.name'};
1.143 raeburn 482: if (!-e $$tempexport) {
483: mkdir($$tempexport,0700);
484: }
1.159 raeburn 485: if (!-e "$$tempexport/resources") {
486: mkdir("$$tempexport/resources",0700);
487: }
1.143 raeburn 488: # open manifest file
489: my $manifest = '/imsmanifest.xml';
490: my $manifestfilename = $$tempexport.$manifest;
491: if ($ims_manifest = Apache::File->new('>'.$manifestfilename)) {
492: $$manifestok=1;
493: print $ims_manifest
494: '<?xml version="1.0" encoding="UTF-8"?>'."\n".
495: '<manifest xmlns="http://www.imsglobal.org/xsd/imscp_v1p1"'.
496: ' xmlns:imsmd="http://www.imsglobal.org/xsd/imsmd_v1p2"'.
497: ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'.
1.174 albertel 498: ' identifier="MANIFEST-'.$env{'request.course.id'}.'-'.$now.'"'.
1.143 raeburn 499: ' xsi:schemaLocation="http://www.imsglobal.org/xsd/imscp_v1p1imscp_v1p1.xsd'.
500: ' http://www.imsglobal.org/xsd/imsmd_v1p2 imsmd_v1p2p2.xsd">'."\n".
1.199 raeburn 501: ' <metadata>
502: <schema></schema>
503: <imsmd:lom>
504: <imsmd:general>
505: <imsmd:identifier>'.$env{'request.course.id'}.'</imsmd:identifier>
506: <imsmd:title>
507: <imsmd:langstring xml:lang="en">'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</imsmd:langstring>
508: </imsmd:title>
509: </imsmd:general>
510: </imsmd:lom>
511: </metadata>'."\n".
1.174 albertel 512: ' <organizations default="ORG-'.$env{'request.course.id'}.'-'.$now.'">'."\n".
513: ' <organization identifier="ORG-'.$env{'request.course.id'}.'-'.$now.'"'.
1.143 raeburn 514: ' structure="hierarchical">'."\n".
1.199 raeburn 515: ' <title>'.$env{'course.'.$env{'request.course.id'}.'.description'}.'</title>'
1.143 raeburn 516: } else {
517: $$outcome .= 'An error occurred opening the IMS manifest file.<br />'
518: ;
519: }
520: return $ims_manifest;
521: }
522:
523: sub build_package {
524: my ($now,$navmap,$exportitems,$discussions,$outcome,$tempexport,$copyresult,$ims_manifest) = @_;
525: # first iterator to look for dependencies
526: my $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
527: my $curRes;
528: my $count = 0;
529: my $depth = 0;
530: my $lastcontainer = 0;
531: my %parent = ();
532: my @dependencies = ();
1.174 albertel 533: my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
534: my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
1.143 raeburn 535: while ($curRes = $it->next()) {
536: if (ref($curRes)) {
537: $count ++;
538: }
539: if ($curRes == $it->BEGIN_MAP()) {
540: $depth++;
541: $parent{$depth} = $lastcontainer;
542: }
543: if ($curRes == $it->END_MAP()) {
544: $depth--;
545: $lastcontainer = $parent{$depth};
546: }
547: if (ref($curRes)) {
548: if ($curRes->is_sequence() || $curRes->is_page()) {
549: $lastcontainer = $count;
550: }
551: if (grep/^$count$/,@$exportitems) {
552: &get_dependencies($exportitems,\%parent,$depth,\@dependencies);
553: }
554: }
555: }
556: # second iterator to build manifest and store resources
557: $it = $navmap->getIterator(undef,undef,undef,1,undef,undef);
558: $depth = 0;
559: my $prevdepth;
560: $count = 0;
561: my $imsresources;
562: my $pkgdepth;
1.157 raeburn 563: while ($curRes = $it->next()) {
564: if ($curRes == $it->BEGIN_MAP()) {
565: $prevdepth = $depth;
566: $depth++;
567: }
568: if ($curRes == $it->END_MAP()) {
1.143 raeburn 569: $prevdepth = $depth;
1.157 raeburn 570: $depth--;
571: }
572:
573: if (ref($curRes)) {
574: $count ++;
575: if ((grep/^$count$/,@$exportitems) || (grep/^$count$/,@dependencies)) {
576: my $symb = $curRes->symb();
577: my $isvisible = 'true';
578: my $resourceref;
579: if ($curRes->randomout()) {
580: $isvisible = 'false';
581: }
582: unless ($curRes->is_sequence()) {
1.174 albertel 583: $resourceref = 'identifierref="RES-'.$env{'request.course.id'}.'-'.$count.'"';
1.157 raeburn 584: }
1.199 raeburn 585: my $step = $prevdepth - $depth;
586: if (($step >= 0) && ($count > 1)) {
587: while ($step >= 0) {
588: print $ims_manifest "\n".' </item>'."\n";
589: $step --;
590: }
1.157 raeburn 591: }
592: $prevdepth = $depth;
1.143 raeburn 593:
1.157 raeburn 594: my $itementry =
1.174 albertel 595: '<item identifier="ITEM-'.$env{'request.course.id'}.'-'.$count.
1.143 raeburn 596: '" isvisible="'.$isvisible.'" '.$resourceref.'>'.
597: '<title>'.$curRes->title().'</title>';
1.157 raeburn 598: print $ims_manifest "\n".$itementry;
1.143 raeburn 599:
1.157 raeburn 600: unless ($curRes->is_sequence()) {
601: my $content_file;
602: my @hrefs = ();
603: &process_content($count,$curRes,$cdom,$cnum,$symb,\$content_file,\@hrefs,$copyresult,$tempexport);
604: if ($content_file) {
605: $imsresources .= "\n".
1.174 albertel 606: ' <resource identifier="RES-'.$env{'request.course.id'}.'-'.$count.
1.143 raeburn 607: '" type="webcontent" href="'.$content_file.'">'."\n".
608: ' <file href="'.$content_file.'" />'."\n";
1.157 raeburn 609: foreach (@hrefs) {
610: $imsresources .=
1.143 raeburn 611: ' <file href="'.$_.'" />'."\n";
1.157 raeburn 612: }
1.158 raeburn 613: if (grep/^$count$/,@$discussions) {
614: my $ressymb = $symb;
615: my $mode;
1.264 albertel 616: if ($ressymb =~ m|adm/($match_domain)/($match_username)/(\d+)/bulletinboard$|) {
1.158 raeburn 617: unless ($ressymb =~ m|adm/wrapper/adm|) {
618: $ressymb = 'bulletin___'.$3.'___adm/wrapper/adm/'.$1.'/'.$2.'/'.$3.'/bulletinboard';
619: }
620: $mode = 'board';
621: }
622: my %extras = (
623: caller => 'imsexport',
1.159 raeburn 624: tempexport => $tempexport.'/resources',
1.158 raeburn 625: count => $count
626: );
627: my $discresult = &Apache::lonfeedback::list_discussion($mode,undef,$ressymb,\%extras);
628: }
1.157 raeburn 629: $imsresources .= ' </resource>'."\n";
1.143 raeburn 630: }
631: }
1.157 raeburn 632: $pkgdepth = $depth;
1.143 raeburn 633: }
634: }
635: }
1.157 raeburn 636: while ($pkgdepth > 0) {
1.143 raeburn 637: print $ims_manifest " </item>\n";
638: $pkgdepth --;
639: }
640: my $resource_text = qq|
641: </organization>
642: </organizations>
643: <resources>
644: $imsresources
645: </resources>
646: </manifest>
647: |;
648: print $ims_manifest $resource_text;
649: }
650:
651: sub get_dependencies {
652: my ($exportitems,$parent,$depth,$dependencies) = @_;
653: if ($depth > 1) {
1.157 raeburn 654: if ((!grep/^$$parent{$depth}$/,@$exportitems) && (!grep/^$$parent{$depth}$/,@$dependencies)) {
1.143 raeburn 655: push @$dependencies, $$parent{$depth};
656: if ($depth > 2) {
657: &get_dependencies($exportitems,$parent,$depth-1,$dependencies);
658: }
659: }
660: }
661: }
662:
663: sub process_content {
664: my ($count,$curRes,$cdom,$cnum,$symb,$content_file,$href,$copyresult,$tempexport) = @_;
665: my $content_type;
666: my $message;
1.158 raeburn 667: my @uploads = ();
1.157 raeburn 668: if ($curRes->is_sequence()) {
669: $content_type = 'sequence';
670: } elsif ($curRes->is_page()) {
671: $content_type = 'page'; # need to handle individual items in pages.
1.143 raeburn 672: } elsif ($symb =~ m-public/$cdom/$cnum/syllabus$-) {
673: $content_type = 'syllabus';
1.158 raeburn 674: my $contents = &Apache::imsexport::templatedpage($content_type);
675: if ($contents) {
676: $$content_file = &store_template($contents,$tempexport,$count,$content_type);
677: }
1.157 raeburn 678: } elsif ($symb =~ m-\.sequence___\d+___ext-) {
1.143 raeburn 679: $content_type = 'external';
1.158 raeburn 680: my $title = $curRes->title;
681: my $contents = &Apache::imsexport::external($symb,$title);
682: if ($contents) {
683: $$content_file = &store_template($contents,$tempexport,$count,$content_type);
684: }
1.143 raeburn 685: } elsif ($symb =~ m-adm/navmaps$-) {
686: $content_type = 'navmap';
1.158 raeburn 687: } elsif ($symb =~ m-adm/[^/]+/[^/]+/(\d+)/smppg$-) {
1.143 raeburn 688: $content_type = 'simplepage';
1.158 raeburn 689: my $contents = &Apache::imsexport::templatedpage($content_type,$1,$count,\@uploads);
690: if ($contents) {
691: $$content_file = &store_template($contents,$tempexport,$count,$content_type);
692: }
693: } elsif ($symb =~ m-lib/templates/simpleproblem\.problem$-) {
1.143 raeburn 694: $content_type = 'simpleproblem';
1.158 raeburn 695: my $contents = &Apache::imsexport::simpleproblem($symb);
696: if ($contents) {
697: $$content_file = &store_template($contents,$tempexport,$count,$content_type);
698: }
1.188 raeburn 699: } elsif ($symb =~ m-lib/templates/examupload\.problem$-) {
1.158 raeburn 700: $content_type = 'examupload';
1.264 albertel 701: } elsif ($symb =~ m-adm/($match_domain)/($match_username)/(\d+)/bulletinboard$-) {
1.143 raeburn 702: $content_type = 'bulletinboard';
1.158 raeburn 703: my $contents = &Apache::imsexport::templatedpage($content_type,$3,$count,\@uploads,$1,$2);
704: if ($contents) {
705: $$content_file = &store_template($contents,$tempexport,$count,$content_type);
706: }
707: } elsif ($symb =~ m-adm/([^/]+)/([^/]+)/aboutme$-) {
1.143 raeburn 708: $content_type = 'aboutme';
1.158 raeburn 709: my $contents = &Apache::imsexport::templatedpage($content_type,undef,$count,\@uploads,$1,$2);
710: if ($contents) {
711: $$content_file = &store_template($contents,$tempexport,$count,$content_type);
712: }
1.157 raeburn 713: } elsif ($symb =~ m-\.(sequence|page)___\d+___uploaded/$cdom/$cnum/-) {
714: $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded');
1.162 raeburn 715: } elsif ($symb =~ m-\.(sequence|page)___\d+___([^/]+)/([^/]+)-) {
1.143 raeburn 716: my $canedit = 0;
1.174 albertel 717: if ($2 eq $env{'user.domain'} && $3 eq $env{'user.name'}) {
1.143 raeburn 718: $canedit= 1;
719: }
1.200 raeburn 720: # only include problem code where current user is author
1.143 raeburn 721: if ($canedit) {
1.157 raeburn 722: $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'resource');
1.143 raeburn 723: } else {
1.157 raeburn 724: $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'noedit');
1.143 raeburn 725: }
1.162 raeburn 726: } elsif ($symb =~ m-uploaded/$cdom/$cnum-) {
727: $$content_file = &replicate_content($cdom,$cnum,$tempexport,$symb,$count,\$message,$href,'uploaded');
1.143 raeburn 728: }
1.158 raeburn 729: if (@uploads > 0) {
730: foreach my $item (@uploads) {
731: my $uploadmsg = '';
1.159 raeburn 732: &replicate_content($cdom,$cnum,$tempexport,$item,$count,\$uploadmsg,$href,'templateupload');
1.158 raeburn 733: if ($uploadmsg) {
734: $$copyresult .= $uploadmsg."\n";
735: }
736: }
737: }
1.157 raeburn 738: if ($message) {
739: $$copyresult .= $message."\n";
740: }
1.143 raeburn 741: }
742:
743: sub replicate_content {
1.157 raeburn 744: my ($cdom,$cnum,$tempexport,$symb,$count,$message,$href,$caller) = @_;
1.159 raeburn 745: my ($map,$ind,$url);
746: if ($caller eq 'templateupload') {
747: $url = $symb;
748: $url =~ s#//#/#g;
749: } else {
750: ($map,$ind,$url)=&Apache::lonnet::decode_symb($symb);
751: }
1.143 raeburn 752: my $content;
753: my $filename;
754: my $repstatus;
1.157 raeburn 755: my $content_name;
756: if ($url =~ m-/([^/]+)$-) {
1.143 raeburn 757: $filename = $1;
758: if (!-e $tempexport.'/resources') {
759: mkdir($tempexport.'/resources',0700);
760: }
1.157 raeburn 761: if (!-e $tempexport.'/resources/'.$count) {
1.143 raeburn 762: mkdir($tempexport.'/resources/'.$count,0700);
763: }
1.157 raeburn 764: my $destination = $tempexport.'/resources/'.$count.'/'.$filename;
1.143 raeburn 765: my $copiedfile;
766: if ($copiedfile = Apache::File->new('>'.$destination)) {
767: my $content;
1.157 raeburn 768: if ($caller eq 'resource') {
1.197 raeburn 769: my $respath = $Apache::lonnet::perlvar{'lonDocRoot'}.'/res';
770: my $filepath = &Apache::lonnet::filelocation($respath,$url);
771: $content = &Apache::lonnet::getfile($filepath);
1.143 raeburn 772: if ($content eq -1) {
773: $$message = 'Could not copy file '.$filename;
774: } else {
1.197 raeburn 775: &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'resource');
1.143 raeburn 776: $repstatus = 'ok';
777: }
1.162 raeburn 778: } elsif ($caller eq 'uploaded' || $caller eq 'templateupload') {
1.143 raeburn 779: my $rtncode;
1.157 raeburn 780: $repstatus = &Apache::lonnet::getuploaded('GET',$url,$cdom,$cnum,\$content,$rtncode);
781: if ($repstatus eq 'ok') {
782: if ($url =~ /\.html?$/i) {
1.197 raeburn 783: &extract_media($url,$cdom,$cnum,\$content,$count,$tempexport,$href,$message,'uploaded');
1.157 raeburn 784: }
785: } else {
1.197 raeburn 786: $$message = 'Could not render '.$url.' server message - '.$rtncode."<br />\n";
1.143 raeburn 787: }
1.162 raeburn 788: } elsif ($caller eq 'noedit') {
789: # Need to render the resource without the LON-CAPA Internal header and the Post discussion footer, and then set $content equal to this.
790: $repstatus = 'ok';
791: $content = 'Not the owner of this resource';
1.143 raeburn 792: }
793: if ($repstatus eq 'ok') {
794: print $copiedfile $content;
795: }
796: close($copiedfile);
797: } else {
1.197 raeburn 798: $$message = 'Could not open destination file for '.$filename."<br />\n";
1.143 raeburn 799: }
800: } else {
1.197 raeburn 801: $$message = 'Could not determine name of file for '.$symb."<br />\n";
1.143 raeburn 802: }
1.157 raeburn 803: if ($repstatus eq 'ok') {
1.198 raeburn 804: $content_name = 'resources/'.$count.'/'.$filename;
1.157 raeburn 805: }
806: return $content_name;
807: }
808:
809: sub extract_media {
1.197 raeburn 810: my ($url,$cdom,$cnum,$content,$count,$tempexport,$href,$message,$caller) = @_;
1.198 raeburn 811: my ($dirpath,$container);
1.197 raeburn 812: my %allfiles = ();
813: my %codebase = ();
1.198 raeburn 814: if ($url =~ m-(.*/)([^/]+)$-) {
815: $dirpath = $1;
816: $container = $2;
817: } else {
818: $dirpath = $url;
819: $container = '';
820: }
1.197 raeburn 821: &Apache::lonnet::extract_embedded_items(undef,undef,\%allfiles,\%codebase,$content);
822: foreach my $embed_file (keys(%allfiles)) {
823: my $filename;
824: if ($embed_file =~ m#([^/]+)$#) {
825: $filename = $1;
826: } else {
827: $filename = $embed_file;
828: }
829: my $newname = 'res/'.$filename;
830: my ($rtncode,$embed_content,$repstatus);
831: my $embed_url;
832: if ($embed_file =~ m-^/-) {
833: $embed_url = $embed_file; # points to absolute path
834: } else {
835: if ($embed_file =~ m-https?://-) {
836: next; # points to url
837: } else {
1.198 raeburn 838: $embed_url = $dirpath.$embed_file; # points to relative path
1.197 raeburn 839: }
840: }
841: if ($caller eq 'resource') {
842: my $respath = $Apache::lonnet::perlvar{'lonDocRoot'}.'/res';
843: my $embed_path = &Apache::lonnet::filelocation($respath,$embed_url);
844: $embed_content = &Apache::lonnet::getfile($embed_path);
845: unless ($embed_content eq -1) {
846: $repstatus = 'ok';
847: }
848: } elsif ($caller eq 'uploaded') {
849:
850: $repstatus = &Apache::lonnet::getuploaded('GET',$embed_url,$cdom,$cnum,\$embed_content,$rtncode);
851: }
852: if ($repstatus eq 'ok') {
853: my $destination = $tempexport.'/resources/'.$count.'/res';
854: if (!-e "$destination") {
855: mkdir($destination,0755);
856: }
857: $destination .= '/'.$filename;
858: my $copiedfile;
859: if ($copiedfile = Apache::File->new('>'.$destination)) {
860: print $copiedfile $embed_content;
1.198 raeburn 861: push @{$href}, 'resources/'.$count.'/res/'.$filename;
1.197 raeburn 862: my $attrib_regexp = '';
863: if (@{$allfiles{$embed_file}} > 1) {
864: $attrib_regexp = join('|',@{$allfiles{$embed_file}});
865: } else {
866: $attrib_regexp = $allfiles{$embed_file}[0];
867: }
868: $$content =~ s#($attrib_regexp\s*=\s*['"]?)\Q$embed_file\E(['"]?)#$1$newname$2#gi;
1.198 raeburn 869: if ($caller eq 'resource' && $container =~ /\.(problem|library)$/) {
1.197 raeburn 870: $$content =~ s#\Q$embed_file\E#$newname#gi;
871: }
872: }
873: } else {
874: $$message .= 'replication of embedded file - '.$embed_file.' in '.$url.' failed, reason -'.$rtncode."<br />\n";
875: }
876: }
1.157 raeburn 877: return;
1.143 raeburn 878: }
1.74 www 879:
1.158 raeburn 880: sub store_template {
881: my ($contents,$tempexport,$count,$content_type) = @_;
882: if ($contents) {
1.159 raeburn 883: if ($tempexport) {
884: if (!-e $tempexport.'/resources') {
885: mkdir($tempexport.'/resources',0700);
886: }
887: if (!-e $tempexport.'/resources/'.$count) {
888: mkdir($tempexport.'/resources/'.$count,0700);
889: }
890: my $destination = $tempexport.'/resources/'.$count.'/'.$content_type.'.xml';
891: my $storetemplate;
892: if ($storetemplate = Apache::File->new('>'.$destination)) {
893: print $storetemplate $contents;
894: close($storetemplate);
895: }
896: if ($content_type eq 'external') {
1.198 raeburn 897: return 'resources/'.$count.'/'.$content_type.'.html';
1.159 raeburn 898: } else {
1.198 raeburn 899: return 'resources/'.$count.'/'.$content_type.'.xml';
1.159 raeburn 900: }
1.158 raeburn 901: }
902: }
903: }
904:
1.73 bowersj2 905: # Imports the given (name, url) resources into the course
906: # coursenum, coursedom, and folder must precede the list
907: sub group_import {
1.277 albertel 908: my ($coursenum, $coursedom, $folder, $container, $caller, @files) = @_;
909:
910: while (@files) {
1.287 albertel 911: my ($name, $url, $residx) = @{ shift(@files) };
1.277 albertel 912: if (($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/(default_\d+\.)(page|sequence)$})
913: && ($caller eq 'londocs')
914: && (!&Apache::lonnet::stat_file($url))) {
915:
1.142 raeburn 916: my $errtext = '';
917: my $fatal = 0;
918: my $newmapstr = '<map>'."\n".
919: '<resource id="1" src="" type="start"></resource>'."\n".
920: '<link from="1" to="2" index="1"></link>'."\n".
921: '<resource id="2" src="" type="finish"></resource>'."\n".
922: '</map>';
1.174 albertel 923: $env{'form.output'}=$newmapstr;
1.189 albertel 924: my $result=&Apache::lonnet::finishuserfileupload($coursenum,$coursedom,
1.142 raeburn 925: 'output',$1.$2);
926: if ($result != m|^/uploaded/|) {
927: $errtext.='Map not saved: A network error occured when trying to save the new map. ';
928: $fatal = 2;
929: }
930: if ($fatal) {
931: return ($errtext,$fatal);
932: }
933: }
1.73 bowersj2 934: if ($url) {
1.288 albertel 935: if (!$residx
936: || defined($LONCAPA::map::zombies[$residx])) {
937: $residx = &LONCAPA::map::getresidx($url,$residx);
938: push(@LONCAPA::map::order, $residx);
1.287 albertel 939: }
1.73 bowersj2 940: my $ext = 'false';
1.263 albertel 941: if ($url=~m{^http://} || $url=~m{^https://}) { $ext = 'true'; }
1.273 albertel 942: $url = &LONCAPA::map::qtunescape($url);
943: $name = &LONCAPA::map::qtunescape($name);
1.287 albertel 944: $LONCAPA::map::resources[$residx] =
945: join(':', ($name, $url, $ext, 'normal', 'res'));
1.73 bowersj2 946: }
947: }
1.142 raeburn 948: return &storemap($coursenum, $coursedom, $folder.'.'.$container);
1.73 bowersj2 949: }
950:
1.114 albertel 951: sub breadcrumbs {
952: my ($where)=@_;
953: &Apache::lonhtmlcommon::clear_breadcrumbs();
1.142 raeburn 954: my (@folders);
1.174 albertel 955: if ($env{'form.pagepath'}) {
956: @folders = split('&',$env{'form.pagepath'});
1.142 raeburn 957: } else {
1.174 albertel 958: @folders=split('&',$env{'form.folderpath'});
1.142 raeburn 959: }
1.116 albertel 960: my $folderpath;
1.168 www 961: my $cpinfo='';
1.251 www 962: my $plain='';
1.242 www 963: my $randompick=-1;
964: my $isencrypted=0;
965: my $ishidden=0;
1.116 albertel 966: while (@folders) {
967: my $folder=shift(@folders);
968: my $foldername=shift(@folders);
969: if ($folderpath) {$folderpath.='&';}
970: $folderpath.=$folder.'&'.$foldername;
971: my $url='/adm/coursedocs?folderpath='.
1.228 www 972: &escape($folderpath);
1.242 www 973: my $name=&unescape($foldername);
974: # randompick number, hidden, encrypted is appended with ":"s to the foldername
975: $name=~s/\:(\d*)\:(\w*)\:(\w*)$//;
976: if ($1 ne '') {
977: $randompick=$1;
978: } else {
979: $randompick=-1;
980: }
981: if ($2) { $ishidden=1; }
982: if ($3) { $isencrypted=1; }
1.114 albertel 983: &Apache::lonhtmlcommon::add_breadcrumb(
1.168 www 984: {'href'=>$url.$cpinfo,
1.242 www 985: 'title'=>$name,
1.117 albertel 986: 'text'=>'<font size="+1">'.
1.266 albertel 987: $name.'</font>',
988: 'no_mt'=>1,
1.117 albertel 989: });
1.251 www 990: $plain.=$name.' > ';
1.114 albertel 991: }
1.251 www 992: $plain=~s/\>\;\s*$//;
1.242 www 993: return (&Apache::lonhtmlcommon::breadcrumbs(undef,undef,0,'nohelp',
1.251 www 994: 'LC_docs_path'),$randompick,$ishidden,$isencrypted,$plain);
1.114 albertel 995: }
996:
1.247 www 997: sub log_docs {
998: return &Apache::lonnet::instructor_log('docslog',@_);
999: }
1000:
1001: {
1002: my @oldresources=();
1003: my @oldorder=();
1004: my $parmidx;
1005: my %parmaction=();
1006: my %parmvalue=();
1.249 www 1007: my $changedflag;
1.247 www 1008:
1009: sub snapshotbefore {
1.248 albertel 1010: @oldresources=@LONCAPA::map::resources;
1011: @oldorder=@LONCAPA::map::order;
1.247 www 1012: $parmidx=undef;
1013: %parmaction=();
1014: %parmvalue=();
1.249 www 1015: $changedflag=0;
1.247 www 1016: }
1017:
1018: sub remember_parms {
1019: my ($idx,$parameter,$action,$value)=@_;
1020: $parmidx=$idx;
1021: $parmaction{$parameter}=$action;
1022: $parmvalue{$parameter}=$value;
1.249 www 1023: $changedflag=1;
1.247 www 1024: }
1025:
1026: sub log_differences {
1.251 www 1027: my ($plain)=@_;
1.260 www 1028: my %storehash=('folder' => $plain,
1029: 'currentfolder' => $env{'form.folder'});
1.247 www 1030: if ($parmidx) {
1031: $storehash{'parameter_res'}=$oldresources[$parmidx];
1032: foreach my $parm (keys %parmaction) {
1033: $storehash{'parameter_action_'.$parm}=$parmaction{$parm};
1034: $storehash{'parameter_value_'.$parm}=$parmvalue{$parm};
1035: }
1036: }
1037: my $maxidx=$#oldresources;
1.248 albertel 1038: if ($#LONCAPA::map::resources>$#oldresources) {
1039: $maxidx=$#LONCAPA::map::resources;
1.247 www 1040: }
1041: for (my $idx=0; $idx<=$maxidx; $idx++) {
1042: if ($LONCAPA::map::resources[$idx] ne $oldresources[$idx]) {
1043: $storehash{'before_resources_'.$idx}=$oldresources[$idx];
1044: $storehash{'after_resources_'.$idx}=$LONCAPA::map::resources[$idx];
1.249 www 1045: $changedflag=1;
1.247 www 1046: }
1047: if ($LONCAPA::map::order[$idx] ne $oldorder[$idx]) {
1.252 www 1048: $storehash{'before_order_res_'.$idx}=$oldresources[$oldorder[$idx]];
1049: $storehash{'after_order_res_'.$idx}=$LONCAPA::map::resources[$LONCAPA::map::order[$idx]];
1.249 www 1050: $changedflag=1;
1.247 www 1051: }
1052: }
1.251 www 1053: $storehash{'maxidx'}=$maxidx;
1.249 www 1054: if ($changedflag) { &log_docs(\%storehash); }
1.247 www 1055: }
1056: }
1057:
1058:
1059: #
1060: # Docs Change Log
1061: #
1062: sub docs_change_log {
1063: my ($r)=@_;
1.260 www 1064: my $folder=$env{'form.folder'};
1.247 www 1065: $r->print(&Apache::loncommon::start_page('Course Document Change Log'));
1066: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Document Change Log'));
1067: my %docslog=&Apache::lonnet::dump('nohist_docslog',
1068: $env{'course.'.$env{'request.course.id'}.'.domain'},
1069: $env{'course.'.$env{'request.course.id'}.'.num'});
1.254 albertel 1070:
1.247 www 1071: if ((keys(%docslog))[0]=~/^error\:/) { undef(%docslog); }
1.254 albertel 1072:
1.247 www 1073: $r->print('<form action="/adm/coursedocs" method="post" name="docslog">'.
1074: '<input type="hidden" name="docslog" value="1" />');
1.254 albertel 1075:
1.247 www 1076: my %saveable_parameters = ('show' => 'scalar',);
1077: &Apache::loncommon::store_course_settings('docs_log',
1078: \%saveable_parameters);
1079: &Apache::loncommon::restore_course_settings('docs_log',
1080: \%saveable_parameters);
1081: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.254 albertel 1082: my %lt=('hiddenresource' => 'Resources hidden',
1083: 'encrypturl' => 'URL hidden',
1084: 'randompick' => 'Randomly pick',
1085: 'set' => 'set to',
1086: 'del' => 'deleted');
1.259 www 1087: $r->print(&Apache::loncommon::display_filter().
1.260 www 1088: '<input type="hidden" name="folder" value="'.$folder.'" />'.
1.247 www 1089: '<input type="submit" value="'.&mt('Display').'" /></form>');
1090: $r->print(&Apache::loncommon::start_data_table().&Apache::loncommon::start_data_table_header_row().
1.251 www 1091: '<th>'.&mt('Time').'</th><th>'.&mt('User').'</th><th>'.&mt('Folder').'</th><th>'.&mt('Before').'</th><th>'.
1092: &mt('After').'</th>'.
1.247 www 1093: &Apache::loncommon::end_data_table_header_row());
1094: my $shown=0;
1095: foreach my $id (sort { $docslog{$b}{'exe_time'}<=>$docslog{$a}{'exe_time'} } (keys(%docslog))) {
1.260 www 1096: if ($env{'form.displayfilter'} eq 'currentfolder') {
1097: if ($docslog{$id}{'logentry'}{'currentfolder'} ne $folder) { next; }
1098: }
1.247 www 1099: my @changes=keys(%{$docslog{$id}{'logentry'}});
1.261 www 1100: if ($env{'form.displayfilter'} eq 'containing') {
1101: my $wholeentry=$docslog{$id}{'exe_uname'}.':'.$docslog{$id}{'exe_udom'}.':'.
1102: &Apache::loncommon::plainname($docslog{$id}{'exe_uname'},$docslog{$id}{'exe_udom'});
1103: foreach my $key (@changes) {
1104: $wholeentry.=':'.$docslog{$id}{'logentry'}{$key};
1105: }
1106: if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; }
1107: }
1.247 www 1108: my $count = 0;
1109: my $time =
1110: &Apache::lonlocal::locallocaltime($docslog{$id}{'exe_time'});
1111: my $plainname =
1112: &Apache::loncommon::plainname($docslog{$id}{'exe_uname'},
1113: $docslog{$id}{'exe_udom'});
1114: my $about_me_link =
1115: &Apache::loncommon::aboutmewrapper($plainname,
1116: $docslog{$id}{'exe_uname'},
1117: $docslog{$id}{'exe_udom'});
1118: my $send_msg_link='';
1119: if ((($docslog{$id}{'exe_uname'} ne $env{'user.name'})
1120: || ($docslog{$id}{'exe_udom'} ne $env{'user.domain'}))) {
1121: $send_msg_link ='<br />'.
1122: &Apache::loncommon::messagewrapper(&mt('Send message'),
1123: $docslog{$id}{'exe_uname'},
1124: $docslog{$id}{'exe_udom'});
1125: }
1126: $r->print(&Apache::loncommon::start_data_table_row());
1127: $r->print('<td>'.$time.'</td>
1128: <td>'.$about_me_link.
1129: '<br /><tt>'.$docslog{$id}{'exe_uname'}.
1130: ':'.$docslog{$id}{'exe_udom'}.'</tt>'.
1.249 www 1131: $send_msg_link.'</td><td>'.
1.251 www 1132: $docslog{$id}{'logentry'}{'folder'}.'</td><td>');
1133: # Before
1134: for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
1135: my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0];
1136: my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0];
1137: if ($oldname ne $newname) {
1.252 www 1138: $r->print(&LONCAPA::map::qtescape($oldname));
1.251 www 1139: }
1140: }
1.252 www 1141: $r->print('<ul>');
1142: for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
1143: if ($docslog{$id}{'logentry'}{'before_order_res_'.$idx}) {
1144: $r->print('<li>'.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'before_order_res_'.$idx}))[0]).'</li>');
1145: }
1146: }
1147: $r->print('</ul>');
1.251 www 1148: # After
1149: $r->print('</td><td>');
1150:
1151: for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
1152: my $oldname=(split(/\:/,$docslog{$id}{'logentry'}{'before_resources_'.$idx}))[0];
1153: my $newname=(split(/\:/,$docslog{$id}{'logentry'}{'after_resources_'.$idx}))[0];
1.279 albertel 1154: if ($oldname ne '' && $oldname ne $newname) {
1.252 www 1155: $r->print(&LONCAPA::map::qtescape($newname));
1.251 www 1156: }
1157: }
1.252 www 1158: $r->print('<ul>');
1159: for (my $idx=0;$idx<=$docslog{$id}{'logentry'}{'maxidx'};$idx++) {
1160: if ($docslog{$id}{'logentry'}{'after_order_res_'.$idx}) {
1161: $r->print('<li>'.&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'after_order_res_'.$idx}))[0]).'</li>');
1162: }
1163: }
1164: $r->print('</ul>');
1165: if ($docslog{$id}{'logentry'}{'parameter_res'}) {
1166: $r->print(&LONCAPA::map::qtescape((split(/\:/,$docslog{$id}{'logentry'}{'parameter_res'}))[0]).':<ul>');
1.253 www 1167: foreach my $parameter ('randompick','hiddenresource','encrypturl') {
1.252 www 1168: if ($docslog{$id}{'logentry'}{'parameter_action_'.$parameter}) {
1.254 albertel 1169: $r->print('<li>'.
1170: &mt($lt{$parameter}.' '.$lt{$docslog{$id}{'logentry'}{'parameter_action_'.$parameter}}.' [_1]',
1171: $docslog{$id}{'logentry'}{'parameter_value_'.$parameter})
1172: .'</li>');
1.252 www 1173: }
1174: }
1175: $r->print('</ul>');
1176: }
1.251 www 1177: # End
1178: $r->print('</td>'.&Apache::loncommon::end_data_table_row());
1.247 www 1179: $shown++;
1180: if (!($env{'form.show'} eq &mt('all')
1181: || $shown<=$env{'form.show'})) { last; }
1182: }
1183: $r->print(&Apache::loncommon::end_data_table());
1184: }
1185:
1.281 albertel 1186: sub update_paste_buffer {
1187: my ($coursenum,$coursedom) = @_;
1188:
1189: return if (!defined($env{'form.markcopy'}));
1190: return if (!defined($env{'form.copyfolder'}));
1191: return if ($env{'form.markcopy'} < 0);
1192:
1193: my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
1194: $env{'form.copyfolder'});
1195:
1196: return if ($fatal);
1197:
1198: # Mark for copying
1199: my ($title,$url)=split(':',$LONCAPA::map::resources[$LONCAPA::map::order[$env{'form.markcopy'}]]);
1200: if (&is_supplemental_title($title)) {
1201: ($title) = &parse_supplemental_title($title);
1202: }
1.287 albertel 1203: $url=~s{http(:|:)//https(:|:)//}{https$2//};
1204:
1.281 albertel 1205: &Apache::lonnet::appenv('docs.markedcopy_title' => $title,
1206: 'docs.markedcopy_url' => $url);
1207: delete($env{'form.markcopy'});
1208: }
1209:
1210: sub print_paste_buffer {
1211: my ($r,$container) = @_;
1212: return if (!defined($env{'docs.markedcopy_url'}));
1213:
1214: $r->print(<<ENDPASTE);
1.286 albertel 1215: <form name="pasteform" action="/adm/coursedocs" method="post"><p>
1.281 albertel 1216: ENDPASTE
1217: $r->print('<input type="submit" name="pastemarked" value="'.&mt('Paste').'" /> ');
1218:
1219: my $type;
1.287 albertel 1220: if ($env{'docs.markedcopy_url'} =~ m{^(?:/adm/wrapper/ext|(?:http|https)(?::|:))//} ) {
1.281 albertel 1221: $type = &mt('External Resource');
1.287 albertel 1222: $r->print($type.': '.
1223: &LONCAPA::map::qtescape($env{'docs.markedcopy_title'}).' ('.
1224: &LONCAPA::map::qtescape($env{'docs.markedcopy_url'}).')');
1.281 albertel 1225: } else {
1226: my $extension = (split(/\./,$env{'docs.markedcopy_url'}))[-1];
1227: my $type = &Apache::loncommon::filedescription($extension);
1228: my $icon = '<img src="'.&Apache::loncommon::icon($extension).
1.286 albertel 1229: '" alt="" class="LC_icon" />';
1.287 albertel 1230: $r->print($icon.$type.': '. &parse_supplemental_title(&LONCAPA::map::qtescape($env{'docs.markedcopy_title'})));
1.281 albertel 1231: }
1232: if ($container eq 'page') {
1.286 albertel 1233: $r->print('
1234: <input type="hidden" name="pagepath" value="'.&HTML::Entities::encode($env{'form.pagepath'},'<>&"').'" />
1235: <input type="hidden" name="pagesymb" value="'.&HTML::Entities::encode($env{'form.pagesymb'},'<>&"').'" />
1236: ');
1.281 albertel 1237: } else {
1.286 albertel 1238: $r->print('
1239: <input type="hidden" name="folderpath" value="'.&HTML::Entities::encode($env{'form.folderpath'},'<>&"').'" />
1240: ');
1.281 albertel 1241: }
1.286 albertel 1242: $r->print('</p></form>');
1.281 albertel 1243: }
1244:
1.289 albertel 1245: sub do_paste_from_buffer {
1.292 albertel 1246: my ($coursenum,$coursedom) = @_;
1247:
1248: return 0 if (!$env{'form.pastemarked'});
1249:
1.289 albertel 1250: # paste resource to end of list
1251: my $url=&LONCAPA::map::qtescape($env{'docs.markedcopy_url'});
1252: my $title=&LONCAPA::map::qtescape($env{'docs.markedcopy_title'});
1253: # Maps need to be copied first
1254: if (($url=~/\.(page|sequence)$/) && ($url=~/^\/uploaded\//)) {
1255: $title=&mt('Copy of').' '.$title;
1256: my $newid=$$.time;
1257: $url=~/^(.+)\.(\w+)$/;
1258: my $newurl=$1.$newid.'.'.$2;
1259: my $storefn=$newurl;
1260: $storefn=~s{^/\w+/$match_domain/$match_username/}{};
1261: &Apache::lonclonecourse::writefile($env{'request.course.id'},$storefn,
1262: &Apache::lonnet::getfile($url));
1263: $url = $newurl;
1264: }
1.290 albertel 1265: # published maps can only exists once, so remove it from paste buffer when done
1.289 albertel 1266: if (($url=~/\.(page|sequence)$/) && ($url=~m {^/res/})) {
1267: &Apache::lonnet::delenv('docs\\.markedcopy');
1268: }
1.290 albertel 1269: if ($url=~ m{/smppg$}) {
1270: my $db_name = &Apache::lonsimplepage::get_db_name($url);
1271: if ($db_name =~ /^smppage_/) {
1272: #simple pages, need to copy the db contents to a new one.
1273: my %contents=&Apache::lonnet::dump($db_name,$coursedom,$coursenum);
1274: my $now = time();
1275: $db_name =~ s{_\d*$ }{_$now}x;
1276: my $result=&Apache::lonnet::put($db_name,\%contents,
1277: $coursedom,$coursenum);
1278: $url =~ s{/(\d*)/smppg$ }{/$now/smppg}x;
1279: $title=&mt('Copy of').' '.$title;
1280: }
1281: }
1.289 albertel 1282: $title = &LONCAPA::map::qtunescape($title);
1283: my $ext='false';
1284: if ($url=~m{^http(|s)://}) { $ext='true'; }
1285: $url = &LONCAPA::map::qtunescape($url);
1286: # Now insert the URL at the bottom
1287: my $newidx = &LONCAPA::map::getresidx($url);
1288: $LONCAPA::map::resources[$newidx]= $title.':'.$url.':'.$ext.':normal:res';
1289: push(@LONCAPA::map::order, $newidx);
1290: # Store the result
1.292 albertel 1291: }
1292:
1293: my %parameter_type = ( 'randompick' => 'int_pos',
1294: 'hiddenresource' => 'string_yesno',
1295: 'encrypturl' => 'string_yesno',);
1296: my $valid_parameters_re = join('|',keys(%parameter_type));
1297: # set parameters
1298: sub update_parameter {
1299:
1300: return 0 if ($env{'form.changeparms'} !~ /^($valid_parameters_re)$/);
1301:
1302: my $which = $env{'form.changeparms'};
1303: my $idx = $env{'form.setparms'};
1304: if ($env{'form.'.$which.'_'.$idx}) {
1305: my $value = ($which eq 'randompick') ? $env{'form.'.$which.'_'.$idx}
1306: : 'yes';
1307: &LONCAPA::map::storeparameter($idx, 'parameter_'.$which, $value,
1308: $parameter_type{$which});
1309: &remember_parms($idx,$which,'set',$value);
1310: } else {
1311: &LONCAPA::map::delparameter($idx,'parameter_'.$which);
1312:
1313: &remember_parms($idx,$which,'del');
1314: }
1315: return 1;
1316: }
1317:
1318:
1319: sub handle_edit_cmd {
1320: my ($coursenum,$coursedom) =@_;
1321:
1322: my ($cmd,$idx)=split('_',$env{'form.cmd'});
1323:
1324: my $ratstr = $LONCAPA::map::resources[$LONCAPA::map::order[$idx]];
1325: my ($title, $url, @rrest) = split(':', $ratstr);
1326:
1327: if ($cmd eq 'del') {
1328: if (($url=~m|/+uploaded/\Q$coursedom\E/\Q$coursenum\E/|) &&
1329: ($url!~/\.(page|sequence|problem|exam|quiz|assess|survey|form|library|task)$/)) {
1330: &Apache::lonnet::removeuploadedurl($url);
1331: } else {
1332: &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]);
1333: }
1334: splice(@LONCAPA::map::order, $idx, 1);
1335:
1336: } elsif ($cmd eq 'cut') {
1337: &LONCAPA::map::makezombie($LONCAPA::map::order[$idx]);
1338: splice(@LONCAPA::map::order, $idx, 1);
1339:
1340: } elsif ($cmd eq 'up'
1341: && ($idx) && (defined($LONCAPA::map::order[$idx-1]))) {
1342: @LONCAPA::map::order[$idx-1,$idx] = @LONCAPA::map::order[$idx,$idx-1];
1343:
1344: } elsif ($cmd eq 'down'
1345: && defined($LONCAPA::map::order[$idx+1])) {
1346: @LONCAPA::map::order[$idx+1,$idx] = @LONCAPA::map::order[$idx,$idx+1];
1347:
1348: } elsif ($cmd eq 'rename') {
1349:
1350: my $comment = &LONCAPA::map::qtunescape($env{'form.title'});
1351: if ($comment=~/\S/) {
1352: $LONCAPA::map::resources[$LONCAPA::map::order[$idx]]=
1353: $comment.':'.join(':', $url, @rrest);
1354: }
1355: # Devalidate title cache
1356: my $renamed_url=&LONCAPA::map::qtescape($url);
1357: &Apache::lonnet::devalidate_title_cache($renamed_url);
1358: } else {
1359: return 0;
1360: }
1361: return 1;
1.289 albertel 1362: }
1363:
1.7 www 1364: sub editor {
1.281 albertel 1365: my ($r,$coursenum,$coursedom,$folder,$allowed,$upload_output,$which)=@_;
1.292 albertel 1366:
1367: my $container= ($env{'form.pagepath'}) ? 'page'
1368: : 'sequence';
1369:
1370: my ($errtext,$fatal) = &mapread($coursenum,$coursedom,
1371: $folder.'.'.$container);
1372: return $errtext if ($fatal);
1373:
1.245 albertel 1374: if ($#LONCAPA::map::order<1) {
1375: my $idx=&LONCAPA::map::getresidx();
1.178 www 1376: if ($idx<=0) { $idx=1; }
1.245 albertel 1377: $LONCAPA::map::order[0]=$idx;
1378: $LONCAPA::map::resources[$idx]='';
1.17 www 1379: }
1.281 albertel 1380:
1.292 albertel 1381: my ($breadcrumbtrail,$randompick,$ishidden,$isencrypted,$plain)=
1382: &breadcrumbs($folder);
1.242 www 1383: $r->print($breadcrumbtrail);
1.292 albertel 1384:
1.7 www 1385: # ------------------------------------------------------------ Process commands
1.121 www 1386:
1.16 www 1387: # ---------------- if they are for this folder and user allowed to make changes
1.292 albertel 1388: if (($allowed) && ($env{'form.folder'} eq $folder)) {
1.123 www 1389: # set parameters and change order
1.292 albertel 1390: &snapshotbefore();
1391:
1392: if (&update_parameter()) {
1393: ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container);
1394: return $errtext if ($fatal);
1395: }
1.121 www 1396:
1.292 albertel 1397: if ($env{'form.newpos'} && $env{'form.currentpos'}) {
1.123 www 1398: # change order
1.292 albertel 1399: my $res = splice(@LONCAPA::map::order,$env{'form.currentpos'}-1,1);
1400: splice(@LONCAPA::map::order,$env{'form.newpos'}-1,0,$res);
1401:
1402: ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container);
1403: return $errtext if ($fatal);
1404: }
1405:
1406: if ($env{'form.pastemarked'}) {
1407: &do_paste_from_buffer($coursenum,$coursedom);
1408: ($errtext,$fatal) = &storemap($coursenum,$coursedom,$folder.'.'.$container);
1409: return $errtext if ($fatal);
1410: }
1411:
1412: $r->print($upload_output);
1413:
1414: if (&handle_edit_cmd()) {
1415: ($errtext,$fatal)=&storemap($coursenum,$coursedom,$folder.'.'.$container);
1416: return $errtext if ($fatal);
1417: }
1418: # Group import/search
1419: if ($env{'form.importdetail'}) {
1420: my @imports;
1421: foreach (split(/\&/,$env{'form.importdetail'})) {
1422: if (defined($_)) {
1423: my ($name,$url,$residx)=
1424: map {&unescape($_)} split(/\=/,$_);
1425: push(@imports, [$name, $url, $residx]);
1.123 www 1426: }
1.247 www 1427: }
1.292 albertel 1428: ($errtext,$fatal)=&group_import($coursenum, $coursedom, $folder,
1429: $container,'londocs',@imports);
1430: return $errtext if ($fatal);
1431: }
1432: # Loading a complete map
1433: if ($env{'form.loadmap'}) {
1434: if ($env{'form.importmap'}=~/\w/) {
1435: foreach my $res (&Apache::lonsequence::attemptread(&Apache::lonnet::filelocation('',$env{'form.importmap'}))) {
1436: my ($title,$url,$ext,$type)=split(/\:/,$res);
1437: my $idx=&LONCAPA::map::getresidx($url);
1438: $LONCAPA::map::resources[$idx]=$res;
1439: $LONCAPA::map::order[$#LONCAPA::map::order+1]=$idx;
1.168 www 1440: }
1.104 albertel 1441: ($errtext,$fatal)=&storemap($coursenum,$coursedom,
1.142 raeburn 1442: $folder.'.'.$container);
1.292 albertel 1443: return $errtext if ($fatal);
1444: } else {
1445: $r->print('<p><span class="LC_error">'.&mt('No map selected.').'</span></p>');
1446:
1447: }
1.281 albertel 1448: }
1.292 albertel 1449: &log_differences($plain);
1450: }
1.16 www 1451: # ---------------------------------------------------------------- End commands
1.7 www 1452: # ---------------------------------------------------------------- Print screen
1.292 albertel 1453: my $idx=0;
1454: my $shown=0;
1455: if (($ishidden) || ($isencrypted) || ($randompick>=0)) {
1456: $r->print('<p>'.&mt('Parameters').':<ul>'.
1457: ($randompick>=0?'<li>'.&mt('randomly pick [_1] resources',$randompick).'</li>':'').
1458: ($ishidden?'<li>'.&mt('contents hidden').'</li>':'').
1459: ($isencrypted?'<li>'.&mt('URLs hidden').'</li>':'').
1460: '</ul></p>');
1461: }
1462: if ($randompick>=0) {
1463: $r->print('<p>'.&mt('Caution: this folder is set to randomly pick a subset of resources. Adding or removing resources from this folder will change the set of resources that the students see, resulting in spurious or missing credit for completed problems, not limited to ones you modify. Do not modify the contents of this folder if it is in active student use.').'</p>');
1464: }
1465: $r->print('<table class="LC_docs_editor">');
1466: foreach my $res (@LONCAPA::map::order) {
1467: my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$res]);
1468: $name=&LONCAPA::map::qtescape($name);
1469: $url=&LONCAPA::map::qtescape($url);
1470: unless ($name) { $name=(split(/\//,$url))[-1]; }
1471: unless ($name) { $idx++; next; }
1472: $r->print(&entryline($idx,$name,$url,$folder,$allowed,$res,
1473: $coursenum));
1474: $idx++;
1475: $shown++;
1476: }
1477: unless ($shown) {
1478: $r->print('<tr><td>'.&mt('Currently no documents.').'</td></tr>');
1.7 www 1479: }
1.292 albertel 1480: $r->print("\n</table>\n");
1481:
1482: &print_paste_buffer($r,$container);
1483: return;
1.7 www 1484: }
1.1 www 1485:
1.188 raeburn 1486: sub process_file_upload {
1.194 raeburn 1487: my ($upload_output,$coursenum,$coursedom,$allfiles,$codebase,$uploadcmd) = @_;
1.188 raeburn 1488: # upload a file, if present
1489: my $parseaction;
1.190 albertel 1490: if ($env{'form.parserflag'}) {
1.188 raeburn 1491: $parseaction = 'parse';
1492: }
1493: my $phase_status;
1494: my $folder=$env{'form.folder'};
1.194 raeburn 1495: if ($folder eq '') {
1.188 raeburn 1496: $folder='default';
1497: }
1.194 raeburn 1498: if ( ($folder=~/^$uploadcmd/) || ($uploadcmd eq 'default') ) {
1.188 raeburn 1499: my $errtext='';
1500: my $fatal=0;
1501: my $container='sequence';
1502: if ($env{'form.pagepath'}) {
1503: $container='page';
1504: }
1505: ($errtext,$fatal)=
1506: &mapread($coursenum,$coursedom,$folder.'.'.$container);
1.245 albertel 1507: if ($#LONCAPA::map::order<1) {
1508: $LONCAPA::map::order[0]=1;
1509: $LONCAPA::map::resources[1]='';
1.188 raeburn 1510: }
1511: if ($fatal) {
1512: return 'failed';
1513: }
1514: my $destination = 'docs/';
1.194 raeburn 1515: if ($folder =~ /^supplemental/) {
1516: $destination = 'supplemental/';
1517: }
1518: if (($folder eq 'default') || ($folder eq 'supplemental')) {
1.188 raeburn 1519: $destination .= 'default/';
1.194 raeburn 1520: } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) {
1521: $destination .= $2.'/';
1.188 raeburn 1522: }
1523: # this is for a course, not a user, so set coursedoc flag
1524: # probably the only place in the system where this should be "1"
1.245 albertel 1525: my $newidx=&LONCAPA::map::getresidx();
1.188 raeburn 1526: $destination .= $newidx;
1.190 albertel 1527: my $url=&Apache::lonnet::userfileupload('uploaddoc',1,$destination,
1528: $parseaction,$allfiles,
1529: $codebase);
1.188 raeburn 1530: my $ext='false';
1.287 albertel 1531: if ($url=~m{^http://}) { $ext='true'; }
1.270 albertel 1532: $url = &LONCAPA::map::qtunescape($url);
1.188 raeburn 1533: my $comment=$env{'form.comment'};
1.270 albertel 1534: $comment = &LONCAPA::map::qtunescape($comment);
1.188 raeburn 1535: if ($folder=~/^supplemental/) {
1536: $comment=time.'___&&&___'.$env{'user.name'}.'___&&&___'.
1537: $env{'user.domain'}.'___&&&___'.$comment;
1538: }
1539:
1.245 albertel 1540: $LONCAPA::map::resources[$newidx]=
1541: $comment.':'.$url.':'.$ext.':normal:res';
1542: $LONCAPA::map::order[$#LONCAPA::map::order+1]= $newidx;
1.190 albertel 1543: ($errtext,$fatal)=&storemap($coursenum,$coursedom,
1544: $folder.'.'.$container);
1.188 raeburn 1545: if ($fatal) {
1.283 albertel 1546: $$upload_output .= '<p><span class="LC_error">'.$errtext.'</span></p>';
1.188 raeburn 1547: return 'failed';
1548: } else {
1549: if ($parseaction eq 'parse') {
1.190 albertel 1550: my $total_embedded = keys(%{$allfiles});
1.188 raeburn 1551: if ($total_embedded > 0) {
1552: my $num = 0;
1.269 albertel 1553: my $state = '
1.282 albertel 1554: <input type="hidden" name="folderpath" value="'.&HTML::Entities::encode($env{'form.folderpath'},'<>&"').'" />
1.269 albertel 1555: <input type="hidden" name="cmd" value="upload_embedded" />
1.188 raeburn 1556: <input type="hidden" name="newidx" value="'.$newidx.'" />
1.228 www 1557: <input type="hidden" name="primaryurl" value="'.&escape($url).'" />
1.188 raeburn 1558: <input type="hidden" name="phasetwo" value="'.$total_embedded.'" />';
1.269 albertel 1559: $phase_status = 'phasetwo';
1560:
1561: $$upload_output .=
1562: 'This file contains embedded multimedia objects, which need to be uploaded to LON-CAPA.<br />'.
1563: &ask_for_embedded_content('/adm/coursedocs',
1564: $state,$allfiles,$codebase);
1.188 raeburn 1565: } else {
1566: $$upload_output .= 'No embedded items identified<br />';
1567: }
1568: }
1569: }
1570: }
1571: return $phase_status;
1572: }
1573:
1.269 albertel 1574: sub ask_for_embedded_content {
1.271 albertel 1575: my ($actionurl,$state,$allfiles,$codebase,$args)=@_;
1.269 albertel 1576: my $upload_output = '
1577: <form name="upload_embedded" action="'.$actionurl.'"
1578: method="post" enctype="multipart/form-data">';
1579: $upload_output .= $state;
1.271 albertel 1580: $upload_output .= '<b>Upload embedded files</b>:<br />'.
1581: &Apache::loncommon::start_data_table();
1.269 albertel 1582:
1583: my $num = 0;
1.276 albertel 1584: foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%{$allfiles})) {
1.271 albertel 1585: $upload_output .= &Apache::loncommon::start_data_table_row().
1586: '<td>'.$embed_file.'</td><td>';
1.274 albertel 1587: if ($args->{'ignore_remote_references'}
1588: && $embed_file =~ m{^\w+://}) {
1589: $upload_output.='<span class="LC_warning">'.&mt("URL points to other server.").'</span>';
1590: } elsif ($args->{'error_on_invalid_names'}
1.271 albertel 1591: && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) {
1592:
1593: $upload_output.='<span class="LC_warning">'.&mt("Invalid characters").'</span>';
1.274 albertel 1594:
1.271 albertel 1595: } else {
1.274 albertel 1596:
1.271 albertel 1597: $upload_output .='
1.269 albertel 1598: <input name="embedded_item_'.$num.'" type="file" value="bob" />
1599: <input name="embedded_orig_'.$num.'" type="hidden" value="'.&escape($embed_file).'" />';
1.271 albertel 1600: my $attrib = join(':',@{$$allfiles{$embed_file}});
1601: $upload_output .=
1.269 albertel 1602: "\n\t\t".
1.271 albertel 1603: '<input name="embedded_attrib_'.$num.'" type="hidden" value="'.
1604: $attrib.'" />';
1605: if (exists($$codebase{$embed_file})) {
1606: $upload_output .=
1607: "\n\t\t".
1608: '<input name="codebase_'.$num.'" type="hidden" value="'.
1609: &escape($$codebase{$embed_file}).'" />';
1610: }
1.269 albertel 1611: }
1.271 albertel 1612: $upload_output .= '</td>'.&Apache::loncommon::end_data_table_row();
1.269 albertel 1613: $num++;
1614: }
1.271 albertel 1615: $upload_output .= &Apache::loncommon::end_data_table().'<br />
1.269 albertel 1616: <input type ="hidden" name="number_embedded_items" value="'.$num.'" />
1.275 albertel 1617: <input type ="submit" value="'.&mt('Upload Listed Files').'" />
1618: '.&mt('(only files for which a location has been provided will be uploaded)').'
1.269 albertel 1619: </form>';
1620: return $upload_output;
1621: }
1622:
1.188 raeburn 1623: sub process_secondary_uploads {
1624: my ($upload_output,$coursedom,$coursenum,$formname,$num,$newidx) = @_;
1625: my $folder=$env{'form.folder'};
1626: my $destination = 'docs/';
1.195 raeburn 1627: if ($folder =~ /^supplemental/) {
1628: $destination = 'supplemental/';
1629: }
1630: if (($folder eq 'default') || ($folder eq 'supplemental')) {
1.188 raeburn 1631: $destination .= 'default/';
1.195 raeburn 1632: } elsif ($folder =~ /^(default|supplemental)_(\d+)$/) {
1.217 raeburn 1633: $destination .= $2.'/';
1.188 raeburn 1634: }
1635: $destination .= $newidx;
1636: my ($url,$filename);
1637: $url=&Apache::lonnet::userfileupload($formname.$num,1,$destination);
1.265 albertel 1638: ($filename) = ($url =~ m{^/uploaded/\Q$coursedom\E/\Q$coursenum\E/\Q$destination\E/(.+)$});
1.188 raeburn 1639: return $filename;
1640: }
1641:
1.281 albertel 1642: sub is_supplemental_title {
1643: my ($title) = @_;
1644: return scalar($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/);
1645: }
1646:
1647: sub parse_supplemental_title {
1648: my ($title) = @_;
1649:
1650: my ($foldertitle,$renametitle);
1651: if ($title =~ /&&&/) {
1652: $title = &HTML::Entites::decode($title);
1653: }
1654: if ($title =~ m/^(\d+)___&&&___($match_username)___&&&___($match_domain)___&&&___(.*)$/) {
1655: $renametitle=$4;
1656: my ($time,$uname,$udom) = ($1,$2,$3);
1657: $foldertitle=&Apache::lontexconvert::msgtexconverted($4);
1658: my $name = &Apache::loncommon::plainname($uname,$udom);
1659: $name = &HTML::Entities::encode($name,'"<>&\'');
1660: $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.
1661: $name.': <br />'.$foldertitle;
1662: }
1663: if (wantarray) {
1664: return ($title,$foldertitle,$renametitle);
1665: }
1666: return $title;
1667: }
1668:
1.8 www 1669: # --------------------------------------------------------------- An entry line
1670:
1671: sub entryline {
1.112 raeburn 1672: my ($index,$title,$url,$folder,$allowed,$residx,$coursenum)=@_;
1.281 albertel 1673:
1674: my ($foldertitle,$pagetitle,$renametitle);
1675: if (&is_supplemental_title($title)) {
1676: ($title,$foldertitle,$renametitle) = &parse_supplemental_title($title);
1677: $pagetitle = $foldertitle;
1678: } else {
1679: $title=&HTML::Entities::encode($title,'"<>&\'');
1680: $renametitle=$title;
1681: $foldertitle=$title;
1682: $pagetitle=$title;
1683: }
1684:
1.245 albertel 1685: my $orderidx=$LONCAPA::map::order[$index];
1.281 albertel 1686:
1687:
1.222 albertel 1688: $renametitle=~s/\\/\\\\/g;
1.38 www 1689: $renametitle=~s/\"\;/\\\"/g;
1.286 albertel 1690: $renametitle=~s/ /%20/g;
1.8 www 1691: my $line='<tr>';
1.286 albertel 1692: my ($form_start,$form_end);
1.8 www 1693: # Edit commands
1.142 raeburn 1694: my $container;
1.280 albertel 1695: my ($container, $type, $esc_path, $path, $symb);
1.174 albertel 1696: if ($env{'form.folderpath'}) {
1.280 albertel 1697: $type = 'folder';
1.142 raeburn 1698: $container = 'sequence';
1.282 albertel 1699: $esc_path=&escape($env{'form.folderpath'});
1700: $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
1.174 albertel 1701: # $htmlfoldername=&HTML::Entities::encode($env{'form.foldername'},'<>&"');
1.120 www 1702: }
1.174 albertel 1703: if ($env{'form.pagepath'}) {
1.280 albertel 1704: $type = $container = 'page';
1705: $esc_path=&escape($path = $env{'form.pagepath'});
1.282 albertel 1706: $path = &HTML::Entities::encode($env{'form.pagepath'},'<>&"');
1.280 albertel 1707: $symb=&escape($env{'form.pagesymb'});
1.142 raeburn 1708: }
1.168 www 1709: my $cpinfo='';
1.109 albertel 1710: if ($allowed) {
1.123 www 1711: my $incindex=$index+1;
1712: my $selectbox='';
1.168 www 1713: if (($folder!~/^supplemental/) &&
1.245 albertel 1714: ($#LONCAPA::map::order>0) &&
1.168 www 1715: ((split(/\:/,
1.245 albertel 1716: $LONCAPA::map::resources[$LONCAPA::map::order[0]]))[1]
1.168 www 1717: ne '') &&
1718: ((split(/\:/,
1.245 albertel 1719: $LONCAPA::map::resources[$LONCAPA::map::order[1]]))[1]
1.168 www 1720: ne '')) {
1.123 www 1721: $selectbox=
1.124 www 1722: '<input type="hidden" name="currentpos" value="'.$incindex.'" />'.
1.123 www 1723: '<select name="newpos" onChange="this.form.submit()">';
1.245 albertel 1724: for (my $i=1;$i<=$#LONCAPA::map::order+1;$i++) {
1.123 www 1725: if ($i==$incindex) {
1726: $selectbox.='<option value="" selected="1">('.$i.')</option>';
1727: } else {
1728: $selectbox.='<option value="'.$i.'">'.$i.'</option>';
1729: }
1730: }
1731: $selectbox.='</select>';
1732: }
1.119 www 1733: my %lt=&Apache::lonlocal::texthash(
1734: 'up' => 'Move Up',
1.109 albertel 1735: 'dw' => 'Move Down',
1736: 'rm' => 'Remove',
1.171 www 1737: 'ct' => 'Cut',
1.168 www 1738: 'rn' => 'Rename',
1739: 'cp' => 'Copy');
1.211 www 1740: my $nocopy=0;
1.268 www 1741: my $nocut=0;
1.211 www 1742: if ($url=~/\.(page|sequence)$/) {
1.289 albertel 1743: if ($url =~ m{/res/}) {
1744: # no copy for published maps
1745: $nocopy = 1;
1746: } else {
1747: foreach (&Apache::lonsequence::attemptread(&Apache::lonnet::filelocation('',$url))) {
1748: my ($title,$url,$ext,$type)=split(/\:/,$_);
1749: if (($url=~/\.(page|sequence)/) && ($type ne 'zombie')) {
1750: $nocopy=1;
1751: last;
1752: }
1.211 www 1753: }
1754: }
1755: }
1.268 www 1756: if ($url=~/^\/res\/lib\/templates\//) {
1757: $nocopy=1;
1758: $nocut=1;
1759: }
1.211 www 1760: my $copylink=' ';
1.267 www 1761: my $cutlink=' ';
1.280 albertel 1762:
1.291 albertel 1763: my $skip_confirm = 0;
1764: if ( $folder =~ /^supplemental/
1765: || ($url =~ m{( /smppg$
1766: |/syllabus$
1767: |/aboutme$
1768: |/navmaps$
1769: |/bulletinboard$
1770: |\.html$
1771: |^/adm/wrapper/ext)}x)) {
1772: $skip_confirm = 1;
1773: }
1774:
1.280 albertel 1775: if (!$nocopy) {
1776: $copylink=(<<ENDCOPY);
1.284 albertel 1777: <a href='javascript:markcopy("$esc_path","$index","$renametitle","$container","$symb","$folder");' class="LC_docs_copy">$lt{'cp'}</a>
1.211 www 1778: ENDCOPY
1.280 albertel 1779: }
1780: if (!$nocut) {
1781: $cutlink=(<<ENDCUT);
1.291 albertel 1782: <a href='javascript:cutres("$esc_path","$index","$renametitle","$container","$symb","$folder",$skip_confirm);' class="LC_docs_cut">$lt{'ct'}</a>
1.267 www 1783: ENDCUT
1.280 albertel 1784: }
1.286 albertel 1785: $form_start = (<<END);
1786: <form action="/adm/coursedocs" method="post">
1.280 albertel 1787: <input type="hidden" name="${type}path" value="$path" />
1788: <input type="hidden" name="${type}symb" value="$symb" />
1789: <input type="hidden" name="setparms" value="$orderidx" />
1790: <input type="hidden" name="changeparms" value="0" />
1.286 albertel 1791: END
1792: $form_end = '</form>';
1793: $line.=(<<END);
1.280 albertel 1794: <td>
1.285 albertel 1795: <table class="LC_docs_entry_move">
1.280 albertel 1796: <tr>
1.285 albertel 1797: <td>
1.282 albertel 1798: <a href='/adm/coursedocs?cmd=up_$index&${type}path=$esc_path&${type}symb=$symb$cpinfo'><img src="${iconpath}move_up.gif" alt='$lt{'up'}' class="LC_icon" /></a>
1.280 albertel 1799: </td>
1800: </tr>
1801: <tr>
1.285 albertel 1802: <td>
1.282 albertel 1803: <a href='/adm/coursedocs?cmd=down_$index&${type}path=$esc_path&${type}symb=$symb$cpinfo'><img src="${iconpath}move_down.gif" alt='$lt{'dw'}' class="LC_icon" /></a>
1.280 albertel 1804: </td>
1805: </tr>
1806: </table>
1807: </td>
1808: <td>
1.286 albertel 1809: $form_start
1.280 albertel 1810: $selectbox
1.286 albertel 1811: $form_end
1.280 albertel 1812: </td>
1.285 albertel 1813: <td class="LC_docs_entry_commands">
1.291 albertel 1814: <a href='javascript:removeres("$esc_path","$index","$renametitle","$container","$symb",$skip_confirm);' class="LC_docs_remove">$lt{'rm'}</a>
1.267 www 1815: $cutlink
1.284 albertel 1816: <a href='javascript:changename("$esc_path","$index","$renametitle","$container","$symb");' class="LC_docs_rename">$lt{'rn'}</a>
1.211 www 1817: $copylink
1.280 albertel 1818: </td>
1.142 raeburn 1819: END
1.280 albertel 1820:
1.8 www 1821: }
1.16 www 1822: # Figure out what kind of a resource this is
1823: my ($extension)=($url=~/\.(\w+)$/);
1824: my $uploaded=($url=~/^\/*uploaded\//);
1.97 albertel 1825: my $icon=&Apache::loncommon::icon($url);
1.17 www 1826: my $isfolder=0;
1.142 raeburn 1827: my $ispage=0;
1.114 albertel 1828: my $folderarg;
1.142 raeburn 1829: my $pagearg;
1830: my $pagefile;
1.16 www 1831: if ($uploaded) {
1.135 albertel 1832: if ($extension eq 'sequence') {
1833: $icon=$iconpath.'/folder_closed.gif';
1.264 albertel 1834: $url=~/\Q$coursenum\E\/([\/\w]+)\.sequence$/;
1.135 albertel 1835: $url='/adm/coursedocs?';
1836: $folderarg=$1;
1837: $isfolder=1;
1.142 raeburn 1838: } elsif ($extension eq 'page') {
1839: $icon=$iconpath.'/page.gif';
1.264 albertel 1840: $url=~/\Q$coursenum\E\/([\/\w]+)\.page$/;
1.142 raeburn 1841: $pagearg=$1;
1842: $url='/adm/coursedocs?';
1843: $ispage=1;
1.135 albertel 1844: } else {
1845: &Apache::lonnet::allowuploaded('/adm/coursedoc',$url);
1846: }
1.16 www 1847: }
1.287 albertel 1848:
1849: my $orig_url = $url;
1850: my $external = ($url=~s{^http(|s)(:|:)//}{/adm/wrapper/ext/});
1.142 raeburn 1851: if ((!$isfolder) && ($residx) && ($folder!~/supplemental/) && (!$ispage)) {
1.113 albertel 1852: my $symb=&Apache::lonnet::symbclean(
1.50 www 1853: &Apache::lonnet::declutter('uploaded/'.
1.174 albertel 1854: $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'.
1855: $env{'course.'.$env{'request.course.id'}.'.num'}.'/'.$folder.
1.50 www 1856: '.sequence').
1857: '___'.$residx.'___'.
1.113 albertel 1858: &Apache::lonnet::declutter($url));
1859: (undef,undef,$url)=&Apache::lonnet::decode_symb($symb);
1860: $url=&Apache::lonnet::clutter($url);
1.127 albertel 1861: if ($url=~/^\/*uploaded\//) {
1862: $url=~/\.(\w+)$/;
1863: my $embstyle=&Apache::loncommon::fileembstyle($1);
1864: if (($embstyle eq 'img') || ($embstyle eq 'emb')) {
1865: $url='/adm/wrapper'.$url;
1866: } elsif ($embstyle eq 'ssi') {
1867: #do nothing with these
1868: } elsif ($url!~/\.(sequence|page)$/) {
1869: $url='/adm/coursedocs/showdoc'.$url;
1870: }
1.145 albertel 1871: } elsif ($url=~m|^/ext/|) {
1872: $url='/adm/wrapper'.$url;
1.287 albertel 1873: $external = 1;
1.127 albertel 1874: }
1.241 www 1875: if (&Apache::lonnet::symbverify($symb,$url)) {
1876: $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($symb);
1877: } else {
1878: $url='';
1879: }
1.152 albertel 1880: if ($container eq 'page') {
1.174 albertel 1881: my $symb=$env{'form.pagesymb'};
1.152 albertel 1882:
1883: $url=&Apache::lonnet::clutter((&Apache::lonnet::decode_symb($symb))[2]);
1.228 www 1884: $url.=(($url=~/\?/)?'&':'?').'symb='.&escape($symb);
1.152 albertel 1885: }
1.50 www 1886: }
1.120 www 1887: my $parameterset=' ';
1.216 albertel 1888: if ($isfolder || $extension eq 'sequence') {
1.228 www 1889: my $foldername=&escape($foldertitle);
1.174 albertel 1890: my $folderpath=$env{'form.folderpath'};
1.114 albertel 1891: if ($folderpath) { $folderpath.='&' };
1.242 www 1892: # Append randompick number, hidden, and encrypted with ":" to foldername,
1893: # so it gets transferred between levels
1.245 albertel 1894: $folderpath.=$folderarg.'&'.$foldername.':'.(&LONCAPA::map::getparameter($orderidx,
1.242 www 1895: 'parameter_randompick'))[0]
1.245 albertel 1896: .':'.((&LONCAPA::map::getparameter($orderidx,
1.242 www 1897: 'parameter_hiddenresource'))[0]=~/^yes$/i)
1.245 albertel 1898: .':'.((&LONCAPA::map::getparameter($orderidx,
1.242 www 1899: 'parameter_encrypturl'))[0]=~/^yes$/i);
1.228 www 1900: $url.='folderpath='.&escape($folderpath).$cpinfo;
1.147 matthew 1901: $parameterset='<label>'.&mt('Randomly Pick: ').
1.292 albertel 1902: '<input type="text" size="4" onChange="this.form.changeparms.value='."'randompick'".';this.form.submit()" name="randompick_'.$orderidx.'" value="'.
1.245 albertel 1903: (&LONCAPA::map::getparameter($orderidx,
1.147 matthew 1904: 'parameter_randompick'))[0].
1.165 www 1905: '" />'.
1.285 albertel 1906: '<a href="javascript:void(0)">'.&mt('Save').'</a></label>';
1.147 matthew 1907:
1.114 albertel 1908: }
1.142 raeburn 1909: if ($ispage) {
1.228 www 1910: my $pagename=&escape($pagetitle);
1.142 raeburn 1911: my $pagepath;
1.174 albertel 1912: my $folderpath=$env{'form.folderpath'};
1.142 raeburn 1913: if ($folderpath) { $pagepath = $folderpath.'&' };
1914: $pagepath.=$pagearg.'&'.$pagename;
1.174 albertel 1915: my $symb=$env{'form.pagesymb'};
1.152 albertel 1916: if (!$symb) {
1917: my $path='uploaded/'.
1.174 albertel 1918: $env{'course.'.$env{'request.course.id'}.'.domain'}.'/'.
1919: $env{'course.'.$env{'request.course.id'}.'.num'}.'/';
1.152 albertel 1920: $symb=&Apache::lonnet::encode_symb($path.$folder.'.sequence',
1921: $residx,
1922: $path.$pagearg.'.page');
1923: }
1.228 www 1924: $url.='pagepath='.&escape($pagepath).
1.282 albertel 1925: '&pagesymb='.&escape($symb).$cpinfo;
1.142 raeburn 1926: }
1.287 albertel 1927: if ($external) {
1928: my $form = ($folder =~ /^default/)? 'newext' : 'supnewext';
1929: $external = ' <a class="LC_docs_ext_edit" href="javascript:edittext(\''.$form.'\',\''.$residx.'\',\''.&escape($title).'\',\''.&escape($orig_url).'\');" >'.&mt('Edit').'</a>';
1930: } else {
1931: undef($external);
1932: }
1.285 albertel 1933: $line.='
1934: <td class="LC_docs_entry_icon">
1.287 albertel 1935: '.($url?'<a href="'.$url.'">':'').'<img src="'.$icon.'" alt="" class="LC_icon" />'.($url?'</a>':'').'
1.285 albertel 1936: </td>
1937: <td class="LC_docs_entry_title">
1.287 albertel 1938: '.($url?"<a href=\"$url\">":'').$title.($url?'</a>':' <span class="LC_docs_reinit_warn">'.&mt('(re-initialize course to access)').'</span>').$external."
1.285 albertel 1939: </td>";
1.120 www 1940: if (($allowed) && ($folder!~/^supplemental/)) {
1941: my %lt=&Apache::lonlocal::texthash(
1942: 'hd' => 'Hidden',
1.165 www 1943: 'ec' => 'URL hidden');
1.122 www 1944: my $enctext=
1.245 albertel 1945: ((&LONCAPA::map::getparameter($orderidx,'parameter_encrypturl'))[0]=~/^yes$/i?' checked="1"':'');
1.122 www 1946: my $hidtext=
1.245 albertel 1947: ((&LONCAPA::map::getparameter($orderidx,'parameter_hiddenresource'))[0]=~/^yes$/i?' checked="1"':'');
1.120 www 1948: $line.=(<<ENDPARMS);
1.285 albertel 1949: <td class="LC_docs_entry_parameter">
1.286 albertel 1950: $form_start
1.292 albertel 1951: <label><input type="checkbox" name="hiddenresource_$orderidx" onClick="this.form.changeparms.value='hiddenresource';this.form.submit()" $hidtext /> $lt{'hd'}</label>
1.286 albertel 1952: $form_end
1.285 albertel 1953: </td>
1954: <td class="LC_docs_entry_parameter">
1.286 albertel 1955: $form_start
1.292 albertel 1956: <label><input type="checkbox" name="encrypturl_$orderidx" onClick="this.form.changeparms.value='encrypturl';this.form.submit()" $enctext /> $lt{'ec'}</label>
1.286 albertel 1957: $form_end
1.285 albertel 1958: </td>
1.286 albertel 1959: <td class="LC_docs_entry_parameter">$form_start $parameterset $form_end</td>
1.120 www 1960: ENDPARMS
1.119 www 1961: }
1.286 albertel 1962: $line.="</tr>";
1.8 www 1963: return $line;
1964: }
1965:
1.27 www 1966: # ---------------------------------------------------------------- tie the hash
1967:
1968: sub tiehash {
1.136 albertel 1969: my ($mode)=@_;
1.27 www 1970: $hashtied=0;
1.174 albertel 1971: if ($env{'request.course.fn'}) {
1.136 albertel 1972: if ($mode eq 'write') {
1.174 albertel 1973: if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db",
1.136 albertel 1974: &GDBM_WRCREAT(),0640)) {
1975: $hashtied=2;
1976: }
1977: } else {
1.174 albertel 1978: if (tie(%hash,'GDBM_File',$env{'request.course.fn'}.".db",
1.136 albertel 1979: &GDBM_READER(),0640)) {
1.27 www 1980: $hashtied=1;
1.136 albertel 1981: }
1982: }
1.27 www 1983: }
1984: }
1985:
1986: sub untiehash {
1987: if ($hashtied) { untie %hash; }
1988: $hashtied=0;
1.221 albertel 1989: return OK;
1.27 www 1990: }
1991:
1.29 www 1992: # --------------------------------------------------------------- check on this
1993:
1994: sub checkonthis {
1995: my ($r,$url,$level,$title)=@_;
1.228 www 1996: $url=&unescape($url);
1.29 www 1997: $alreadyseen{$url}=1;
1998: $r->rflush();
1.41 www 1999: if (($url) && ($url!~/^\/uploaded\//) && ($url!~/\*$/)) {
1.108 albertel 2000: $r->print("\n<br />");
1.29 www 2001: for (my $i=0;$i<=$level*5;$i++) {
2002: $r->print(' ');
2003: }
2004: $r->print('<a href="'.$url.'" target="cat">'.
2005: ($title?$title:$url).'</a> ');
2006: if ($url=~/^\/res\//) {
2007: my $result=&Apache::lonnet::repcopy(
2008: &Apache::lonnet::filelocation('',$url));
1.172 raeburn 2009: if ($result eq 'ok') {
1.87 www 2010: $r->print('<font color="green">'.&mt('ok').'</font>');
1.29 www 2011: $r->rflush();
1.34 www 2012: &Apache::lonnet::countacc($url);
2013: $url=~/\.(\w+)$/;
2014: if (&Apache::loncommon::fileembstyle($1) eq 'ssi') {
2015: $r->print('<br />');
2016: $r->rflush();
2017: for (my $i=0;$i<=$level*5;$i++) {
2018: $r->print(' ');
2019: }
1.84 www 2020: $r->print('- '.&mt('Rendering').': ');
1.170 www 2021: my ($errorcount,$warningcount)=split(/:/,
2022: &Apache::lonnet::ssi_body($url,
1.173 albertel 2023: ('grade_target'=>'web',
2024: 'return_only_error_and_warning_counts' => 1)));
1.170 www 2025: if (($errorcount) ||
2026: ($warningcount)) {
2027: if ($errorcount) {
1.283 albertel 2028: $r->print('<img src="/adm/lonMisc/bomb.gif" /><span class="LC_error">'.
1.170 www 2029: $errorcount.' '.
1.283 albertel 2030: &mt('error(s)').'</span> ');
1.34 www 2031: }
1.170 www 2032: if ($warningcount) {
1.283 albertel 2033: $r->print('<span class="LC_warning">'.
1.170 www 2034: $warningcount.' '.
1.283 albertel 2035: &mt('warning(s)').'</span>');
1.34 www 2036: }
2037: } else {
1.283 albertel 2038: $r->print('<span class="LC_success">'.&mt('ok').'</span>');
1.34 www 2039: }
2040: $r->rflush();
2041: }
1.29 www 2042: my $dependencies=
2043: &Apache::lonnet::metadata($url,'dependencies');
2044: foreach (split(/\,/,$dependencies)) {
2045: if (($_=~/^\/res\//) && (!$alreadyseen{$_})) {
2046: &checkonthis($r,$_,$level+1);
2047: }
2048: }
1.172 raeburn 2049: } elsif ($result eq 'unavailable') {
1.283 albertel 2050: $r->print('<span class="LC_error">'.&mt('connection down').'</span>');
1.172 raeburn 2051: } elsif ($result eq 'not_found') {
1.100 www 2052: unless ($url=~/\$/) {
1.283 albertel 2053: $r->print('<span class="LC_error">'.&mt('not found').'</b></font>');
1.100 www 2054: } else {
1.283 albertel 2055: $r->print('<span class="LC_unknown">'.&mt('unable to verify variable URL').'</span>');
1.100 www 2056: }
1.29 www 2057: } else {
1.283 albertel 2058: $r->print('<span class="LC_error">'.&mt('access denied').'</span>');
1.29 www 2059: }
2060: }
2061: }
2062: }
2063:
1.1 www 2064:
1.75 www 2065: #
1.208 albertel 2066: # ----------------------------------------------------------------- List Symbs
2067: #
2068: sub list_symbs {
1.224 albertel 2069: my ($r) = @_;
2070:
2071: $r->print(&Apache::loncommon::start_page('Symb List'));
1.257 www 2072: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Symb List'));
1.224 albertel 2073: my $navmap = Apache::lonnavmaps::navmap->new();
2074: $r->print("<pre>\n");
2075: foreach my $res ($navmap->retrieveResources()) {
2076: $r->print($res->compTitle()."\t".$res->symb()."\n");
2077: }
2078: $r->print("\n</pre>\n");
2079: $r->print('<a href="/adm/coursedocs">'.&mt('Return to DOCS').'</a>');
1.208 albertel 2080: }
2081:
2082:
2083: #
1.75 www 2084: # -------------------------------------------------------------- Verify Content
2085: #
2086: sub verifycontent {
1.224 albertel 2087: my ($r) = @_;
1.230 albertel 2088: my $type = &Apache::loncommon::course_type();
1.26 www 2089: my $loaderror=&Apache::lonnet::overloaderror($r);
2090: if ($loaderror) { return $loaderror; }
1.229 raeburn 2091: $r->print(&Apache::loncommon::start_page('Verify '.$type.' Documents'));
1.257 www 2092: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Verify '.$type.' Documents'));
1.27 www 2093: $hashtied=0;
1.30 www 2094: undef %alreadyseen;
2095: %alreadyseen=();
1.27 www 2096: &tiehash();
2097: foreach (keys %hash) {
1.140 www 2098: if ($hash{$_}=~/\.(page|sequence)$/) {
1.228 www 2099: if (($_=~/^src_/) && ($alreadyseen{&unescape($hash{$_})})) {
1.283 albertel 2100: $r->print('<hr /><span class="LC_error">'.
1.230 albertel 2101: &mt('The following sequence or page is included more than once in your '.$type.': ').
1.283 albertel 2102: &unescape($hash{$_}).'</span><br />'.
1.140 www 2103: &mt('Note that grading records for problems included in this sequence or folder will overlap.<hr />'));
2104: }
2105: }
1.228 www 2106: if (($_=~/^src\_(.+)$/) && (!$alreadyseen{&unescape($hash{$_})})) {
1.29 www 2107: &checkonthis($r,$hash{$_},0,$hash{'title_'.$1});
1.27 www 2108: }
2109: }
2110: &untiehash();
1.108 albertel 2111: $r->print('<h1>'.&mt('Done').'.</h1>'.'<a href="/adm/coursedocs">'.
2112: &mt('Return to DOCS').'</a>');
1.75 www 2113: }
2114:
1.192 www 2115:
1.75 www 2116: # -------------------------------------------------------------- Check Versions
2117:
1.192 www 2118: sub devalidateversioncache {
2119: my $src=shift;
2120: &Apache::lonnet::devalidate_cache_new('courseresversion',$env{'request.course.id'}.'_'.
2121: &Apache::lonnet::clutter($src));
2122: }
2123:
1.75 www 2124: sub checkversions {
1.224 albertel 2125: my ($r) = @_;
1.230 albertel 2126: my $type = &Apache::loncommon::course_type();
1.229 raeburn 2127: $r->print(&Apache::loncommon::start_page("Check $type Document Versions"));
1.257 www 2128: $r->print(&Apache::lonhtmlcommon::breadcrumbs("Check $type Document Versions"));
1.89 www 2129: my $header='';
2130: my $startsel='';
2131: my $monthsel='';
2132: my $weeksel='';
2133: my $daysel='';
2134: my $allsel='';
2135: my %changes=();
2136: my $starttime=0;
1.91 www 2137: my $haschanged=0;
1.92 www 2138: my %setversions=&Apache::lonnet::dump('resourceversions',
1.174 albertel 2139: $env{'course.'.$env{'request.course.id'}.'.domain'},
2140: $env{'course.'.$env{'request.course.id'}.'.num'});
1.92 www 2141:
2142: $hashtied=0;
2143: &tiehash();
2144: my %newsetversions=();
1.174 albertel 2145: if ($env{'form.setmostrecent'}) {
1.91 www 2146: $haschanged=1;
1.92 www 2147: foreach (keys %hash) {
2148: if ($_=~/^ids\_(\/res\/.+)$/) {
1.93 www 2149: $newsetversions{$1}='mostrecent';
1.192 www 2150: &devalidateversioncache($1);
1.92 www 2151: }
2152: }
1.174 albertel 2153: } elsif ($env{'form.setcurrent'}) {
1.91 www 2154: $haschanged=1;
1.92 www 2155: foreach (keys %hash) {
2156: if ($_=~/^ids\_(\/res\/.+)$/) {
1.93 www 2157: my $getvers=&Apache::lonnet::getversion($1);
2158: if ($getvers>0) {
2159: $newsetversions{$1}=$getvers;
1.192 www 2160: &devalidateversioncache($1);
1.93 www 2161: }
1.92 www 2162: }
2163: }
1.174 albertel 2164: } elsif ($env{'form.setversions'}) {
1.91 www 2165: $haschanged=1;
1.174 albertel 2166: foreach (keys %env) {
1.92 www 2167: if ($_=~/^form\.set_version_(.+)$/) {
2168: my $src=$1;
1.174 albertel 2169: if (($env{$_}) && ($env{$_} ne $setversions{$src})) {
2170: $newsetversions{$src}=$env{$_};
1.192 www 2171: &devalidateversioncache($src);
1.92 www 2172: }
2173: }
2174: }
1.91 www 2175: }
2176: if ($haschanged) {
1.92 www 2177: if (&Apache::lonnet::put('resourceversions',\%newsetversions,
1.174 albertel 2178: $env{'course.'.$env{'request.course.id'}.'.domain'},
2179: $env{'course.'.$env{'request.course.id'}.'.num'}) eq 'ok') {
1.272 albertel 2180: $r->print('<h1>'.&mt('Your Version Settings have been Saved').'</h1>');
1.92 www 2181: } else {
1.283 albertel 2182: $r->print('<h1><span class="LC_error">'.&mt('An Error Occured while Attempting to Save your Version Settings').'</span></h1>');
1.92 www 2183: }
1.136 albertel 2184: &mark_hash_old();
1.91 www 2185: }
1.136 albertel 2186: &changewarning($r,'');
1.174 albertel 2187: if ($env{'form.timerange'} eq 'all') {
1.89 www 2188: # show all documents
1.230 albertel 2189: $header=&mt('All Documents in '.$type);
1.91 www 2190: $allsel=1;
1.90 www 2191: foreach (keys %hash) {
2192: if ($_=~/^ids\_(\/res\/.+)$/) {
2193: my $src=$1;
2194: $changes{$src}=1;
2195: }
2196: }
1.89 www 2197: } else {
2198: # show documents which changed
2199: %changes=&Apache::lonnet::dump
1.174 albertel 2200: ('versionupdate',$env{'course.'.$env{'request.course.id'}.'.domain'},
2201: $env{'course.'.$env{'request.course.id'}.'.num'});
1.89 www 2202: my $firstkey=(keys %changes)[0];
2203: unless ($firstkey=~/^error\:/) {
1.174 albertel 2204: unless ($env{'form.timerange'}) {
2205: $env{'form.timerange'}=604800;
1.89 www 2206: }
1.174 albertel 2207: my $seltext=&mt('during the last').' '.$env{'form.timerange'}.' '
1.89 www 2208: .&mt('seconds');
1.174 albertel 2209: if ($env{'form.timerange'}==-1) {
1.89 www 2210: $seltext='since start of course';
2211: $startsel='selected';
1.174 albertel 2212: $env{'form.timerange'}=time;
1.89 www 2213: }
1.174 albertel 2214: $starttime=time-$env{'form.timerange'};
2215: if ($env{'form.timerange'}==2592000) {
1.89 www 2216: $seltext=&mt('during the last month').' ('.&Apache::lonlocal::locallocaltime($starttime).')';
2217: $monthsel='selected';
1.174 albertel 2218: } elsif ($env{'form.timerange'}==604800) {
1.89 www 2219: $seltext=&mt('during the last week').' ('.&Apache::lonlocal::locallocaltime($starttime).')';
2220: $weeksel='selected';
1.174 albertel 2221: } elsif ($env{'form.timerange'}==86400) {
1.89 www 2222: $seltext=&mt('since yesterday').' ('.&Apache::lonlocal::locallocaltime($starttime).')';
2223: $daysel='selected';
2224: }
2225: $header=&mt('Content changed').' '.$seltext;
2226: } else {
2227: $header=&mt('No content modifications yet.');
2228: }
2229: }
1.92 www 2230: %setversions=&Apache::lonnet::dump('resourceversions',
1.174 albertel 2231: $env{'course.'.$env{'request.course.id'}.'.domain'},
2232: $env{'course.'.$env{'request.course.id'}.'.num'});
1.89 www 2233: my %lt=&Apache::lonlocal::texthash
1.229 raeburn 2234: ('st' => 'Version changes since start of '.$type,
1.88 www 2235: 'lm' => 'Version changes since last Month',
2236: 'lw' => 'Version changes since last Week',
2237: 'sy' => 'Version changes since Yesterday',
1.91 www 2238: 'al' => 'All Resources (possibly large output)',
1.88 www 2239: 'sd' => 'Display',
1.84 www 2240: 'fi' => 'File',
2241: 'md' => 'Modification Date',
1.87 www 2242: 'mr' => 'Most recently published Version',
1.229 raeburn 2243: 've' => 'Version used in '.$type,
2244: 'vu' => 'Set Version to be used in '.$type,
2245: 'sv' => 'Set Versions to be used in '.$type.' according to Selections below',
1.91 www 2246: 'sm' => 'Keep all Resources up-to-date with most recent Versions (default)',
2247: 'sc' => 'Set all Resource Versions to current Version (Fix Versions)',
1.84 www 2248: 'di' => 'Differences');
1.89 www 2249: $r->print(<<ENDHEADERS);
1.31 www 2250: <form action="/adm/coursedocs" method="post">
1.91 www 2251: <input type="hidden" name="versions" value="1" />
2252: <input type="submit" name="setmostrecent" value="$lt{'sm'}" />
2253: <input type="submit" name="setcurrent" value="$lt{'sc'}" /><hr />
1.31 www 2254: <select name="timerange">
1.88 www 2255: <option value='all' $allsel>$lt{'al'}</option>
1.84 www 2256: <option value="-1" $startsel>$lt{'st'}</option>
2257: <option value="2592000" $monthsel>$lt{'lm'}</option>
2258: <option value="604800" $weeksel>$lt{'lw'}</option>
2259: <option value="86400" $daysel>$lt{'sy'}</option>
1.31 www 2260: </select>
1.91 www 2261: <input type="submit" name="display" value="$lt{'sd'}" />
1.89 www 2262: <h3>$header</h3>
1.91 www 2263: <input type="submit" name="setversions" value="$lt{'sv'}" />
1.103 matthew 2264: <table border="0">
1.31 www 2265: ENDHEADERS
1.91 www 2266: foreach (sort keys %changes) {
1.89 www 2267: if ($changes{$_}>$starttime) {
2268: my ($root,$extension)=($_=~/^(.*)\.(\w+)$/);
2269: my $currentversion=&Apache::lonnet::getversion($_);
1.93 www 2270: if ($currentversion<0) {
2271: $currentversion=&mt('Could not be determined.');
2272: }
1.89 www 2273: my $linkurl=&Apache::lonnet::clutter($_);
2274: $r->print(
1.103 matthew 2275: '<tr><td colspan="5"><br /><br /><font size="+1"><b>'.
1.91 www 2276: &Apache::lonnet::gettitle($linkurl).
1.103 matthew 2277: '</b></font></td></tr>'.
2278: '<tr><td> </td>'.
2279: '<td colspan="4">'.
2280: '<a href="'.$linkurl.'" target="cat">'.$linkurl.
2281: '</a></td></tr>'.
2282: '<tr><td></td>'.
2283: '<td title="'.$lt{'md'}.'">'.
1.102 matthew 2284: &Apache::lonlocal::locallocaltime(
2285: &Apache::lonnet::metadata($root.'.'.$extension,
2286: 'lastrevisiondate')
2287: ).
1.103 matthew 2288: '</td>'.
1.284 albertel 2289: '<td title="'.$lt{'mr'}.'"><span class="LC_nobreak">Most Recent: '.
1.103 matthew 2290: '<font size="+1">'.$currentversion.'</font>'.
1.284 albertel 2291: '</span></td>'.
2292: '<td title="'.$lt{'ve'}.'"><span class="LC_nobreak">In '.$type.': '.
1.103 matthew 2293: '<font size="+1">');
1.87 www 2294: # Used in course
1.89 www 2295: my $usedversion=$hash{'version_'.$linkurl};
1.93 www 2296: if (($usedversion) && ($usedversion ne 'mostrecent')) {
1.89 www 2297: $r->print($usedversion);
2298: } else {
2299: $r->print($currentversion);
2300: }
1.284 albertel 2301: $r->print('</font></span></td><td title="'.$lt{'vu'}.'">'.
2302: '<span class="LC_nobreak">Use: ');
1.87 www 2303: # Set version
1.92 www 2304: $r->print(&Apache::loncommon::select_form($setversions{$linkurl},
1.89 www 2305: 'set_version_'.$linkurl,
1.136 albertel 2306: ('select_form_order' =>
2307: ['',1..$currentversion,'mostrecent'],
2308: '' => '',
1.93 www 2309: 'mostrecent' => 'most recent',
1.89 www 2310: map {$_,$_} (1..$currentversion))));
1.284 albertel 2311: $r->print('</span></td></tr><tr><td></td>');
1.89 www 2312: my $lastold=1;
2313: for (my $prevvers=1;$prevvers<$currentversion;$prevvers++) {
2314: my $url=$root.'.'.$prevvers.'.'.$extension;
2315: if (&Apache::lonnet::metadata($url,'lastrevisiondate')<
2316: $starttime) {
2317: $lastold=$prevvers;
2318: }
2319: }
1.103 matthew 2320: #
2321: # Code to figure out how many version entries should go in
2322: # each of the four columns
2323: my $entries_per_col = 0;
2324: my $num_entries = ($currentversion-$lastold);
2325: if ($num_entries % 4 == 0) {
2326: $entries_per_col = $num_entries/4;
2327: } else {
2328: $entries_per_col = $num_entries/4 + 1;
2329: }
2330: my $entries_count = 0;
2331: $r->print('<td valign="top"><font size="-2">');
2332: my $cols_output = 1;
1.32 www 2333: for (my $prevvers=$lastold;$prevvers<$currentversion;$prevvers++) {
1.89 www 2334: my $url=$root.'.'.$prevvers.'.'.$extension;
1.284 albertel 2335: $r->print('<span class="LC_nobreak"><a href="'.&Apache::lonnet::clutter($url).
1.91 www 2336: '">'.&mt('Version').' '.$prevvers.'</a> ('.
1.103 matthew 2337: &Apache::lonlocal::locallocaltime(
2338: &Apache::lonnet::metadata($url,
2339: 'lastrevisiondate')
2340: ).
1.91 www 2341: ')');
1.89 www 2342: if (&Apache::loncommon::fileembstyle($extension) eq 'ssi') {
1.33 www 2343: $r->print(' <a href="/adm/diff?filename='.
1.89 www 2344: &Apache::lonnet::clutter($root.'.'.$extension).
2345: '&versionone='.$prevvers.
2346: '">'.&mt('Diffs').'</a>');
2347: }
1.284 albertel 2348: $r->print('</span><br />');
1.103 matthew 2349: if (++$entries_count % $entries_per_col == 0) {
2350: $r->print('</font></td>');
2351: if ($cols_output != 4) {
2352: $r->print('<td valign="top"><font size="-2">');
2353: $cols_output++;
2354: }
2355: }
1.89 www 2356: }
1.103 matthew 2357: while($cols_output++ < 4) {
2358: $r->print('</font></td><td><font>')
2359: }
2360: $r->print('</font></td></tr>'."\n");
1.89 www 2361: }
2362: }
1.92 www 2363: $r->print('</table></form>');
1.89 www 2364: $r->print('<h1>'.&mt('Done').'.</h1>');
2365:
2366: &untiehash();
1.75 www 2367: }
2368:
1.136 albertel 2369: sub mark_hash_old {
2370: my $retie_hash=0;
2371: if ($hashtied) {
2372: $retie_hash=1;
2373: &untiehash();
2374: }
2375: &tiehash('write');
2376: $hash{'old'}=1;
2377: &untiehash();
2378: if ($retie_hash) { &tiehash(); }
2379: }
2380:
2381: sub is_hash_old {
2382: my $untie_hash=0;
2383: if (!$hashtied) {
2384: $untie_hash=1;
2385: &tiehash();
2386: }
2387: my $return=$hash{'old'};
2388: if ($untie_hash) { &untiehash(); }
2389: return $return;
2390: }
2391:
1.91 www 2392: sub changewarning {
1.177 albertel 2393: my ($r,$postexec,$message,$url)=@_;
1.136 albertel 2394: if (!&is_hash_old()) { return; }
1.150 albertel 2395: my $pathvar='folderpath';
1.228 www 2396: my $path=&escape($env{'form.folderpath'});
1.177 albertel 2397: if (!defined($url)) {
2398: if (defined($env{'form.pagepath'})) {
2399: $pathvar='pagepath';
1.228 www 2400: $path=&escape($env{'form.pagepath'});
2401: $path.='&pagesymb='.&escape($env{'form.pagesymb'});
1.177 albertel 2402: }
2403: $url='/adm/coursedocs?'.$pathvar.'='.$path;
2404: }
1.230 albertel 2405: my $course_type = &Apache::loncommon::course_type();
1.177 albertel 2406: if (!defined($message)) {
2407: $message='Changes will become active for your current session after [_1], or the next time you log in.';
1.150 albertel 2408: }
1.185 www 2409: $r->print("\n\n".
1.286 albertel 2410: '<script type="text/javascript">function reinit(tf) { tf.submit();'.$postexec.' }</script>'."\n".
1.185 www 2411: '<form name="reinitform" method="post" action="/adm/roles" target="loncapaclient">'.
1.177 albertel 2412: '<input type="hidden" name="orgurl" value="'.$url.
1.283 albertel 2413: '" /><input type="hidden" name="selectrole" value="1" /><h3><span class="LC_warning">'.
1.177 albertel 2414: &mt($message,' <input type="hidden" name="'.
2415: $env{'request.role'}.'" value="1" /><input type="button" value="'.
1.230 albertel 2416: &mt('re-initializing '.$course_type).'" onClick="reinit(this.form)" />').
1.283 albertel 2417: $help{'Caching'}.'</span></h3></form>'."\n\n");
1.91 www 2418: }
2419:
1.257 www 2420: # =========================================== Breadcrumbs for special functions
2421:
2422: sub init_breadcrumbs {
2423: my ($form,$text)=@_;
2424: &Apache::lonhtmlcommon::clear_breadcrumbs();
2425: &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs",
2426: text=>&Apache::loncommon::course_type()." Documents",
2427: faq=>273,
2428: bug=>'Instructor Interface',
2429: help => 'Docs_Adding_Course_Doc'});
2430: &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/coursedocs?".$form.'=1',
2431: text=>$text,
2432: faq=>273,
2433: bug=>'Instructor Interface'});
2434: }
2435:
1.75 www 2436: # ================================================================ Main Handler
2437: sub handler {
2438: my $r = shift;
1.82 www 2439: &Apache::loncommon::content_type($r,'text/html');
1.75 www 2440: $r->send_http_header;
2441: return OK if $r->header_only;
1.230 albertel 2442: my $type = &Apache::loncommon::course_type();
1.75 www 2443:
2444: # --------------------------------------------- Initialize help topics for this
1.209 albertel 2445: foreach ('Adding_Course_Doc','Main_Course_Documents',
2446: 'Adding_External_Resource','Navigate_Content',
2447: 'Adding_Folders','Docs_Overview', 'Load_Map',
2448: 'Supplemental','Score_Upload_Form','Adding_Pages',
2449: 'Importing_LON-CAPA_Resource','Uploading_From_Harddrive',
2450: 'Check_Resource_Versions','Verify_Content') {
2451: $help{$_}=&Apache::loncommon::help_open_topic('Docs_'.$_);
2452: }
1.75 www 2453: # Composite help files
2454: $help{'Syllabus'} = &Apache::loncommon::help_open_topic(
2455: 'Docs_About_Syllabus,Docs_Editing_Templated_Pages');
2456: $help{'Simple Page'} = &Apache::loncommon::help_open_topic(
2457: 'Docs_About_Simple_Page,Docs_Editing_Templated_Pages');
1.86 albertel 2458: $help{'Simple Problem'} = &Apache::loncommon::help_open_topic(
2459: 'Option_Response_Simple');
1.75 www 2460: $help{'Bulletin Board'} = &Apache::loncommon::help_open_topic(
2461: 'Docs_About_Bulletin_Board,Docs_Editing_Templated_Pages');
2462: $help{'My Personal Info'} = &Apache::loncommon::help_open_topic(
2463: 'Docs_About_My_Personal_Info,Docs_Editing_Templated_Pages');
1.255 raeburn 2464: $help{'Group Files'} = &Apache::loncommon::help_open_topic('Docs_About_Group_Files');
1.75 www 2465: $help{'Caching'} = &Apache::loncommon::help_open_topic('Caching');
1.142 raeburn 2466:
1.209 albertel 2467: # does this user have privileges to modify docs
2468: my $allowed=&Apache::lonnet::allowed('mdc',$env{'request.course.id'});
2469: if ($allowed && $env{'form.verify'}) {
1.257 www 2470: &init_breadcrumbs('verify','Verify Content');
1.75 www 2471: &verifycontent($r);
1.209 albertel 2472: } elsif ($allowed && $env{'form.listsymbs'}) {
1.257 www 2473: &init_breadcrumbs('listsymbs','List Symbs');
1.208 albertel 2474: &list_symbs($r);
1.247 www 2475: } elsif ($allowed && $env{'form.docslog'}) {
1.257 www 2476: &init_breadcrumbs('docslog','Show Log');
1.247 www 2477: &docs_change_log($r);
1.209 albertel 2478: } elsif ($allowed && $env{'form.versions'}) {
1.257 www 2479: &init_breadcrumbs('versions','Check/Set Resource Versions');
1.75 www 2480: &checkversions($r);
1.209 albertel 2481: } elsif ($allowed && $env{'form.dumpcourse'}) {
1.257 www 2482: &init_breadcrumbs('dumpcourse','Dump '.&Apache::loncommon::course_type().' DOCS to Construction Space');
1.75 www 2483: &dumpcourse($r);
1.209 albertel 2484: } elsif ($allowed && $env{'form.exportcourse'}) {
1.257 www 2485: &init_breadcrumbs('exportcourse','Export '.&Apache::loncommon::course_type().' to IMS');
1.138 raeburn 2486: &exportcourse($r);
1.26 www 2487: } else {
1.7 www 2488: # is this a standard course?
2489:
1.174 albertel 2490: my $standard=($env{'request.course.uri'}=~/^\/uploaded\//);
1.155 raeburn 2491: my $forcestandard = 0;
1.15 www 2492: my $forcesupplement;
2493: my $script='';
1.19 www 2494: my $showdoc=0;
1.142 raeburn 2495: my $containertag;
2496: my $uploadtag;
1.15 www 2497: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
1.224 albertel 2498: ['folderpath','pagepath',
1.281 albertel 2499: 'pagesymb']);
1.174 albertel 2500: if ($env{'form.folderpath'}) {
2501: my (@folderpath)=split('&',$env{'form.folderpath'});
1.228 www 2502: $env{'form.foldername'}=&unescape(pop(@folderpath));
1.174 albertel 2503: $env{'form.folder'}=pop(@folderpath);
2504: }
2505: if ($env{'form.pagepath'}) {
2506: my (@pagepath)=split('&',$env{'form.pagepath'});
1.228 www 2507: $env{'form.pagename'}=&unescape(pop(@pagepath));
1.174 albertel 2508: $env{'form.folder'}=pop(@pagepath);
1.156 albertel 2509: $containertag = '<input type="hidden" name="pagepath" value="" />'.
2510: '<input type="hidden" name="pagesymb" value="" />';
1.282 albertel 2511: $uploadtag = '<input type="hidden" name="pagepath" value="'.&HTML::Entities::encode($env{'form.pagepath'},'<>&"').'" />'.
2512: '<input type="hidden" name="pagesymb" value="'.&HTML::Entities::encode($env{'form.pagesymb'},'<>&"').'" />';
1.142 raeburn 2513: }
1.21 www 2514: if ($r->uri=~/^\/adm\/coursedocs\/showdoc\/(.*)$/) {
1.127 albertel 2515: $showdoc='/'.$1;
1.21 www 2516: }
2517: unless ($showdoc) { # got called from remote
1.237 albertel 2518: if (($env{'form.folder'}=~/^(?:group|default)_/) ||
1.209 albertel 2519: ($env{'form.folder'} =~ m:^\d+/(pages|sequences)/:)) {
1.155 raeburn 2520: $forcestandard = 1;
2521: }
1.174 albertel 2522: $forcesupplement=($env{'form.folder'}=~/^supplemental_/);
1.7 www 2523:
1.15 www 2524: if ($allowed) {
2525: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['cmd']);
2526: $script=&Apache::lonratedt::editscript('simple');
2527: }
2528: } else { # got called in sequence from course
2529: $allowed=0;
1.3 www 2530: }
1.4 www 2531:
2532: # get course data
1.174 albertel 2533: my $coursenum=$env{'course.'.$env{'request.course.id'}.'.num'};
2534: my $coursedom=$env{'course.'.$env{'request.course.id'}.'.domain'};
1.4 www 2535:
1.225 albertel 2536: # get personal data
1.174 albertel 2537: my $uname=$env{'user.name'};
2538: my $udom=$env{'user.domain'};
1.245 albertel 2539: my $plainname=&escape(&Apache::loncommon::plainname($uname,$udom));
1.14 www 2540:
1.8 www 2541: # graphics settings
1.4 www 2542:
1.176 albertel 2543: $iconpath = &Apache::loncommon::lonhttpdurl($r->dir_config('lonIconsURL') . "/");
1.8 www 2544:
1.224 albertel 2545: if ($allowed) {
2546: $script .= &editing_js($udom,$uname);
1.171 www 2547: }
1.42 www 2548: # -------------------------------------------------------------------- Body tag
1.224 albertel 2549: $script = '<script type="text/javascript">'."\n".$script."\n".'</script>';
1.229 raeburn 2550: $r->print(&Apache::loncommon::start_page("$type Documents", $script,
1.225 albertel 2551: {'force_register' => $showdoc,}).
1.233 albertel 2552: &Apache::loncommon::help_open_menu('','',273,'RAT'));
1.224 albertel 2553:
1.188 raeburn 2554: my %allfiles = ();
2555: my %codebase = ();
2556: my ($upload_result,$upload_output);
2557: if ($allowed) {
1.264 albertel 2558: if (($env{'form.uploaddoc.filename'}) &&
2559: ($env{'form.cmd'}=~/^upload_(\w+)/)) {
1.188 raeburn 2560: # Process file upload - phase one - upload and parse primary file.
1.190 albertel 2561: $upload_result = &process_file_upload(\$upload_output,$coursenum,
2562: $coursedom,\%allfiles,
1.194 raeburn 2563: \%codebase,$1);
1.188 raeburn 2564: if ($upload_result eq 'phasetwo') {
2565: $r->print($upload_output);
2566: }
2567: } elsif ($env{'form.phasetwo'}) {
2568: my %newname = ();
2569: my %origname = ();
2570: my %attribs = ();
2571: my $updateflag = 0;
2572: my $residx = $env{'form.newidx'};
1.228 www 2573: my $primary_url = &unescape($env{'form.primaryurl'});
1.188 raeburn 2574: # Process file upload - phase two - gather secondary files.
2575: for (my $i=0; $i<$env{'form.phasetwo'}; $i++) {
2576: if ($env{'form.embedded_item_'.$i.'.filename'}) {
2577: my $javacodebase;
2578: $newname{$i} = &process_secondary_uploads(\$upload_output,$coursedom,$coursenum,'embedded_item_',$i,$residx);
1.228 www 2579: $origname{$i} = &unescape($env{'form.embedded_orig_'.$i});
1.188 raeburn 2580: if (exists($env{'form.embedded_codebase_'.$i})) {
1.228 www 2581: $javacodebase = &unescape($env{'form.embedded_codebase_'.$i});
1.188 raeburn 2582: $origname{$i} =~ s#^\Q$javacodebase\E/##;
2583: }
2584: my @attributes = ();
2585: if ($env{'form.embedded_attrib_'.$i} =~ /:/) {
2586: @attributes = split/:/,$env{'form.embedded_attrib_'.$i};
2587: } else {
2588: @attributes = ($env{'form.embedded_attrib_'.$i});
2589: }
2590: foreach (@attributes) {
1.228 www 2591: push(@{$attribs{$i}},&unescape($_));
1.188 raeburn 2592: }
2593: if ($javacodebase) {
2594: $codebase{$i} = $javacodebase;
2595: $codebase{$i} =~ s#/$##;
2596: $updateflag = 1;
2597: }
2598: }
2599: unless ($newname{$i} eq $origname{$i}) {
2600: $updateflag = 1;
2601: }
2602: }
2603: # Process file upload - phase three - modify primary file
2604: if ($updateflag) {
2605: my ($content,$rtncode);
2606: my $updateflag = 0;
2607: my $getstatus = &Apache::lonnet::getuploaded('GET',$primary_url,$coursedom,$coursenum,\$content,\$rtncode);
2608: if ($getstatus eq 'ok') {
2609: foreach my $item (keys %newname) {
2610: if ($newname{$item} ne $origname{$item}) {
2611: my $attrib_regexp = '';
2612: if (@{$attribs{$item}} > 1) {
2613: $attrib_regexp = join('|',@{$attribs{$item}});
2614: } else {
2615: $attrib_regexp = $attribs{$item}[0];
2616: }
2617: if ($content =~ m#($attrib_regexp\s*=\s*['"]?)\Q$origname{$item}\E(['"]?)#) {
2618: }
2619: $content =~ s#($attrib_regexp\s*=\s*['"]?)\Q$origname{$item}\E(['"]?)#$1$newname{$item}$2#gi;
2620: }
2621: if (exists($codebase{$item})) {
1.224 albertel 2622: $content =~ s/(codebase\s*=\s*["']?)\Q$codebase{$item}\E(["']?)/$1.$2/i; #' stupid emacs
1.188 raeburn 2623: }
2624: }
2625: # Save edited file.
2626: my $saveresult;
2627: my $docuname=$env{'course.'.$env{'request.course.id'}.'.num'};
2628: my $docudom=$env{'course.'.$env{'request.course.id'}.'.domain'};
1.191 raeburn 2629: my $url = &Apache::lonnet::store_edited_file($primary_url,$content,$docudom,$docuname,\$saveresult);
1.188 raeburn 2630: } else {
2631: &Apache::lonnet::logthis('retrieval of uploaded file - '.$primary_url.' - for editing, failed: '.$getstatus);
2632: }
2633: }
2634: }
2635: }
2636:
2637: unless ($showdoc || $upload_result eq 'phasetwo') {
1.81 www 2638: # -----------------------------------------------------------------------------
2639: my %lt=&Apache::lonlocal::texthash(
1.229 raeburn 2640: 'uplm' => 'Upload a new main '.lc($type).' document',
2641: 'upls' => 'Upload a new supplemental '.lc($type).' document',
1.168 www 2642: 'impp' => 'Import a document',
2643: 'pubd' => 'Published documents',
1.181 www 2644: 'copm' => 'All documents out of a published map into this folder',
1.81 www 2645: 'spec' => 'Special documents',
2646: 'upld' => 'Upload Document',
2647: 'srch' => 'Search',
2648: 'impo' => 'Import',
1.232 www 2649: 'book' => 'Import Bookmarks',
1.81 www 2650: 'selm' => 'Select Map',
2651: 'load' => 'Load Map',
1.186 www 2652: 'reco' => 'Recover Deleted Resources',
1.81 www 2653: 'newf' => 'New Folder',
1.142 raeburn 2654: 'newp' => 'New Composite Page',
1.81 www 2655: 'extr' => 'External Resource',
2656: 'syll' => 'Syllabus',
2657: 'navc' => 'Navigate Contents',
2658: 'sipa' => 'Simple Page',
2659: 'sipr' => 'Simple Problem',
1.219 www 2660: 'drbx' => 'Drop Box',
1.81 www 2661: 'scuf' => 'Score Upload Form',
2662: 'bull' => 'Bulletin Board',
1.96 sakharuk 2663: 'mypi' => 'My Personal Info',
1.255 raeburn 2664: 'grpo' => 'Group Files',
1.101 www 2665: 'abou' => 'About User',
1.110 raeburn 2666: 'imsf' => 'Import IMS package',
1.96 sakharuk 2667: 'file' => 'File',
2668: 'title' => 'Title',
1.188 raeburn 2669: 'comment' => 'Comment',
2670: 'parse' => 'If HTML file, upload embedded images/multimedia files'
1.81 www 2671: );
2672: # -----------------------------------------------------------------------------
1.42 www 2673: if ($allowed) {
1.281 albertel 2674: &update_paste_buffer($coursenum,$coursedom);
1.74 www 2675: my $dumpbut=&dumpbutton();
1.138 raeburn 2676: my $exportbut=&exportbutton();
1.88 www 2677: my %lt=&Apache::lonlocal::texthash(
2678: 'vc' => 'Verify Content',
2679: 'cv' => 'Check/Set Resource Versions',
1.208 albertel 2680: 'ls' => 'List Symbs',
1.247 www 2681: 'sl' => 'Show Log'
1.88 www 2682: );
1.118 albertel 2683:
1.174 albertel 2684: my $folderpath=$env{'form.folderpath'};
1.118 albertel 2685: if (!$folderpath) {
1.174 albertel 2686: if ($env{'form.folder'} eq '' ||
2687: $env{'form.folder'} eq 'supplemental') {
1.118 albertel 2688: $folderpath='default&'.
1.230 albertel 2689: &escape(&mt('Main '.$type.' Documents'));
1.118 albertel 2690: }
2691: }
1.174 albertel 2692: unless ($env{'form.pagepath'}) {
1.142 raeburn 2693: $containertag = '<input type="hidden" name="folderpath" value="" />';
1.282 albertel 2694: $uploadtag = '<input type="hidden" name="folderpath" value="'.&HTML::Entities::encode($folderpath,'<>&"').'" />';
1.142 raeburn 2695: }
2696:
1.42 www 2697: $r->print(<<ENDCOURSEVERIFY);
1.36 www 2698: <form name="renameform" method="post" action="/adm/coursedocs">
1.283 albertel 2699: <input type="hidden" name="title" />
2700: <input type="hidden" name="cmd" />
2701: <input type="hidden" name="markcopy" />
2702: <input type="hidden" name="copyfolder" />
2703: $containertag
1.36 www 2704: </form>
1.39 www 2705: <form name="simpleedit" method="post" action="/adm/coursedocs">
1.283 albertel 2706: <input type="hidden" name="importdetail" value="" />
2707: $uploadtag
1.39 www 2708: </form>
1.26 www 2709: <form action="/adm/coursedocs" method="post" name="courseverify">
1.283 albertel 2710: <div class="LC_docs_course_commands">
2711:
2712: <div>
2713: <input type="submit" name="verify" value="$lt{'vc'}" />$help{'Verify_Content'}
2714: </div>
2715: <div>
2716: <input type="submit" name="versions" value="$lt{'cv'}" />$help{'Check_Resource_Versions'}
2717: </div>
2718: $dumpbut
2719: $exportbut
2720: <div>
2721: <input type="submit" name="listsymbs" value="$lt{'ls'}" />
2722: </div>
2723: <div>
2724: <input type="hidden" name="folder" value="$env{'form.folder'}" />
2725: <input type="submit" name="docslog" value="$lt{'sl'}" />
2726: </div>
2727: </div>
1.25 www 2728: </form>
1.283 albertel 2729: <div style="clear: both; height: 0px;"> </div>
1.25 www 2730: ENDCOURSEVERIFY
1.74 www 2731: $r->print(&Apache::loncommon::help_open_topic('Docs_Adding_Course_Doc',
1.230 albertel 2732: &mt('Editing the Table of Contents for your '.$type)));
1.25 www 2733: }
1.17 www 2734: # --------------------------------------------------------- Standard documents
1.293 ! albertel 2735: $r->print('<table class="LC_docs_documents">');
! 2736:
1.7 www 2737: if (($standard) && ($allowed) && (!$forcesupplement)) {
1.285 albertel 2738: $r->print('<tr><td class="LC_docs_document">');
1.116 albertel 2739: # '<h2>'.&mt('Main Course Documents').
2740: # ($allowed?' '.$help{'Main_Course_Documents'}:'').'</h2>');
1.174 albertel 2741: my $folder=$env{'form.folder'};
1.117 albertel 2742: if ($folder eq '' || $folder eq 'supplemental') {
1.112 raeburn 2743: $folder='default';
1.230 albertel 2744: $env{'form.folderpath'}='default&'.&escape(&mt('Main '.$type.' Documents'));
1.293 ! albertel 2745: $uploadtag = '<input type="hidden" name="folderpath" value="'.
! 2746: &HTML::Entities::encode($env{'form.folderpath'},'<>&"').'" />';
1.112 raeburn 2747: }
1.51 www 2748: my $postexec='';
2749: if ($folder eq 'default') {
1.286 albertel 2750: $r->print('<script type="text/javascript">this.window.name="loncapaclient";</script>');
1.51 www 2751: } else {
1.117 albertel 2752: #$postexec='self.close();';
1.51 www 2753: }
1.40 www 2754: $hadchanges=0;
1.292 albertel 2755: my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed,
2756: $upload_output);
2757: if ($error) {
2758: $r->print('<p><span class="LC_error">'.$error.'</span></p>');
2759: }
1.40 www 2760: if ($hadchanges) {
1.136 albertel 2761: &mark_hash_old()
1.40 www 2762: }
1.136 albertel 2763: &changewarning($r,$postexec);
1.16 www 2764: my $folderseq='/uploaded/'.$coursedom.'/'.$coursenum.'/default_'.time.
2765: '.sequence';
1.142 raeburn 2766: my $pageseq = '/uploaded/'.$coursedom.'/'.$coursenum.'/default_'.time.
2767: '.page';
1.186 www 2768: my $container='sequence';
2769: if ($env{'form.pagepath'}) {
2770: $container='page';
2771: }
2772: my $readfile='/uploaded/'.$coursedom.'/'.$coursenum.'/'.$folder.'.'.$container;
1.8 www 2773: $r->print(<<ENDFORM);
1.285 albertel 2774: <table class="LC_docs_adddocs">
2775: <tr>
2776: <th>$lt{'uplm'}</th>
2777: <th>$lt{'impp'}</th>
2778: <th>$lt{'spec'}</th>
1.11 www 2779: </tr>
1.285 albertel 2780: <tr>
2781: <td>
1.96 sakharuk 2782: $lt{'file'}:<br />
1.182 albertel 2783: <form name="uploaddocument" action="/adm/coursedocs" method="post" enctype="multipart/form-data">
1.286 albertel 2784: <input type="file" name="uploaddoc" size="40" />
1.8 www 2785: <br />
1.96 sakharuk 2786: $lt{'title'}:<br />
1.286 albertel 2787: <input type="text" size="50" name="comment" />
1.142 raeburn 2788: $uploadtag
1.286 albertel 2789: <input type="hidden" name="cmd" value="upload_default" />
1.188 raeburn 2790: <br />
1.284 albertel 2791: <span class="LC_nobreak">
1.190 albertel 2792: <label>$lt{'parse'}?
1.188 raeburn 2793: <input type="checkbox" name="parserflag" />
1.190 albertel 2794: </label>
1.284 albertel 2795: </span>
1.188 raeburn 2796: <br />
2797: <br />
1.284 albertel 2798: <span class="LC_nobreak">
1.286 albertel 2799: <input type="submit" value="$lt{'upld'}" />
1.60 albertel 2800: $help{'Uploading_From_Harddrive'}
1.284 albertel 2801: </span>
1.60 albertel 2802: </form>
1.11 www 2803: </td>
1.285 albertel 2804: <td>
1.39 www 2805: <form action="/adm/coursedocs" method="post" name="simpleeditdefault">
1.168 www 2806: $lt{'pubd'}<br />
1.142 raeburn 2807: $uploadtag
1.286 albertel 2808: <input type="button" onClick="javascript:groupsearch()" value="$lt{'srch'}" />
1.232 www 2809: <br />
1.284 albertel 2810: <span class="LC_nobreak">
1.286 albertel 2811: <input type="button" onClick="javascript:groupimport();" value="$lt{'impo'}" />
1.58 albertel 2812: $help{'Importing_LON-CAPA_Resource'}
1.284 albertel 2813: </span>
1.232 www 2814: <br />
1.286 albertel 2815: <input type="button" onClick="javascript:groupopen(0,1,1);" value="$lt{'book'}" />
2816: <hr />
1.59 www 2817: <p>
1.181 www 2818: $lt{'copm'}<br />
1.282 albertel 2819: <input type="text" size="40" name="importmap" /><br />
1.286 albertel 2820: <span class="LC_nobreak"><input type="button"
1.52 www 2821: onClick="javascript:openbrowser('simpleeditdefault','importmap','sequence,page','')"
1.282 albertel 2822: value="$lt{'selm'}" /> <input type="submit" name="loadmap" value="$lt{'load'}" />
1.284 albertel 2823: $help{'Load_Map'}</span>
1.59 www 2824: </p>
1.52 www 2825: </form>
1.186 www 2826: <hr />
2827: <form action="/adm/groupsort" method="post" name="recover">
1.232 www 2828: <input type="button" name="recovermap" onClick="javascript:groupopen('$readfile',1,0)" value="$lt{'reco'}" />
1.186 www 2829: </form>
1.142 raeburn 2830: ENDFORM
1.174 albertel 2831: unless ($env{'form.pagepath'}) {
1.168 www 2832: $r->print(<<ENDFORM);
2833: <hr />
2834: <form action="/adm/coursedocs" method="post" name="newext">
2835: $uploadtag
1.256 albertel 2836: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2837: <span class="LC_nobreak">
1.168 www 2838: <input name="newext" type="button" onClick="javascript:makenewext('newext');"
2839: value="$lt{'extr'}" /> $help{'Adding_External_Resource'}
1.284 albertel 2840: </span>
1.168 www 2841: </form>
1.214 www 2842: <br /><form action="/adm/imsimportdocs" method="post" name="ims">
1.168 www 2843: <input type="hidden" name="folder" value="$folder" />
2844: <input name="imsimport" type="button" value="$lt{'imsf'}" onClick="javascript:makeims();" />
2845: </form>
2846: ENDFORM
2847: }
1.285 albertel 2848: $r->print('</td><td>');
1.174 albertel 2849: unless ($env{'form.pagepath'}) {
1.282 albertel 2850: my $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
1.142 raeburn 2851: $r->print(<<ENDFORM);
1.214 www 2852: <br /><form action="/adm/coursedocs" method="post" name="newfolder">
1.282 albertel 2853: <input type="hidden" name="folderpath" value="$path" />
1.256 albertel 2854: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2855: <span class="LC_nobreak">
1.16 www 2856: <input name="newfolder" type="button"
2857: onClick="javascript:makenewfolder(this.form,'$folderseq');"
1.81 www 2858: value="$lt{'newf'}" />$help{'Adding_Folders'}
1.284 albertel 2859: </span>
1.11 www 2860: </form>
1.214 www 2861: <br /><form action="/adm/coursedocs" method="post" name="newpage">
1.282 albertel 2862: <input type="hidden" name="folderpath" value="$path" />
1.256 albertel 2863: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2864: <span class="LC_nobreak">
1.142 raeburn 2865: <input name="newpage" type="button"
2866: onClick="javascript:makenewpage(this.form,'$pageseq');"
2867: value="$lt{'newp'}" />$help{'Adding_Pages'}
1.284 albertel 2868: </span>
1.142 raeburn 2869: </form>
1.214 www 2870: <br /><form action="/adm/coursedocs" method="post" name="newsyl">
1.142 raeburn 2871: $uploadtag
1.256 albertel 2872: <input type="hidden" name="importdetail"
2873: value="Syllabus=/public/$coursedom/$coursenum/syllabus" />
1.284 albertel 2874: <span class="LC_nobreak">
1.81 www 2875: <input name="newsyl" type="submit" value="$lt{'syll'}" />
1.65 bowersj2 2876: $help{'Syllabus'}
1.284 albertel 2877: </span>
1.58 albertel 2878: </form>
1.214 www 2879: <br /><form action="/adm/coursedocs" method="post" name="newnav">
1.142 raeburn 2880: $uploadtag
1.256 albertel 2881: <input type="hidden" name="importdetail"
2882: value="Navigate Content=/adm/navmaps" />
1.284 albertel 2883: <span class="LC_nobreak">
1.81 www 2884: <input name="newnav" type="submit" value="$lt{'navc'}" />
1.47 www 2885: $help{'Navigate_Content'}
1.284 albertel 2886: </span>
1.22 www 2887: </form>
1.214 www 2888: <br /><form action="/adm/coursedocs" method="post" name="newsmppg">
1.142 raeburn 2889: $uploadtag
1.256 albertel 2890: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2891: <span class="LC_nobreak">
1.81 www 2892: <input name="newsmppg" type="button" value="$lt{'sipa'}"
1.65 bowersj2 2893: onClick="javascript:makesmppage();" /> $help{'Simple Page'}
1.284 albertel 2894: </span>
1.55 www 2895: </form>
1.214 www 2896: <br /><form action="/adm/coursedocs" method="post" name="newsmpproblem">
1.142 raeburn 2897: $uploadtag
1.256 albertel 2898: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2899: <span class="LC_nobreak">
1.81 www 2900: <input name="newsmpproblem" type="button" value="$lt{'sipr'}"
1.65 bowersj2 2901: onClick="javascript:makesmpproblem();" />$help{'Simple Problem'}
1.284 albertel 2902: </span>
1.62 www 2903: </form>
1.219 www 2904: <br /><form action="/adm/coursedocs" method="post" name="newdropbox">
2905: $uploadtag
1.256 albertel 2906: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2907: <span class="LC_nobreak">
1.219 www 2908: <input name="newdropbox" type="button" value="$lt{'drbx'}"
2909: onClick="javascript:makedropbox();" />
1.284 albertel 2910: </span>
1.219 www 2911: </form>
1.214 www 2912: <br /><form action="/adm/coursedocs" method="post" name="newexamupload">
1.142 raeburn 2913: $uploadtag
1.256 albertel 2914: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2915: <span class="LC_nobreak">
1.81 www 2916: <input name="newexamupload" type="button" value="$lt{'scuf'}"
1.62 www 2917: onClick="javascript:makeexamupload();" />
1.66 bowersj2 2918: $help{'Score_Upload_Form'}
1.284 albertel 2919: </span>
1.22 www 2920: </form>
1.214 www 2921: <br /><form action="/adm/coursedocs" method="post" name="newbul">
1.142 raeburn 2922: $uploadtag
1.256 albertel 2923: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2924: <span class="LC_nobreak">
1.81 www 2925: <input name="newbulletin" type="button" value="$lt{'bull'}"
1.22 www 2926: onClick="javascript:makebulboard();" />
1.65 bowersj2 2927: $help{'Bulletin Board'}
1.284 albertel 2928: </span>
1.58 albertel 2929: </form>
1.214 www 2930: <br /><form action="/adm/coursedocs" method="post" name="newaboutme">
1.142 raeburn 2931: $uploadtag
1.256 albertel 2932: <input type="hidden" name="importdetail"
2933: value="$plainname=/adm/$udom/$uname/aboutme" />
1.284 albertel 2934: <span class="LC_nobreak">
1.81 www 2935: <input name="newaboutme" type="submit" value="$lt{'mypi'}" />
1.65 bowersj2 2936: $help{'My Personal Info'}
1.284 albertel 2937: </span>
1.101 www 2938: </form>
1.214 www 2939: <br /><form action="/adm/coursedocs" method="post" name="newaboutsomeone">
1.142 raeburn 2940: $uploadtag
1.256 albertel 2941: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2942: <span class="LC_nobreak">
1.101 www 2943: <input name="newaboutsomeone" type="button" value="$lt{'abou'}"
2944: onClick="javascript:makeabout();" />
1.284 albertel 2945: </span>
1.182 albertel 2946: </form>
1.255 raeburn 2947: <br /><form action="/adm/coursedocs" method="post" name="newgroupfiles">
2948: $uploadtag
1.256 albertel 2949: <input type="hidden" name="importdetail"
2950: value="Group Files=/adm/$coursedom/$coursenum/aboutme" />
1.284 albertel 2951: <span class="LC_nobreak">
1.255 raeburn 2952: <input name="newgroupfiles" type="submit" value="$lt{'grpo'}" />
2953: $help{'Group Files'}
1.284 albertel 2954: </span>
1.255 raeburn 2955: </form>
1.142 raeburn 2956: ENDFORM
2957: }
1.174 albertel 2958: if ($env{'form.pagepath'}) {
1.142 raeburn 2959: $r->print(<<ENDBLOCK);
2960: <form action="/adm/coursedocs" method="post" name="newsmpproblem">
2961: $uploadtag
1.256 albertel 2962: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2963: <span class="LC_nobreak">
1.142 raeburn 2964: <input name="newsmpproblem" type="button" value="$lt{'sipr'}"
2965: onClick="javascript:makesmpproblem();" />$help{'Simple Problem'}
1.284 albertel 2966: </span>
1.142 raeburn 2967: </form>
1.214 www 2968: <br /><form action="/adm/coursedocs" method="post" name="newexamupload">
1.142 raeburn 2969: $uploadtag
1.256 albertel 2970: <input type="hidden" name="importdetail" value="" />
1.284 albertel 2971: <span class="LC_nobreak">
1.142 raeburn 2972: <input name="newexamupload" type="button" value="$lt{'scuf'}"
2973: onClick="javascript:makeexamupload();" />
2974: $help{'Score_Upload_Form'}
1.284 albertel 2975: </span>
1.182 albertel 2976: </form>
1.142 raeburn 2977: ENDBLOCK
2978: }
2979: $r->print('</td></tr>'."\n".
2980: '</table>');
1.24 www 2981: $r->print('</td></tr>');
1.7 www 2982: }
2983: # ----------------------------------------------------- Supplemental documents
2984: if (!$forcestandard) {
1.285 albertel 2985: $r->print('<tr><td class="LC_docs_document">');
1.116 albertel 2986: # '<h2>'.&mt('Supplemental Course Documents').
2987: # ($allowed?' '.$help{'Supplemental'}:'').'</h2>');
1.174 albertel 2988: my $folder=$env{'form.folder'};
1.117 albertel 2989: unless ($folder=~/^supplemental/) {
1.116 albertel 2990: $folder='supplemental';
1.117 albertel 2991: }
2992: if ($folder =~ /^supplemental$/ &&
1.174 albertel 2993: $env{'form.folderpath'} =~ /^default\&/) {
2994: $env{'form.folderpath'}='supplemental&'.
1.230 albertel 2995: &escape(&mt('Supplemental '.$type.' Documents'));
1.116 albertel 2996: }
1.292 albertel 2997: my $error = &editor($r,$coursenum,$coursedom,$folder,$allowed);
2998: if ($error) {
2999: $r->print('<p><span class="LC_error">'.$error.'</span></p>');
3000: }
1.8 www 3001: if ($allowed) {
1.282 albertel 3002: my $folderseq=
3003: '/uploaded/'.$coursedom.'/'.$coursenum.'/supplemental_'.time.
3004: '.sequence';
1.17 www 3005:
1.282 albertel 3006: my $path = &HTML::Entities::encode($env{'form.folderpath'},'<>&"');
3007: $r->print(<<ENDSUPFORM);
1.285 albertel 3008: <table class="LC_docs_adddocs"><tr>
3009: <th>$lt{'upls'}</th>
3010: <th>$lt{'spec'}</th>
1.17 www 3011: </tr>
1.285 albertel 3012: <tr><td>
1.10 www 3013: <form action="/adm/coursedocs" method="post" enctype="multipart/form-data">
1.286 albertel 3014: <input type="file" name="uploaddoc" size="40" />
1.196 raeburn 3015: <br />
3016: <br />
1.284 albertel 3017: <span class="LC_nobreak">
1.196 raeburn 3018: <label>$lt{'parse'}?
3019: <input type="checkbox" name="parserflag" />
3020: </label>
1.284 albertel 3021: </span>
1.196 raeburn 3022: <br /><br />
3023: $lt{'comment'}:<br />
1.4 www 3024: <textarea cols=50 rows=4 name='comment'>
3025: </textarea>
1.115 albertel 3026: <br />
1.282 albertel 3027: <input type="hidden" name="folderpath" value="$path" />
1.286 albertel 3028: <input type="hidden" name="cmd" value="upload_supplemental" />
1.284 albertel 3029: <span class="LC_nobreak">
1.286 albertel 3030: <input type="submit" value="$lt{'upld'}" />
1.58 albertel 3031: $help{'Uploading_From_Harddrive'}
1.284 albertel 3032: </span>
1.58 albertel 3033: </form>
1.17 www 3034: </td>
1.285 albertel 3035: <td>
1.18 www 3036: <form action="/adm/coursedocs" method="post" name="supnewfolder">
1.282 albertel 3037: <input type="hidden" name="folderpath" value="$path" />
1.256 albertel 3038: <input type="hidden" name="importdetail" value="" />
1.284 albertel 3039: <span class="LC_nobreak">
1.17 www 3040: <input name="newfolder" type="button"
3041: onClick="javascript:makenewfolder(this.form,'$folderseq');"
1.81 www 3042: value="$lt{'newf'}" /> $help{'Adding_Folders'}
1.284 albertel 3043: </span>
1.17 www 3044: </form>
1.214 www 3045: <br /><form action="/adm/coursedocs" method="post" name="supnewext">
1.282 albertel 3046: <input type="hidden" name="folderpath" value="$path" />
1.256 albertel 3047: <input type="hidden" name="importdetail" value="" />
1.284 albertel 3048: <span class="LC_nobreak">
1.18 www 3049: <input name="newext" type="button"
3050: onClick="javascript:makenewext('supnewext');"
1.81 www 3051: value="$lt{'extr'}" /> $help{'Adding_External_Resource'}
1.284 albertel 3052: </span>
1.17 www 3053: </form>
1.214 www 3054: <br /><form action="/adm/coursedocs" method="post" name="supnewsyl">
1.282 albertel 3055: <input type="hidden" name="folderpath" value="$path" />
1.256 albertel 3056: <input type="hidden" name="importdetail"
3057: value="Syllabus=/public/$coursedom/$coursenum/syllabus" />
1.284 albertel 3058: <span class="LC_nobreak">
1.81 www 3059: <input name="newsyl" type="submit" value="$lt{'syll'}" />
1.65 bowersj2 3060: $help{'Syllabus'}
1.284 albertel 3061: </span>
1.58 albertel 3062: </form>
1.214 www 3063: <br /><form action="/adm/coursedocs" method="post" name="subnewaboutme">
1.282 albertel 3064: <input type="hidden" name="folderpath" value="$path" />
1.256 albertel 3065: <input type="hidden" name="importdetail"
3066: value="$plainname=/adm/$udom/$uname/aboutme" />
1.284 albertel 3067: <span class="LC_nobreak">
1.81 www 3068: <input name="newaboutme" type="submit" value="$lt{'mypi'}" />
1.65 bowersj2 3069: $help{'My Personal Info'}
1.284 albertel 3070: </span>
1.58 albertel 3071: </form>
1.17 www 3072: </td></tr>
1.24 www 3073: </table></td></tr>
1.8 www 3074: ENDSUPFORM
3075: }
1.7 www 3076: }
1.286 albertel 3077: $r->print('</table>');
1.18 www 3078: if ($allowed) {
1.287 albertel 3079: $r->print('
3080: <form method="post" name="extimport" action="/adm/coursedocs">
3081: <input type="hidden" name="title" />
3082: <input type="hidden" name="url" />
3083: <input type="hidden" name="useform" />
3084: <input type="hidden" name="residx" />
3085: </form>');
1.18 www 3086: }
1.19 www 3087: } else {
1.188 raeburn 3088: unless ($upload_result eq 'phasetwo') {
1.19 www 3089: # -------------------------------------------------------- This is showdoc mode
1.188 raeburn 3090: $r->print("<h1>".&mt('Uploaded Document').' - '.
1.141 albertel 3091: &Apache::lonnet::gettitle($r->uri).'</h1><p>'.
1.286 albertel 3092: &mt('It is recommended that you use an up-to-date virus scanner before handling this file.')."</p><table>".
3093: &entryline(0,&mt("Click to download or use your browser's Save Link function"),$showdoc).'</table>');
1.188 raeburn 3094: }
1.19 www 3095: }
1.26 www 3096: }
1.224 albertel 3097: $r->print(&Apache::loncommon::end_page());
1.26 www 3098: return OK;
1.1 www 3099: }
3100:
1.224 albertel 3101:
3102: sub editing_js {
3103: my ($udom,$uname) = @_;
3104: my $now = time();
3105:
3106: return <<ENDNEWSCRIPT;
3107: function makenewfolder(targetform,folderseq) {
3108: var foldername=prompt('Name of New Folder','New Folder');
3109: if (foldername) {
1.236 albertel 3110: targetform.importdetail.value=escape(foldername)+"="+folderseq;
1.224 albertel 3111: targetform.submit();
3112: }
3113: }
3114:
3115: function makenewpage(targetform,folderseq) {
3116: var pagename=prompt('Name of New Page','New Page');
3117: if (pagename) {
1.236 albertel 3118: targetform.importdetail.value=escape(pagename)+"="+folderseq;
1.224 albertel 3119: targetform.submit();
3120: }
3121: }
3122:
3123: function makenewext(targetname) {
3124: this.document.forms.extimport.useform.value=targetname;
1.287 albertel 3125: this.document.forms.extimport.title.value='';
3126: this.document.forms.extimport.url.value='';
3127: this.document.forms.extimport.residx.value='';
3128: window.open('/adm/rat/extpickframe.html');
3129: }
3130:
3131: function edittext(targetname,residx,title,url) {
3132: this.document.forms.extimport.useform.value=targetname;
3133: this.document.forms.extimport.residx.value=residx;
3134: this.document.forms.extimport.url.value=url;
3135: this.document.forms.extimport.title.value=title;
1.224 albertel 3136: window.open('/adm/rat/extpickframe.html');
3137: }
3138:
3139: function makeexamupload() {
3140: var title=prompt('Listed Title for the Uploaded Score');
3141: if (title) {
3142: this.document.forms.newexamupload.importdetail.value=
1.236 albertel 3143: escape(title)+'=/res/lib/templates/examupload.problem';
1.224 albertel 3144: this.document.forms.newexamupload.submit();
3145: }
3146: }
3147:
3148: function makesmppage() {
3149: var title=prompt('Listed Title for the Page');
3150: if (title) {
3151: this.document.forms.newsmppg.importdetail.value=
1.236 albertel 3152: escape(title)+'=/adm/$udom/$uname/$now/smppg';
1.224 albertel 3153: this.document.forms.newsmppg.submit();
3154: }
3155: }
3156:
3157: function makesmpproblem() {
3158: var title=prompt('Listed Title for the Problem');
3159: if (title) {
3160: this.document.forms.newsmpproblem.importdetail.value=
1.236 albertel 3161: escape(title)+'=/res/lib/templates/simpleproblem.problem';
1.224 albertel 3162: this.document.forms.newsmpproblem.submit();
3163: }
3164: }
3165:
3166: function makedropbox() {
3167: var title=prompt('Listed Title for the Drop Box');
3168: if (title) {
3169: this.document.forms.newdropbox.importdetail.value=
1.236 albertel 3170: escape(title)+'=/res/lib/templates/DropBox.problem';
1.224 albertel 3171: this.document.forms.newdropbox.submit();
3172: }
3173: }
3174:
3175: function makebulboard() {
3176: var title=prompt('Listed Title for the Bulletin Board');
3177: if (title) {
3178: this.document.forms.newbul.importdetail.value=
1.236 albertel 3179: escape(title)+'=/adm/$udom/$uname/$now/bulletinboard';
1.224 albertel 3180: this.document.forms.newbul.submit();
3181: }
3182: }
3183:
3184: function makeabout() {
1.236 albertel 3185: var user=prompt("Enter user:domain for User's 'About Me' Page");
1.224 albertel 3186: if (user) {
3187: var comp=new Array();
1.236 albertel 3188: comp=user.split(':');
1.224 albertel 3189: if ((typeof(comp[0])!=undefined) && (typeof(comp[1])!=undefined)) {
3190: if ((comp[0]) && (comp[1])) {
3191: this.document.forms.newaboutsomeone.importdetail.value=
1.236 albertel 3192: 'About '+escape(user)+'=/adm/'+comp[1]+'/'+comp[0]+'/aboutme';
1.224 albertel 3193: this.document.forms.newaboutsomeone.submit();
3194: } else {
1.236 albertel 3195: alert("Not a valid user:domain");
1.224 albertel 3196: }
3197: } else {
1.236 albertel 3198: alert("Please enter both user and domain in the format user:domain");
1.224 albertel 3199: }
3200: }
3201: }
3202:
3203: function makeims() {
3204: var caller = document.forms.ims.folder.value;
3205: var newlocation = "/adm/imsimportdocs?folder="+caller+"&phase=one";
3206: newWindow = window.open("","IMSimport","HEIGHT=700,WIDTH=750,scrollbars=yes");
3207: newWindow.location.href = newlocation;
3208: }
3209:
3210:
3211: function finishpick() {
3212: var title=this.document.forms.extimport.title.value;
3213: var url=this.document.forms.extimport.url.value;
3214: var form=this.document.forms.extimport.useform.value;
1.287 albertel 3215: var residx=this.document.forms.extimport.residx.value;
3216: eval('this.document.forms.'+form+'.importdetail.value="'+title+'='+url+'='+residx+'";this.document.forms.'+form+'.submit();');
1.224 albertel 3217: }
3218:
3219: function changename(folderpath,index,oldtitle,container,pagesymb) {
3220: var title=prompt('New Title',oldtitle);
3221: if (title) {
1.281 albertel 3222: this.document.forms.renameform.markcopy.value=-1;
1.224 albertel 3223: this.document.forms.renameform.title.value=title;
3224: this.document.forms.renameform.cmd.value='rename_'+index;
3225: if (container == 'sequence') {
3226: this.document.forms.renameform.folderpath.value=folderpath;
3227: }
3228: if (container == 'page') {
3229: this.document.forms.renameform.pagepath.value=folderpath;
3230: this.document.forms.renameform.pagesymb.value=pagesymb;
3231: }
3232: this.document.forms.renameform.submit();
3233: }
3234: }
3235:
1.291 albertel 3236: function removeres(folderpath,index,oldtitle,container,pagesymb,skip_confirm) {
3237: if (skip_confirm || confirm('WARNING: Removing a resource makes associated grades and scores inaccessible!\\nRemove "'+oldtitle+'"?')) {
1.281 albertel 3238: this.document.forms.renameform.markcopy.value=-1;
1.224 albertel 3239: this.document.forms.renameform.cmd.value='del_'+index;
3240: if (container == 'sequence') {
3241: this.document.forms.renameform.folderpath.value=folderpath;
3242: }
3243: if (container == 'page') {
3244: this.document.forms.renameform.pagepath.value=folderpath;
3245: this.document.forms.renameform.pagesymb.value=pagesymb;
3246: }
3247: this.document.forms.renameform.submit();
3248: }
3249: }
3250:
1.291 albertel 3251: function cutres(folderpath,index,oldtitle,container,pagesymb,folder,skip_confirm) {
3252: if (skip_confirm || confirm('WARNING: Cutting a resource makes associated grades and scores inaccessible!\\nGrades remain inaccessible if resource is pasted into another folder.\\nCut "'+oldtitle+'"?')) {
1.224 albertel 3253: this.document.forms.renameform.cmd.value='cut_'+index;
3254: this.document.forms.renameform.markcopy.value=index;
1.281 albertel 3255: this.document.forms.renameform.copyfolder.value=folder+'.'+container;
1.224 albertel 3256: if (container == 'sequence') {
3257: this.document.forms.renameform.folderpath.value=folderpath;
3258: }
3259: if (container == 'page') {
3260: this.document.forms.renameform.pagepath.value=folderpath;
3261: this.document.forms.renameform.pagesymb.value=pagesymb;
3262: }
3263: this.document.forms.renameform.submit();
3264: }
3265: }
3266:
1.281 albertel 3267: function markcopy(folderpath,index,oldtitle,container,pagesymb,folder) {
1.224 albertel 3268: this.document.forms.renameform.markcopy.value=index;
1.281 albertel 3269: this.document.forms.renameform.copyfolder.value=folder+'.'+container;
1.224 albertel 3270: if (container == 'sequence') {
3271: this.document.forms.renameform.folderpath.value=folderpath;
3272: }
3273: if (container == 'page') {
3274: this.document.forms.renameform.pagepath.value=folderpath;
3275: this.document.forms.renameform.pagesymb.value=pagesymb;
3276: }
3277: this.document.forms.renameform.submit();
3278: }
3279:
3280: ENDNEWSCRIPT
3281: }
1.1 www 3282: 1;
3283: __END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>