Annotation of loncom/interface/loncommon.pm, revision 1.556
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.556 ! raeburn 4: # $Id: loncommon.pm,v 1.555 2007/07/28 21:38:29 raeburn Exp $
1.10 albertel 5: #
6: # Copyright Michigan State University Board of Trustees
7: #
8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
9: #
10: # LON-CAPA is free software; you can redistribute it and/or modify
11: # it under the terms of the GNU General Public License as published by
12: # the Free Software Foundation; either version 2 of the License, or
13: # (at your option) any later version.
14: #
15: # LON-CAPA is distributed in the hope that it will be useful,
16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18: # GNU General Public License for more details.
19: #
20: # You should have received a copy of the GNU General Public License
21: # along with LON-CAPA; if not, write to the Free Software
22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23: #
24: # /home/httpd/html/adm/gpl.txt
25: #
26: # http://www.lon-capa.org/
27: #
1.1 albertel 28:
29: # Makes a table out of the previous attempts
1.2 albertel 30: # Inputs result_from_symbread, user, domain, course_id
1.16 harris41 31: # Reads in non-network-related .tab files
1.1 albertel 32:
1.35 matthew 33: # POD header:
34:
1.45 matthew 35: =pod
36:
1.35 matthew 37: =head1 NAME
38:
39: Apache::loncommon - pile of common routines
40:
41: =head1 SYNOPSIS
42:
1.112 bowersj2 43: Common routines for manipulating connections, student answers,
44: domains, common Javascript fragments, etc.
1.35 matthew 45:
1.112 bowersj2 46: =head1 OVERVIEW
1.35 matthew 47:
1.112 bowersj2 48: A collection of commonly used subroutines that don't have a natural
49: home anywhere else. This collection helps remove
1.35 matthew 50: redundancy from other modules and increase efficiency of memory usage.
51:
52: =cut
53:
54: # End of POD header
1.1 albertel 55: package Apache::loncommon;
56:
57: use strict;
1.258 albertel 58: use Apache::lonnet;
1.46 matthew 59: use GDBM_File;
1.51 www 60: use POSIX qw(strftime mktime);
1.82 www 61: use Apache::lonmenu();
1.498 albertel 62: use Apache::lonenc();
1.117 www 63: use Apache::lonlocal;
1.139 matthew 64: use HTML::Entities;
1.334 albertel 65: use Apache::lonhtmlcommon();
66: use Apache::loncoursedata();
1.344 albertel 67: use Apache::lontexconvert();
1.444 albertel 68: use Apache::lonclonecourse();
1.479 albertel 69: use LONCAPA qw(:DEFAULT :match);
1.117 www 70:
1.517 raeburn 71: # ---------------------------------------------- Designs
72: use vars qw(%defaultdesign);
73:
1.22 www 74: my $readit;
75:
1.517 raeburn 76:
1.157 matthew 77: ##
78: ## Global Variables
79: ##
1.46 matthew 80:
1.20 www 81: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12 harris41 82: my %language;
1.124 www 83: my %supported_language;
1.12 harris41 84: my %cprtag;
1.192 taceyjo1 85: my %scprtag;
1.351 www 86: my %fe; my %fd; my %fm;
1.41 ng 87: my %category_extensions;
1.12 harris41 88:
1.46 matthew 89: # ---------------------------------------------- Thesaurus variables
1.144 matthew 90: #
91: # %Keywords:
92: # A hash used by &keyword to determine if a word is considered a keyword.
93: # $thesaurus_db_file
94: # Scalar containing the full path to the thesaurus database.
1.46 matthew 95:
96: my %Keywords;
97: my $thesaurus_db_file;
98:
1.144 matthew 99: #
100: # Initialize values from language.tab, copyright.tab, filetypes.tab,
101: # thesaurus.tab, and filecategories.tab.
102: #
1.18 www 103: BEGIN {
1.46 matthew 104: # Variable initialization
105: $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db";
106: #
1.22 www 107: unless ($readit) {
1.12 harris41 108: # ------------------------------------------------------------------- languages
109: {
1.158 raeburn 110: my $langtabfile = $Apache::lonnet::perlvar{'lonTabDir'}.
111: '/language.tab';
112: if ( open(my $fh,"<$langtabfile") ) {
1.356 albertel 113: while (my $line = <$fh>) {
114: next if ($line=~/^\#/);
115: chomp($line);
116: my ($key,$two,$country,$three,$enc,$val,$sup)=(split(/\t/,$line));
1.158 raeburn 117: $language{$key}=$val.' - '.$enc;
118: if ($sup) {
119: $supported_language{$key}=$sup;
120: }
121: }
122: close($fh);
123: }
1.12 harris41 124: }
125: # ------------------------------------------------------------------ copyrights
126: {
1.158 raeburn 127: my $copyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
128: '/copyright.tab';
129: if ( open (my $fh,"<$copyrightfile") ) {
1.356 albertel 130: while (my $line = <$fh>) {
131: next if ($line=~/^\#/);
132: chomp($line);
133: my ($key,$val)=(split(/\s+/,$line,2));
1.158 raeburn 134: $cprtag{$key}=$val;
135: }
136: close($fh);
137: }
1.12 harris41 138: }
1.351 www 139: # ----------------------------------------------------------- source copyrights
1.192 taceyjo1 140: {
141: my $sourcecopyrightfile = $Apache::lonnet::perlvar{'lonIncludes'}.
142: '/source_copyright.tab';
143: if ( open (my $fh,"<$sourcecopyrightfile") ) {
1.356 albertel 144: while (my $line = <$fh>) {
145: next if ($line =~ /^\#/);
146: chomp($line);
147: my ($key,$val)=(split(/\s+/,$line,2));
1.192 taceyjo1 148: $scprtag{$key}=$val;
149: }
150: close($fh);
151: }
152: }
1.63 www 153:
1.517 raeburn 154: # -------------------------------------------------------------- default domain designs
1.63 www 155: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
1.517 raeburn 156: my $designfile = $designdir.'/default.tab';
157: if ( open (my $fh,"<$designfile") ) {
158: while (my $line = <$fh>) {
159: next if ($line =~ /^\#/);
160: chomp($line);
161: my ($key,$val)=(split(/\=/,$line));
162: if ($val) { $defaultdesign{$key}=$val; }
163: }
164: close($fh);
1.63 www 165: }
166:
1.15 harris41 167: # ------------------------------------------------------------- file categories
168: {
1.158 raeburn 169: my $categoryfile = $Apache::lonnet::perlvar{'lonTabDir'}.
170: '/filecategories.tab';
171: if ( open (my $fh,"<$categoryfile") ) {
1.356 albertel 172: while (my $line = <$fh>) {
173: next if ($line =~ /^\#/);
174: chomp($line);
175: my ($extension,$category)=(split(/\s+/,$line,2));
1.158 raeburn 176: push @{$category_extensions{lc($category)}},$extension;
177: }
178: close($fh);
179: }
180:
1.15 harris41 181: }
1.12 harris41 182: # ------------------------------------------------------------------ file types
183: {
1.158 raeburn 184: my $typesfile = $Apache::lonnet::perlvar{'lonTabDir'}.
185: '/filetypes.tab';
186: if ( open (my $fh,"<$typesfile") ) {
1.356 albertel 187: while (my $line = <$fh>) {
188: next if ($line =~ /^\#/);
189: chomp($line);
190: my ($ending,$emb,$mime,$descr)=split(/\s+/,$line,4);
1.158 raeburn 191: if ($descr ne '') {
192: $fe{$ending}=lc($emb);
193: $fd{$ending}=$descr;
1.351 www 194: if ($mime ne 'unk') { $fm{$ending}=$mime; }
1.158 raeburn 195: }
196: }
197: close($fh);
198: }
1.12 harris41 199: }
1.22 www 200: &Apache::lonnet::logthis(
1.46 matthew 201: "<font color=yellow>INFO: Read file types</font>");
1.22 www 202: $readit=1;
1.46 matthew 203: } # end of unless($readit)
1.32 matthew 204:
205: }
1.112 bowersj2 206:
1.42 matthew 207: ###############################################################
208: ## HTML and Javascript Helper Functions ##
209: ###############################################################
210:
211: =pod
212:
1.112 bowersj2 213: =head1 HTML and Javascript Functions
1.42 matthew 214:
1.112 bowersj2 215: =over 4
216:
217: =item * browser_and_searcher_javascript ()
218:
219: X<browsing, javascript>X<searching, javascript>Returns a string
220: containing javascript with two functions, C<openbrowser> and
221: C<opensearcher>. Returned string does not contain E<lt>scriptE<gt>
222: tags.
1.42 matthew 223:
1.112 bowersj2 224: =item * openbrowser(formname,elementname,only,omit) [javascript]
1.42 matthew 225:
226: inputs: formname, elementname, only, omit
227:
228: formname and elementname indicate the name of the html form and name of
229: the element that the results of the browsing selection are to be placed in.
230:
231: Specifying 'only' will restrict the browser to displaying only files
1.185 www 232: with the given extension. Can be a comma separated list.
1.42 matthew 233:
234: Specifying 'omit' will restrict the browser to NOT displaying files
1.185 www 235: with the given extension. Can be a comma separated list.
1.42 matthew 236:
1.112 bowersj2 237: =item * opensearcher(formname, elementname) [javascript]
1.42 matthew 238:
239: Inputs: formname, elementname
240:
241: formname and elementname specify the name of the html form and the name
242: of the element the selection from the search results will be placed in.
1.542 raeburn 243:
1.42 matthew 244: =cut
245:
246: sub browser_and_searcher_javascript {
1.199 albertel 247: my ($mode)=@_;
248: if (!defined($mode)) { $mode='edit'; }
1.453 albertel 249: my $resurl=&escape_single(&lastresurl());
1.42 matthew 250: return <<END;
1.219 albertel 251: // <!-- BEGIN LON-CAPA Internal
1.50 matthew 252: var editbrowser = null;
1.135 albertel 253: function openbrowser(formname,elementname,only,omit,titleelement) {
1.170 www 254: var url = '$resurl/?';
1.42 matthew 255: if (editbrowser == null) {
256: url += 'launch=1&';
257: }
258: url += 'catalogmode=interactive&';
1.199 albertel 259: url += 'mode=$mode&';
1.42 matthew 260: url += 'form=' + formname + '&';
261: if (only != null) {
262: url += 'only=' + only + '&';
1.217 albertel 263: } else {
264: url += 'only=&';
265: }
1.42 matthew 266: if (omit != null) {
267: url += 'omit=' + omit + '&';
1.217 albertel 268: } else {
269: url += 'omit=&';
270: }
1.135 albertel 271: if (titleelement != null) {
272: url += 'titleelement=' + titleelement + '&';
1.217 albertel 273: } else {
274: url += 'titleelement=&';
275: }
1.42 matthew 276: url += 'element=' + elementname + '';
277: var title = 'Browser';
1.435 albertel 278: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 279: options += ',width=700,height=600';
280: editbrowser = open(url,title,options,'1');
281: editbrowser.focus();
282: }
283: var editsearcher;
1.135 albertel 284: function opensearcher(formname,elementname,titleelement) {
1.42 matthew 285: var url = '/adm/searchcat?';
286: if (editsearcher == null) {
287: url += 'launch=1&';
288: }
289: url += 'catalogmode=interactive&';
1.199 albertel 290: url += 'mode=$mode&';
1.42 matthew 291: url += 'form=' + formname + '&';
1.135 albertel 292: if (titleelement != null) {
293: url += 'titleelement=' + titleelement + '&';
1.217 albertel 294: } else {
295: url += 'titleelement=&';
296: }
1.42 matthew 297: url += 'element=' + elementname + '';
298: var title = 'Search';
1.435 albertel 299: var options = 'scrollbars=1,resizable=1,menubar=0,toolbar=1,location=1';
1.42 matthew 300: options += ',width=700,height=600';
301: editsearcher = open(url,title,options,'1');
302: editsearcher.focus();
303: }
1.219 albertel 304: // END LON-CAPA Internal -->
1.42 matthew 305: END
1.170 www 306: }
307:
308: sub lastresurl {
1.258 albertel 309: if ($env{'environment.lastresurl'}) {
310: return $env{'environment.lastresurl'}
1.170 www 311: } else {
312: return '/res';
313: }
314: }
315:
316: sub storeresurl {
317: my $resurl=&Apache::lonnet::clutter(shift);
318: unless ($resurl=~/^\/res/) { return 0; }
319: $resurl=~s/\/$//;
320: &Apache::lonnet::put('environment',{'lastresurl' => $resurl});
321: &Apache::lonnet::appenv('environment.lastresurl' => $resurl);
322: return 1;
1.42 matthew 323: }
324:
1.74 www 325: sub studentbrowser_javascript {
1.111 www 326: unless (
1.258 albertel 327: (($env{'request.course.id'}) &&
1.302 albertel 328: (&Apache::lonnet::allowed('srm',$env{'request.course.id'})
329: || &Apache::lonnet::allowed('srm',$env{'request.course.id'}.
330: '/'.$env{'request.course.sec'})
331: ))
1.258 albertel 332: || ($env{'request.role'}=~/^(au|dc|su)/)
1.111 www 333: ) { return ''; }
1.74 www 334: return (<<'ENDSTDBRW');
335: <script type="text/javascript" language="Javascript" >
336: var stdeditbrowser;
1.111 www 337: function openstdbrowser(formname,uname,udom,roleflag) {
1.74 www 338: var url = '/adm/pickstudent?';
339: var filter;
340: eval('filter=document.'+formname+'.'+uname+'.value;');
341: if (filter != null) {
342: if (filter != '') {
343: url += 'filter='+filter+'&';
344: }
345: }
346: url += 'form=' + formname + '&unameelement='+uname+
347: '&udomelement='+udom;
1.111 www 348: if (roleflag) { url+="&roles=1"; }
1.102 www 349: var title = 'Student_Browser';
1.74 www 350: var options = 'scrollbars=1,resizable=1,menubar=0';
351: options += ',width=700,height=600';
352: stdeditbrowser = open(url,title,options,'1');
353: stdeditbrowser.focus();
354: }
355: </script>
356: ENDSTDBRW
357: }
1.42 matthew 358:
1.74 www 359: sub selectstudent_link {
1.111 www 360: my ($form,$unameele,$udomele)=@_;
1.258 albertel 361: if ($env{'request.course.id'}) {
1.302 albertel 362: if (!&Apache::lonnet::allowed('srm',$env{'request.course.id'})
363: && !&Apache::lonnet::allowed('srm',$env{'request.course.id'}.
364: '/'.$env{'request.course.sec'})) {
1.111 www 365: return '';
366: }
367: return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
1.119 www 368: '","'.$udomele.'");'."'>".&mt('Select User')."</a>";
1.74 www 369: }
1.258 albertel 370: if ($env{'request.role'}=~/^(au|dc|su)/) {
1.111 www 371: return "<a href='".'javascript:openstdbrowser("'.$form.'","'.$unameele.
1.119 www 372: '","'.$udomele.'",1);'."'>".&mt('Select User')."</a>";
1.111 www 373: }
374: return '';
1.91 www 375: }
376:
377: sub coursebrowser_javascript {
1.468 raeburn 378: my ($domainfilter,$sec_element,$formname)=@_;
1.377 raeburn 379: my $crs_or_grp_alert = &mt('Please select the type of LON-CAPA entity - Course or Group - for which you wish to add/modify a user role');
1.468 raeburn 380: my $output = '
1.538 albertel 381: <script type="text/javascript">
1.468 raeburn 382: var stdeditbrowser;'."\n";
383: $output .= <<"ENDSTDBRW";
1.377 raeburn 384: function opencrsbrowser(formname,uname,udom,desc,extra_element,multflag,crstype) {
1.91 www 385: var url = '/adm/pickcourse?';
1.468 raeburn 386: var domainfilter = '';
387: var formid = getFormIdByName(formname);
388: if (formid > -1) {
389: var domid = getIndexByName(formid,udom);
390: if (domid > -1) {
391: if (document.forms[formid].elements[domid].type == 'select-one') {
392: domainfilter=document.forms[formid].elements[domid].options[document.forms[formid].elements[domid].selectedIndex].value;
393: }
394: if (document.forms[formid].elements[domid].type == 'hidden') {
395: domainfilter=document.forms[formid].elements[domid].value;
396: }
397: }
1.91 www 398: }
1.128 albertel 399: if (domainfilter != null) {
400: if (domainfilter != '') {
401: url += 'domainfilter='+domainfilter+'&';
402: }
403: }
1.91 www 404: url += 'form=' + formname + '&cnumelement='+uname+
1.187 albertel 405: '&cdomelement='+udom+
406: '&cnameelement='+desc;
1.468 raeburn 407: if (extra_element !=null && extra_element != '') {
408: if (formname == 'rolechoice') {
409: url += '&roleelement='+extra_element;
410: if (domainfilter == null || domainfilter == '') {
411: url += '&domainfilter='+extra_element;
412: }
1.234 raeburn 413: }
1.468 raeburn 414: else {
415: if (formname == 'portform') {
416: url += '&setroles='+extra_element;
417: }
418: }
1.230 raeburn 419: }
1.293 raeburn 420: if (multflag !=null && multflag != '') {
421: url += '&multiple='+multflag;
422: }
1.377 raeburn 423: if (crstype == 'Course/Group') {
424: if (formname == 'cu') {
425: crstype = document.cu.crstype.options[document.cu.crstype.selectedIndex].value;
426: if (crstype == "") {
427: alert("$crs_or_grp_alert");
428: return;
429: }
430: }
431: }
432: if (crstype !=null && crstype != '') {
433: url += '&type='+crstype;
434: }
1.102 www 435: var title = 'Course_Browser';
1.91 www 436: var options = 'scrollbars=1,resizable=1,menubar=0';
437: options += ',width=700,height=600';
438: stdeditbrowser = open(url,title,options,'1');
439: stdeditbrowser.focus();
440: }
1.468 raeburn 441:
442: function getFormIdByName(formname) {
443: for (var i=0;i<document.forms.length;i++) {
444: if (document.forms[i].name == formname) {
445: return i;
446: }
447: }
448: return -1;
449: }
450:
451: function getIndexByName(formid,item) {
452: for (var i=0;i<document.forms[formid].elements.length;i++) {
453: if (document.forms[formid].elements[i].name == item) {
454: return i;
455: }
456: }
457: return -1;
458: }
1.91 www 459: ENDSTDBRW
1.468 raeburn 460: if ($sec_element ne '') {
461: $output .= &setsec_javascript($sec_element,$formname);
462: }
463: $output .= '
464: </script>';
465: return $output;
466: }
467:
468: sub setsec_javascript {
469: my ($sec_element,$formname) = @_;
470: my $setsections = qq|
471: function setSect(sectionlist) {
472: var sectionsArray = sectionlist.split(",");
473: var numSections = sectionsArray.length;
474: document.$formname.$sec_element.length = 0;
475: if (numSections == 0) {
476: document.$formname.$sec_element.multiple=false;
477: document.$formname.$sec_element.size=1;
478: document.$formname.$sec_element.options[0] = new Option('No existing sections','',false,false)
479: } else {
480: if (numSections == 1) {
481: document.$formname.$sec_element.multiple=false;
482: document.$formname.$sec_element.size=1;
483: document.$formname.$sec_element.options[0] = new Option('Select','',true,true);
484: document.$formname.$sec_element.options[1] = new Option('No section','',false,false)
485: document.$formname.$sec_element.options[2] = new Option(sectionsArray[0],sectionsArray[0],false,false);
486: } else {
487: for (var i=0; i<numSections; i++) {
488: document.$formname.$sec_element.options[i] = new Option(sectionsArray[i],sectionsArray[i],false,false)
489: }
490: document.$formname.$sec_element.multiple=true
491: if (numSections < 3) {
492: document.$formname.$sec_element.size=numSections;
493: } else {
494: document.$formname.$sec_element.size=3;
495: }
496: document.$formname.$sec_element.options[0].selected = false
497: }
498: }
1.91 www 499: }
1.468 raeburn 500: |;
501: return $setsections;
502: }
503:
1.91 www 504:
505: sub selectcourse_link {
1.377 raeburn 506: my ($form,$unameele,$udomele,$desc,$extra_element,$multflag,$selecttype)=@_;
1.492 albertel 507: return "<a href='".'javascript:opencrsbrowser("'.$form.'","'.$unameele.
508: '","'.$udomele.'","'.$desc.'","'.$extra_element.'","'.$multflag.'","'.$selecttype.'");'."'>".&mt('Select Course')."</a>";
1.74 www 509: }
1.42 matthew 510:
1.273 raeburn 511: sub check_uncheck_jscript {
512: my $jscript = <<"ENDSCRT";
513: function checkAll(field) {
514: if (field.length > 0) {
515: for (i = 0; i < field.length; i++) {
516: field[i].checked = true ;
517: }
518: } else {
519: field.checked = true
520: }
521: }
522:
523: function uncheckAll(field) {
524: if (field.length > 0) {
525: for (i = 0; i < field.length; i++) {
526: field[i].checked = false ;
1.543 albertel 527: }
528: } else {
1.273 raeburn 529: field.checked = false ;
530: }
531: }
532: ENDSCRT
533: return $jscript;
534: }
535:
536:
1.42 matthew 537: =pod
1.36 matthew 538:
1.112 bowersj2 539: =item * linked_select_forms(...)
1.36 matthew 540:
541: linked_select_forms returns a string containing a <script></script> block
542: and html for two <select> menus. The select menus will be linked in that
543: changing the value of the first menu will result in new values being placed
544: in the second menu. The values in the select menu will appear in alphabetical
545: order.
546:
547: linked_select_forms takes the following ordered inputs:
548:
549: =over 4
550:
1.112 bowersj2 551: =item * $formname, the name of the <form> tag
1.36 matthew 552:
1.112 bowersj2 553: =item * $middletext, the text which appears between the <select> tags
1.36 matthew 554:
1.112 bowersj2 555: =item * $firstdefault, the default value for the first menu
1.36 matthew 556:
1.112 bowersj2 557: =item * $firstselectname, the name of the first <select> tag
1.36 matthew 558:
1.112 bowersj2 559: =item * $secondselectname, the name of the second <select> tag
1.36 matthew 560:
1.112 bowersj2 561: =item * $hashref, a reference to a hash containing the data for the menus.
1.36 matthew 562:
1.41 ng 563: =back
564:
1.36 matthew 565: Below is an example of such a hash. Only the 'text', 'default', and
566: 'select2' keys must appear as stated. keys(%menu) are the possible
567: values for the first select menu. The text that coincides with the
1.41 ng 568: first menu value is given in $menu{$choice1}->{'text'}. The values
1.36 matthew 569: and text for the second menu are given in the hash pointed to by
570: $menu{$choice1}->{'select2'}.
571:
1.112 bowersj2 572: my %menu = ( A1 => { text =>"Choice A1" ,
573: default => "B3",
574: select2 => {
575: B1 => "Choice B1",
576: B2 => "Choice B2",
577: B3 => "Choice B3",
578: B4 => "Choice B4"
579: }
580: },
581: A2 => { text =>"Choice A2" ,
582: default => "C2",
583: select2 => {
584: C1 => "Choice C1",
585: C2 => "Choice C2",
586: C3 => "Choice C3"
587: }
588: },
589: A3 => { text =>"Choice A3" ,
590: default => "D6",
591: select2 => {
592: D1 => "Choice D1",
593: D2 => "Choice D2",
594: D3 => "Choice D3",
595: D4 => "Choice D4",
596: D5 => "Choice D5",
597: D6 => "Choice D6",
598: D7 => "Choice D7"
599: }
600: }
601: );
1.36 matthew 602:
603: =cut
604:
605: sub linked_select_forms {
606: my ($formname,
607: $middletext,
608: $firstdefault,
609: $firstselectname,
610: $secondselectname,
611: $hashref
612: ) = @_;
613: my $second = "document.$formname.$secondselectname";
614: my $first = "document.$formname.$firstselectname";
615: # output the javascript to do the changing
616: my $result = '';
1.219 albertel 617: $result.="<script type=\"text/javascript\">\n";
1.36 matthew 618: $result.="var select2data = new Object();\n";
619: $" = '","';
620: my $debug = '';
621: foreach my $s1 (sort(keys(%$hashref))) {
622: $result.="select2data.d_$s1 = new Object();\n";
623: $result.="select2data.d_$s1.def = new String('".
624: $hashref->{$s1}->{'default'}."');\n";
625: $result.="select2data.d_$s1.values = new Array(";
626: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } ));
627: $result.="\"@s2values\");\n";
628: $result.="select2data.d_$s1.texts = new Array(";
629: my @s2texts;
630: foreach my $value (@s2values) {
631: push @s2texts, $hashref->{$s1}->{'select2'}->{$value};
632: }
633: $result.="\"@s2texts\");\n";
634: }
635: $"=' ';
636: $result.= <<"END";
637:
638: function select1_changed() {
639: // Determine new choice
640: var newvalue = "d_" + $first.value;
641: // update select2
642: var values = select2data[newvalue].values;
643: var texts = select2data[newvalue].texts;
644: var select2def = select2data[newvalue].def;
645: var i;
646: // out with the old
647: for (i = 0; i < $second.options.length; i++) {
648: $second.options[i] = null;
649: }
650: // in with the nuclear
651: for (i=0;i<values.length; i++) {
652: $second.options[i] = new Option(values[i]);
1.143 matthew 653: $second.options[i].value = values[i];
1.36 matthew 654: $second.options[i].text = texts[i];
655: if (values[i] == select2def) {
656: $second.options[i].selected = true;
657: }
658: }
659: }
660: </script>
661: END
662: # output the initial values for the selection lists
663: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n";
664: foreach my $value (sort(keys(%$hashref))) {
665: $result.=" <option value=\"$value\" ";
1.253 albertel 666: $result.=" selected=\"selected\" " if ($value eq $firstdefault);
1.119 www 667: $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
1.36 matthew 668: }
669: $result .= "</select>\n";
670: my %select2 = %{$hashref->{$firstdefault}->{'select2'}};
671: $result .= $middletext;
672: $result .= "<select size=\"1\" name=\"$secondselectname\">\n";
673: my $seconddefault = $hashref->{$firstdefault}->{'default'};
674: foreach my $value (sort(keys(%select2))) {
675: $result.=" <option value=\"$value\" ";
1.253 albertel 676: $result.=" selected=\"selected\" " if ($value eq $seconddefault);
1.119 www 677: $result.=">".&mt($select2{$value})."</option>\n";
1.36 matthew 678: }
679: $result .= "</select>\n";
680: # return $debug;
681: return $result;
682: } # end of sub linked_select_forms {
683:
1.45 matthew 684: =pod
1.44 bowersj2 685:
1.112 bowersj2 686: =item * help_open_topic($topic, $text, $stayOnPage, $width, $height)
1.44 bowersj2 687:
1.112 bowersj2 688: Returns a string corresponding to an HTML link to the given help
689: $topic, where $topic corresponds to the name of a .tex file in
690: /home/httpd/html/adm/help/tex, with underscores replaced by
691: spaces.
692:
693: $text will optionally be linked to the same topic, allowing you to
694: link text in addition to the graphic. If you do not want to link
695: text, but wish to specify one of the later parameters, pass an
696: empty string.
697:
698: $stayOnPage is a value that will be interpreted as a boolean. If true,
699: the link will not open a new window. If false, the link will open
700: a new window using Javascript. (Default is false.)
701:
702: $width and $height are optional numerical parameters that will
703: override the width and height of the popped up window, which may
704: be useful for certain help topics with big pictures included.
1.44 bowersj2 705:
706: =cut
707:
708: sub help_open_topic {
1.48 bowersj2 709: my ($topic, $text, $stayOnPage, $width, $height) = @_;
710: $text = "" if (not defined $text);
1.44 bowersj2 711: $stayOnPage = 0 if (not defined $stayOnPage);
1.552 banghart 712: if ($env{'browser.interface'} eq 'textual') {
1.79 www 713: $stayOnPage=1;
714: }
1.44 bowersj2 715: $width = 350 if (not defined $width);
716: $height = 400 if (not defined $height);
717: my $filename = $topic;
718: $filename =~ s/ /_/g;
719:
1.48 bowersj2 720: my $template = "";
721: my $link;
1.159 www 722:
723: $topic=~s/\W/\_/g;
1.44 bowersj2 724:
725: if (!$stayOnPage)
726: {
1.72 bowersj2 727: $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
1.44 bowersj2 728: }
729: else
730: {
1.48 bowersj2 731: $link = "/adm/help/${filename}.hlp";
732: }
733:
734: # Add the text
735: if ($text ne "")
736: {
1.77 www 737: $template .=
738: "<table bgcolor='#3333AA' cellspacing='1' cellpadding='1' border='0'><tr>".
1.436 albertel 739: "<td bgcolor='#5555FF'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
1.48 bowersj2 740: }
741:
742: # Add the graphic
1.179 matthew 743: my $title = &mt('Online Help');
1.215 albertel 744: my $helpicon=&lonhttpdurl("/adm/help/gif/smallHelp.gif");
1.48 bowersj2 745: $template .= <<"ENDTEMPLATE";
1.436 albertel 746: <a target="_top" href="$link" title="$title"><img src="$helpicon" border="0" alt="(Help: $topic)" /></a>
1.44 bowersj2 747: ENDTEMPLATE
1.78 www 748: if ($text ne '') { $template.='</td></tr></table>' };
1.44 bowersj2 749: return $template;
750:
1.106 bowersj2 751: }
752:
753: # This is a quicky function for Latex cheatsheet editing, since it
754: # appears in at least four places
755: sub helpLatexCheatsheet {
756: my $other = shift;
757: my $addOther = '';
758: if ($other) {
759: $addOther = Apache::loncommon::help_open_topic($other, shift,
760: undef, undef, 600) .
761: '</td><td>';
762: }
763: return '<table><tr><td>'.
764: $addOther .
765: &Apache::loncommon::help_open_topic("Greek_Symbols",'Greek Symbols',
766: undef,undef,600)
767: .'</td><td>'.
768: &Apache::loncommon::help_open_topic("Other_Symbols",'Other Symbols',
769: undef,undef,600)
770: .'</td></tr></table>';
1.172 www 771: }
772:
1.430 albertel 773: sub general_help {
774: my $helptopic='Student_Intro';
775: if ($env{'request.role'}=~/^(ca|au)/) {
776: $helptopic='Authoring_Intro';
777: } elsif ($env{'request.role'}=~/^cc/) {
778: $helptopic='Course_Coordination_Intro';
779: }
780: return $helptopic;
781: }
782:
783: sub update_help_link {
784: my ($topic,$component_help,$faq,$bug,$stayOnPage) = @_;
785: my $origurl = $ENV{'REQUEST_URI'};
786: $origurl=~s|^/~|/priv/|;
787: my $timestamp = time;
788: foreach my $datum (\$topic,\$component_help,\$faq,\$bug,\$origurl) {
789: $$datum = &escape($$datum);
790: }
791:
792: my $banner_link = "/adm/helpmenu?page=banner&topic=$topic&component_help=$component_help&faq=$faq&bug=$bug&origurl=$origurl&stamp=$timestamp&stayonpage=$stayOnPage";
793: my $output .= <<"ENDOUTPUT";
794: <script type="text/javascript">
795: banner_link = '$banner_link';
796: </script>
797: ENDOUTPUT
798: return $output;
799: }
800:
801: # now just updates the help link and generates a blue icon
1.193 raeburn 802: sub help_open_menu {
1.430 albertel 803: my ($topic,$component_help,$faq,$bug,$stayOnPage,$width,$height,$text)
1.552 banghart 804: = @_;
1.430 albertel 805: $stayOnPage = 0 if (not defined $stayOnPage);
1.552 banghart 806: # formerly only used pop-up help (stayOnPage = 0)
807: # if environment.remote is on (using remote control UI)
808: # if ($env{'browser.interface'} eq 'textual' ||
809: # $env{'environment.remote'} eq 'off' ) {
810: # $stayOnPage=1;
811: #}
812: # Now making pop-up help the default even with remote control
813: if ($env{'browser.interface'} eq 'textual') {
814: $stayOnPage=1;
1.430 albertel 815: }
816: my $output;
817: if ($component_help) {
818: if (!$text) {
819: $output=&help_open_topic($component_help,undef,$stayOnPage,
820: $width,$height);
821: } else {
822: my $help_text;
823: $help_text=&unescape($topic);
824: $output='<table><tr><td>'.
825: &help_open_topic($component_help,$help_text,$stayOnPage,
826: $width,$height).'</td></tr></table>';
827: }
828: }
829: my $banner_link = &update_help_link($topic,$component_help,$faq,$bug,$stayOnPage);
830: return $output.$banner_link;
831: }
832:
833: sub top_nav_help {
834: my ($text) = @_;
835:
1.436 albertel 836: $text = &mt($text);
837:
838: my $stayOnPage =
839: ($env{'browser.interface'} eq 'textual' ||
840: $env{'environment.remote'} eq 'off' );
841: my $link= ($stayOnPage) ? "javascript:helpMenu('display')"
842: : "javascript:helpMenu('open')";
843: my $banner_link = &update_help_link(undef,undef,undef,undef,$stayOnPage);
844:
1.201 raeburn 845: my $title = &mt('Get help');
1.436 albertel 846:
847: return <<"END";
848: $banner_link
849: <a href="$link" title="$title">$text</a>
850: END
851: }
852:
853: sub help_menu_js {
854: my ($text) = @_;
855:
856: my $stayOnPage =
857: ($env{'browser.interface'} eq 'textual' ||
858: $env{'environment.remote'} eq 'off' );
859:
860: my $width = 620;
861: my $height = 600;
1.430 albertel 862: my $helptopic=&general_help();
863: my $details_link = '/adm/help/'.$helptopic.'.hlp';
1.261 albertel 864: my $nothing=&Apache::lonhtmlcommon::javascript_nothing();
1.331 albertel 865: my $start_page =
866: &Apache::loncommon::start_page('Help Menu', undef,
867: {'frameset' => 1,
868: 'js_ready' => 1,
869: 'add_entries' => {
870: 'border' => '0',
871: 'rows' => "105,*",},});
872: my $end_page =
873: &Apache::loncommon::end_page({'frameset' => 1,
874: 'js_ready' => 1,});
875:
1.436 albertel 876: my $template .= <<"ENDTEMPLATE";
877: <script type="text/javascript">
1.253 albertel 878: // <!-- BEGIN LON-CAPA Internal
879: // <![CDATA[
1.430 albertel 880: var banner_link = '';
1.243 raeburn 881: function helpMenu(target) {
882: var caller = this;
883: if (target == 'open') {
884: var newWindow = null;
885: try {
1.262 albertel 886: newWindow = window.open($nothing,"helpmenu","HEIGHT=$height,WIDTH=$width,resizable=yes,scrollbars=yes" )
1.243 raeburn 887: }
888: catch(error) {
889: writeHelp(caller);
890: return;
891: }
892: if (newWindow) {
893: caller = newWindow;
894: }
1.193 raeburn 895: }
1.243 raeburn 896: writeHelp(caller);
897: return;
898: }
899: function writeHelp(caller) {
1.430 albertel 900: caller.document.writeln('$start_page<frame name="bannerframe" src="'+banner_link+'" /><frame name="bodyframe" src="$details_link" /> $end_page')
1.243 raeburn 901: caller.document.close()
902: caller.focus()
1.193 raeburn 903: }
1.253 albertel 904: // ]]>
1.219 albertel 905: // END LON-CAPA Internal -->
1.436 albertel 906: </script>
1.193 raeburn 907: ENDTEMPLATE
908: return $template;
909: }
910:
1.172 www 911: sub help_open_bug {
912: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 913: unless ($env{'user.adv'}) { return ''; }
1.172 www 914: unless ($Apache::lonnet::perlvar{'BugzillaHost'}) { return ''; }
915: $text = "" if (not defined $text);
916: $stayOnPage = 0 if (not defined $stayOnPage);
1.258 albertel 917: if ($env{'browser.interface'} eq 'textual' ||
918: $env{'environment.remote'} eq 'off' ) {
1.172 www 919: $stayOnPage=1;
920: }
1.184 albertel 921: $width = 600 if (not defined $width);
922: $height = 600 if (not defined $height);
1.172 www 923:
924: $topic=~s/\W+/\+/g;
925: my $link='';
926: my $template='';
1.379 albertel 927: my $url=$Apache::lonnet::perlvar{'BugzillaHost'}.'enter_bug.cgi?product=LON-CAPA&bug_file_loc='.
928: &escape($ENV{'REQUEST_URI'}).'&component='.$topic;
1.172 www 929: if (!$stayOnPage)
930: {
931: $link = "javascript:void(open('$url', 'Bugzilla', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
932: }
933: else
934: {
935: $link = $url;
936: }
937: # Add the text
938: if ($text ne "")
939: {
940: $template .=
941: "<table bgcolor='#AA3333' cellspacing='1' cellpadding='1' border='0'><tr>".
1.436 albertel 942: "<td bgcolor='#FF5555'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
1.172 www 943: }
944:
945: # Add the graphic
1.179 matthew 946: my $title = &mt('Report a Bug');
1.215 albertel 947: my $bugicon=&lonhttpdurl("/adm/lonMisc/smallBug.gif");
1.172 www 948: $template .= <<"ENDTEMPLATE";
1.436 albertel 949: <a target="_top" href="$link" title="$title"><img src="$bugicon" border="0" alt="(Bug: $topic)" /></a>
1.172 www 950: ENDTEMPLATE
951: if ($text ne '') { $template.='</td></tr></table>' };
952: return $template;
953:
954: }
955:
956: sub help_open_faq {
957: my ($topic, $text, $stayOnPage, $width, $height) = @_;
1.258 albertel 958: unless ($env{'user.adv'}) { return ''; }
1.172 www 959: unless ($Apache::lonnet::perlvar{'FAQHost'}) { return ''; }
960: $text = "" if (not defined $text);
961: $stayOnPage = 0 if (not defined $stayOnPage);
1.258 albertel 962: if ($env{'browser.interface'} eq 'textual' ||
963: $env{'environment.remote'} eq 'off' ) {
1.172 www 964: $stayOnPage=1;
965: }
966: $width = 350 if (not defined $width);
967: $height = 400 if (not defined $height);
968:
969: $topic=~s/\W+/\+/g;
970: my $link='';
971: my $template='';
972: my $url=$Apache::lonnet::perlvar{'FAQHost'}.'/fom/cache/'.$topic.'.html';
973: if (!$stayOnPage)
974: {
975: $link = "javascript:void(open('$url', 'FAQ-O-Matic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height,resizable=yes'))";
976: }
977: else
978: {
979: $link = $url;
980: }
981:
982: # Add the text
983: if ($text ne "")
984: {
985: $template .=
1.173 www 986: "<table bgcolor='#337733' cellspacing='1' cellpadding='1' border='0'><tr>".
1.436 albertel 987: "<td bgcolor='#448844'><a target=\"_top\" href=\"$link\"><font color='#FFFFFF' size='2'>$text</font></a>";
1.172 www 988: }
989:
990: # Add the graphic
1.179 matthew 991: my $title = &mt('View the FAQ');
1.215 albertel 992: my $faqicon=&lonhttpdurl("/adm/lonMisc/smallFAQ.gif");
1.172 www 993: $template .= <<"ENDTEMPLATE";
1.436 albertel 994: <a target="_top" href="$link" title="$title"><img src="$faqicon" border="0" alt="(FAQ: $topic)" /></a>
1.172 www 995: ENDTEMPLATE
996: if ($text ne '') { $template.='</td></tr></table>' };
997: return $template;
998:
1.44 bowersj2 999: }
1.37 matthew 1000:
1.180 matthew 1001: ###############################################################
1002: ###############################################################
1003:
1.45 matthew 1004: =pod
1005:
1.256 matthew 1006: =item * change_content_javascript():
1007:
1008: This and the next function allow you to create small sections of an
1009: otherwise static HTML page that you can update on the fly with
1010: Javascript, even in Netscape 4.
1011:
1012: The Javascript fragment returned by this function (no E<lt>scriptE<gt> tag)
1013: must be written to the HTML page once. It will prove the Javascript
1014: function "change(name, content)". Calling the change function with the
1015: name of the section
1016: you want to update, matching the name passed to C<changable_area>, and
1017: the new content you want to put in there, will put the content into
1018: that area.
1019:
1020: B<Note>: Netscape 4 only reserves enough space for the changable area
1021: to contain room for the original contents. You need to "make space"
1022: for whatever changes you wish to make, and be B<sure> to check your
1023: code in Netscape 4. This feature in Netscape 4 is B<not> powerful;
1024: it's adequate for updating a one-line status display, but little more.
1025: This script will set the space to 100% width, so you only need to
1026: worry about height in Netscape 4.
1027:
1028: Modern browsers are much less limiting, and if you can commit to the
1029: user not using Netscape 4, this feature may be used freely with
1030: pretty much any HTML.
1031:
1032: =cut
1033:
1034: sub change_content_javascript {
1035: # If we're on Netscape 4, we need to use Layer-based code
1.258 albertel 1036: if ($env{'browser.type'} eq 'netscape' &&
1037: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1038: return (<<NETSCAPE4);
1039: function change(name, content) {
1040: doc = document.layers[name+"___escape"].layers[0].document;
1041: doc.open();
1042: doc.write(content);
1043: doc.close();
1044: }
1045: NETSCAPE4
1046: } else {
1047: # Otherwise, we need to use semi-standards-compliant code
1048: # (technically, "innerHTML" isn't standard but the equivalent
1049: # is really scary, and every useful browser supports it
1050: return (<<DOMBASED);
1051: function change(name, content) {
1052: element = document.getElementById(name);
1053: element.innerHTML = content;
1054: }
1055: DOMBASED
1056: }
1057: }
1058:
1059: =pod
1060:
1061: =item * changable_area($name, $origContent):
1062:
1063: This provides a "changable area" that can be modified on the fly via
1064: the Javascript code provided in C<change_content_javascript>. $name is
1065: the name you will use to reference the area later; do not repeat the
1066: same name on a given HTML page more then once. $origContent is what
1067: the area will originally contain, which can be left blank.
1068:
1069: =cut
1070:
1071: sub changable_area {
1072: my ($name, $origContent) = @_;
1073:
1.258 albertel 1074: if ($env{'browser.type'} eq 'netscape' &&
1075: $env{'browser.version'} =~ /^4\./) {
1.256 matthew 1076: # If this is netscape 4, we need to use the Layer tag
1077: return "<ilayer width='100%' id='${name}___escape' overflow='none'><layer width='100%' id='$name' overflow='none'>$origContent</layer></ilayer>";
1078: } else {
1079: return "<span id='$name'>$origContent</span>";
1080: }
1081: }
1082:
1083: =pod
1084:
1085: =back
1.542 raeburn 1086:
1.256 matthew 1087: =head1 Excel and CSV file utility routines
1088:
1089: =over 4
1090:
1091: =cut
1092:
1093: ###############################################################
1094: ###############################################################
1095:
1096: =pod
1097:
1.112 bowersj2 1098: =item * csv_translate($text)
1.37 matthew 1099:
1.185 www 1100: Translate $text to allow it to be output as a 'comma separated values'
1.37 matthew 1101: format.
1102:
1103: =cut
1104:
1.180 matthew 1105: ###############################################################
1106: ###############################################################
1.37 matthew 1107: sub csv_translate {
1108: my $text = shift;
1109: $text =~ s/\"/\"\"/g;
1.209 albertel 1110: $text =~ s/\n/ /g;
1.37 matthew 1111: return $text;
1112: }
1.180 matthew 1113:
1114: ###############################################################
1115: ###############################################################
1116:
1117: =pod
1118:
1119: =item * define_excel_formats
1120:
1121: Define some commonly used Excel cell formats.
1122:
1123: Currently supported formats:
1124:
1125: =over 4
1126:
1127: =item header
1128:
1129: =item bold
1130:
1131: =item h1
1132:
1133: =item h2
1134:
1135: =item h3
1136:
1.256 matthew 1137: =item h4
1138:
1139: =item i
1140:
1.180 matthew 1141: =item date
1142:
1143: =back
1144:
1145: Inputs: $workbook
1146:
1147: Returns: $format, a hash reference.
1148:
1149: =cut
1150:
1151: ###############################################################
1152: ###############################################################
1153: sub define_excel_formats {
1154: my ($workbook) = @_;
1155: my $format;
1156: $format->{'header'} = $workbook->add_format(bold => 1,
1157: bottom => 1,
1158: align => 'center');
1159: $format->{'bold'} = $workbook->add_format(bold=>1);
1160: $format->{'h1'} = $workbook->add_format(bold=>1, size=>18);
1161: $format->{'h2'} = $workbook->add_format(bold=>1, size=>16);
1162: $format->{'h3'} = $workbook->add_format(bold=>1, size=>14);
1.255 matthew 1163: $format->{'h4'} = $workbook->add_format(bold=>1, size=>12);
1.246 matthew 1164: $format->{'i'} = $workbook->add_format(italic=>1);
1.180 matthew 1165: $format->{'date'} = $workbook->add_format(num_format=>
1.207 matthew 1166: 'mm/dd/yyyy hh:mm:ss');
1.180 matthew 1167: return $format;
1168: }
1169:
1170: ###############################################################
1171: ###############################################################
1.113 bowersj2 1172:
1173: =pod
1174:
1.256 matthew 1175: =item * create_workbook
1.255 matthew 1176:
1177: Create an Excel worksheet. If it fails, output message on the
1178: request object and return undefs.
1179:
1180: Inputs: Apache request object
1181:
1182: Returns (undef) on failure,
1183: Excel worksheet object, scalar with filename, and formats
1184: from &Apache::loncommon::define_excel_formats on success
1185:
1186: =cut
1187:
1188: ###############################################################
1189: ###############################################################
1190: sub create_workbook {
1191: my ($r) = @_;
1192: #
1193: # Create the excel spreadsheet
1194: my $filename = '/prtspool/'.
1.258 albertel 1195: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.255 matthew 1196: time.'_'.rand(1000000000).'.xls';
1197: my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename);
1198: if (! defined($workbook)) {
1199: $r->log_error("Error creating excel spreadsheet $filename: $!");
1200: $r->print('<p>'.&mt("Unable to create new Excel file. ".
1201: "This error has been logged. ".
1202: "Please alert your LON-CAPA administrator").
1203: '</p>');
1204: return (undef);
1205: }
1206: #
1207: $workbook->set_tempdir('/home/httpd/perl/tmp');
1208: #
1209: my $format = &Apache::loncommon::define_excel_formats($workbook);
1210: return ($workbook,$filename,$format);
1211: }
1212:
1213: ###############################################################
1214: ###############################################################
1215:
1216: =pod
1217:
1.256 matthew 1218: =item * create_text_file
1.113 bowersj2 1219:
1.542 raeburn 1220: Create a file to write to and eventually make available to the user.
1.256 matthew 1221: If file creation fails, outputs an error message on the request object and
1222: return undefs.
1.113 bowersj2 1223:
1.256 matthew 1224: Inputs: Apache request object, and file suffix
1.113 bowersj2 1225:
1.256 matthew 1226: Returns (undef) on failure,
1227: Filehandle and filename on success.
1.113 bowersj2 1228:
1229: =cut
1230:
1.256 matthew 1231: ###############################################################
1232: ###############################################################
1233: sub create_text_file {
1234: my ($r,$suffix) = @_;
1235: if (! defined($suffix)) { $suffix = 'txt'; };
1236: my $fh;
1237: my $filename = '/prtspool/'.
1.258 albertel 1238: $env{'user.name'}.'_'.$env{'user.domain'}.'_'.
1.256 matthew 1239: time.'_'.rand(1000000000).'.'.$suffix;
1240: $fh = Apache::File->new('>/home/httpd'.$filename);
1241: if (! defined($fh)) {
1242: $r->log_error("Couldn't open $filename for output $!");
1243: $r->print("Problems occured in creating the output file. ".
1244: "This error has been logged. ".
1245: "Please alert your LON-CAPA administrator.");
1.113 bowersj2 1246: }
1.256 matthew 1247: return ($fh,$filename)
1.113 bowersj2 1248: }
1249:
1250:
1.256 matthew 1251: =pod
1.113 bowersj2 1252:
1253: =back
1254:
1255: =cut
1.37 matthew 1256:
1257: ###############################################################
1.33 matthew 1258: ## Home server <option> list generating code ##
1259: ###############################################################
1.35 matthew 1260:
1.169 www 1261: # ------------------------------------------
1262:
1263: sub domain_select {
1264: my ($name,$value,$multiple)=@_;
1265: my %domains=map {
1.514 albertel 1266: $_ => $_.' '. &Apache::lonnet::domain($_,'description')
1.512 albertel 1267: } &Apache::lonnet::all_domains();
1.169 www 1268: if ($multiple) {
1269: $domains{''}=&mt('Any domain');
1.550 albertel 1270: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.287 albertel 1271: return &multiple_select_form($name,$value,4,\%domains);
1.169 www 1272: } else {
1.550 albertel 1273: $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))];
1.169 www 1274: return &select_form($name,$value,%domains);
1275: }
1276: }
1277:
1.282 albertel 1278: #-------------------------------------------
1279:
1280: =pod
1281:
1.519 raeburn 1282: =head1 Routines for form select boxes
1283:
1284: =over 4
1285:
1286: =cut
1287:
1.287 albertel 1288: =item * multiple_select_form($name,$value,$size,$hash,$order)
1.282 albertel 1289:
1290: Returns a string containing a <select> element int multiple mode
1291:
1292:
1293: Args:
1294: $name - name of the <select> element
1.506 raeburn 1295: $value - scalar or array ref of values that should already be selected
1.282 albertel 1296: $size - number of rows long the select element is
1.283 albertel 1297: $hash - the elements should be 'option' => 'shown text'
1.282 albertel 1298: (shown text should already have been &mt())
1.506 raeburn 1299: $order - (optional) array ref of the order to show the elements in
1.283 albertel 1300:
1.282 albertel 1301: =cut
1302:
1303: #-------------------------------------------
1.169 www 1304: sub multiple_select_form {
1.284 albertel 1305: my ($name,$value,$size,$hash,$order)=@_;
1.169 www 1306: my %selected = map { $_ => 1 } ref($value)?@{$value}:($value);
1307: my $output='';
1.191 matthew 1308: if (! defined($size)) {
1309: $size = 4;
1.283 albertel 1310: if (scalar(keys(%$hash))<4) {
1311: $size = scalar(keys(%$hash));
1.191 matthew 1312: }
1313: }
1.169 www 1314: $output.="\n<select name='$name' size='$size' multiple='1'>";
1.501 banghart 1315: my @order;
1.506 raeburn 1316: if (ref($order) eq 'ARRAY') {
1317: @order = @{$order};
1318: } else {
1319: @order = sort(keys(%$hash));
1.501 banghart 1320: }
1321: if (exists($$hash{'select_form_order'})) {
1322: @order = @{$$hash{'select_form_order'}};
1323: }
1324:
1.284 albertel 1325: foreach my $key (@order) {
1.356 albertel 1326: $output.='<option value="'.&HTML::Entities::encode($key,'"<>&').'" ';
1.284 albertel 1327: $output.='selected="selected" ' if ($selected{$key});
1328: $output.='>'.$hash->{$key}."</option>\n";
1.169 www 1329: }
1330: $output.="</select>\n";
1331: return $output;
1332: }
1333:
1.88 www 1334: #-------------------------------------------
1335:
1336: =pod
1337:
1.112 bowersj2 1338: =item * select_form($defdom,$name,%hash)
1.88 www 1339:
1340: Returns a string containing a <select name='$name' size='1'> form to
1341: allow a user to select options from a hash option_name => displayed text.
1342: See lonrights.pm for an example invocation and use.
1343:
1344: =cut
1345:
1346: #-------------------------------------------
1347: sub select_form {
1348: my ($def,$name,%hash) = @_;
1349: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1.128 albertel 1350: my @keys;
1351: if (exists($hash{'select_form_order'})) {
1352: @keys=@{$hash{'select_form_order'}};
1353: } else {
1354: @keys=sort(keys(%hash));
1355: }
1.356 albertel 1356: foreach my $key (@keys) {
1357: $selectform.=
1358: '<option value="'.&HTML::Entities::encode($key,'"<>&').'" '.
1359: ($key eq $def ? 'selected="selected" ' : '').
1360: ">".&mt($hash{$key})."</option>\n";
1.88 www 1361: }
1362: $selectform.="</select>";
1363: return $selectform;
1364: }
1365:
1.475 www 1366: # For display filters
1367:
1368: sub display_filter {
1369: if (!$env{'form.show'}) { $env{'form.show'}=10; }
1.477 www 1370: if (!$env{'form.displayfilter'}) { $env{'form.displayfilter'}='currentfolder'; }
1.475 www 1371: return '<nobr><label>'.&mt('Records [_1]',
1372: &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,
1373: (&mt('all'),10,20,50,100,1000,10000))).
1.478 www 1374: '</label></nobr> <nobr>'.
1.475 www 1375: &mt('Filter [_1]',
1.477 www 1376: &select_form($env{'form.displayfilter'},
1377: 'displayfilter',
1378: ('currentfolder' => 'Current folder/page',
1379: 'containing' => 'Containing phrase',
1380: 'none' => 'None'))).
1.478 www 1381: '<input type="text" name="containingphrase" size="30" value="'.&HTML::Entities::encode($env{'form.containingphrase'}).'" /></nobr>';
1.475 www 1382: }
1383:
1.167 www 1384: sub gradeleveldescription {
1385: my $gradelevel=shift;
1386: my %gradelevels=(0 => 'Not specified',
1387: 1 => 'Grade 1',
1388: 2 => 'Grade 2',
1389: 3 => 'Grade 3',
1390: 4 => 'Grade 4',
1391: 5 => 'Grade 5',
1392: 6 => 'Grade 6',
1393: 7 => 'Grade 7',
1394: 8 => 'Grade 8',
1395: 9 => 'Grade 9',
1396: 10 => 'Grade 10',
1397: 11 => 'Grade 11',
1398: 12 => 'Grade 12',
1399: 13 => 'Grade 13',
1400: 14 => '100 Level',
1401: 15 => '200 Level',
1402: 16 => '300 Level',
1403: 17 => '400 Level',
1404: 18 => 'Graduate Level');
1405: return &mt($gradelevels{$gradelevel});
1406: }
1407:
1.163 www 1408: sub select_level_form {
1409: my ($deflevel,$name)=@_;
1410: unless ($deflevel) { $deflevel=0; }
1.167 www 1411: my $selectform = "<select name=\"$name\" size=\"1\">\n";
1412: for (my $i=0; $i<=18; $i++) {
1413: $selectform.="<option value=\"$i\" ".
1.253 albertel 1414: ($i==$deflevel ? 'selected="selected" ' : '').
1.167 www 1415: ">".&gradeleveldescription($i)."</option>\n";
1416: }
1417: $selectform.="</select>";
1418: return $selectform;
1.163 www 1419: }
1.167 www 1420:
1.35 matthew 1421: #-------------------------------------------
1422:
1.45 matthew 1423: =pod
1424:
1.112 bowersj2 1425: =item * select_dom_form($defdom,$name,$includeempty)
1.35 matthew 1426:
1427: Returns a string containing a <select name='$name' size='1'> form to
1428: allow a user to select the domain to preform an operation in.
1429: See loncreateuser.pm for an example invocation and use.
1430:
1.90 www 1431: If the $includeempty flag is set, it also includes an empty choice ("no domain
1432: selected");
1433:
1.35 matthew 1434: =cut
1435:
1436: #-------------------------------------------
1.34 matthew 1437: sub select_dom_form {
1.90 www 1438: my ($defdom,$name,$includeempty) = @_;
1.550 albertel 1439: my @domains = sort {lc($a) cmp lc($b)} (&Apache::lonnet::all_domains());
1.90 www 1440: if ($includeempty) { @domains=('',@domains); }
1.34 matthew 1441: my $selectdomain = "<select name=\"$name\" size=\"1\">\n";
1.356 albertel 1442: foreach my $dom (@domains) {
1443: $selectdomain.="<option value=\"$dom\" ".
1444: ($dom eq $defdom ? 'selected="selected" ' : '').
1445: ">$dom</option>\n";
1.34 matthew 1446: }
1447: $selectdomain.="</select>";
1448: return $selectdomain;
1449: }
1450:
1.35 matthew 1451: #-------------------------------------------
1452:
1.45 matthew 1453: =pod
1454:
1.112 bowersj2 1455: =item * home_server_option_list($domain)
1.35 matthew 1456:
1457: returns a string which contains an <option> list to be used in a
1458: <select> form input. See loncreateuser.pm for an example.
1459:
1460: =cut
1461:
1462: #-------------------------------------------
1.33 matthew 1463: sub home_server_option_list {
1464: my $domain = shift;
1.513 albertel 1465: my %servers = &Apache::lonnet::get_servers($domain,'library');
1.33 matthew 1466: my $result = '';
1.356 albertel 1467: foreach my $hostid (sort(keys(%servers))) {
1.33 matthew 1468: $result.=
1.356 albertel 1469: '<option value="'.$hostid.'">'.
1470: $hostid.' '.$servers{$hostid}."</option>\n";
1.33 matthew 1471: }
1472: return $result;
1473: }
1.112 bowersj2 1474:
1475: =pod
1476:
1.534 albertel 1477: =back
1478:
1.112 bowersj2 1479: =cut
1.87 matthew 1480:
1481: ###############################################################
1.112 bowersj2 1482: ## Decoding User Agent ##
1.87 matthew 1483: ###############################################################
1484:
1485: =pod
1486:
1.112 bowersj2 1487: =head1 Decoding the User Agent
1488:
1489: =over 4
1490:
1491: =item * &decode_user_agent()
1.87 matthew 1492:
1493: Inputs: $r
1494:
1495: Outputs:
1496:
1497: =over 4
1498:
1.112 bowersj2 1499: =item * $httpbrowser
1.87 matthew 1500:
1.112 bowersj2 1501: =item * $clientbrowser
1.87 matthew 1502:
1.112 bowersj2 1503: =item * $clientversion
1.87 matthew 1504:
1.112 bowersj2 1505: =item * $clientmathml
1.87 matthew 1506:
1.112 bowersj2 1507: =item * $clientunicode
1.87 matthew 1508:
1.112 bowersj2 1509: =item * $clientos
1.87 matthew 1510:
1511: =back
1512:
1.157 matthew 1513: =back
1514:
1.87 matthew 1515: =cut
1516:
1517: ###############################################################
1518: ###############################################################
1519: sub decode_user_agent {
1.247 albertel 1520: my ($r)=@_;
1.87 matthew 1521: my @browsertype=split(/\&/,$Apache::lonnet::perlvar{"lonBrowsDet"});
1522: my %mathcap=split(/\&/,$$Apache::lonnet::perlvar{"lonMathML"});
1523: my $httpbrowser=$ENV{"HTTP_USER_AGENT"};
1.247 albertel 1524: if (!$httpbrowser && $r) { $httpbrowser=$r->header_in('User-Agent'); }
1.87 matthew 1525: my $clientbrowser='unknown';
1526: my $clientversion='0';
1527: my $clientmathml='';
1528: my $clientunicode='0';
1529: for (my $i=0;$i<=$#browsertype;$i++) {
1530: my ($bname,$match,$notmatch,$vreg,$minv,$univ)=split(/\:/,$browsertype[$i]);
1531: if (($httpbrowser=~/$match/i) && ($httpbrowser!~/$notmatch/i)) {
1532: $clientbrowser=$bname;
1533: $httpbrowser=~/$vreg/i;
1534: $clientversion=$1;
1535: $clientmathml=($clientversion>=$minv);
1536: $clientunicode=($clientversion>=$univ);
1537: }
1538: }
1539: my $clientos='unknown';
1540: if (($httpbrowser=~/linux/i) ||
1541: ($httpbrowser=~/unix/i) ||
1542: ($httpbrowser=~/ux/i) ||
1543: ($httpbrowser=~/solaris/i)) { $clientos='unix'; }
1544: if (($httpbrowser=~/vax/i) ||
1545: ($httpbrowser=~/vms/i)) { $clientos='vms'; }
1546: if ($httpbrowser=~/next/i) { $clientos='next'; }
1547: if (($httpbrowser=~/mac/i) ||
1548: ($httpbrowser=~/powerpc/i)) { $clientos='mac'; }
1549: if ($httpbrowser=~/win/i) { $clientos='win'; }
1550: if ($httpbrowser=~/embed/i) { $clientos='pda'; }
1551: return ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
1552: $clientunicode,$clientos,);
1553: }
1554:
1.32 matthew 1555: ###############################################################
1556: ## Authentication changing form generation subroutines ##
1557: ###############################################################
1558: ##
1559: ## All of the authform_xxxxxxx subroutines take their inputs in a
1560: ## hash, and have reasonable default values.
1561: ##
1562: ## formname = the name given in the <form> tag.
1.35 matthew 1563: #-------------------------------------------
1564:
1.45 matthew 1565: =pod
1566:
1.112 bowersj2 1567: =head1 Authentication Routines
1568:
1569: =over 4
1570:
1571: =item * authform_xxxxxx
1.35 matthew 1572:
1573: The authform_xxxxxx subroutines provide javascript and html forms which
1574: handle some of the conveniences required for authentication forms.
1575: This is not an optimal method, but it works.
1576:
1577: See loncreateuser.pm for invocation and use examples.
1578:
1579: =over 4
1580:
1.112 bowersj2 1581: =item * authform_header
1.35 matthew 1582:
1.112 bowersj2 1583: =item * authform_authorwarning
1.35 matthew 1584:
1.112 bowersj2 1585: =item * authform_nochange
1.35 matthew 1586:
1.112 bowersj2 1587: =item * authform_kerberos
1.35 matthew 1588:
1.112 bowersj2 1589: =item * authform_internal
1.35 matthew 1590:
1.112 bowersj2 1591: =item * authform_filesystem
1.35 matthew 1592:
1593: =back
1594:
1.157 matthew 1595: =back
1596:
1.35 matthew 1597: =cut
1598:
1599: #-------------------------------------------
1.32 matthew 1600: sub authform_header{
1601: my %in = (
1602: formname => 'cu',
1.80 albertel 1603: kerb_def_dom => '',
1.32 matthew 1604: @_,
1605: );
1606: $in{'formname'} = 'document.' . $in{'formname'};
1607: my $result='';
1.80 albertel 1608:
1609: #---------------------------------------------- Code for upper case translation
1610: my $Javascript_toUpperCase;
1611: unless ($in{kerb_def_dom}) {
1612: $Javascript_toUpperCase =<<"END";
1613: switch (choice) {
1614: case 'krb': currentform.elements[choicearg].value =
1615: currentform.elements[choicearg].value.toUpperCase();
1616: break;
1617: default:
1618: }
1619: END
1620: } else {
1621: $Javascript_toUpperCase = "";
1622: }
1623:
1.165 raeburn 1624: my $radioval = "'nochange'";
1.174 matthew 1625: if (exists($in{'curr_authtype'}) &&
1626: defined($in{'curr_authtype'}) &&
1627: $in{'curr_authtype'} ne '') {
1628: $radioval = "'$in{'curr_authtype'}arg'";
1629: }
1.165 raeburn 1630: my $argfield = 'null';
1631: if ( grep/^mode$/,(keys %in) ) {
1632: if ($in{'mode'} eq 'modifycourse') {
1633: if ( grep/^curr_authtype$/,(keys %in) ) {
1634: $radioval = "'$in{'curr_authtype'}'";
1635: }
1636: if ( grep/^curr_autharg$/,(keys %in) ) {
1637: unless ($in{'curr_autharg'} eq '') {
1638: $argfield = "'$in{'curr_autharg'}'";
1639: }
1640: }
1641: }
1642: }
1643:
1.32 matthew 1644: $result.=<<"END";
1645: var current = new Object();
1.165 raeburn 1646: current.radiovalue = $radioval;
1647: current.argfield = $argfield;
1.32 matthew 1648:
1649: function changed_radio(choice,currentform) {
1650: var choicearg = choice + 'arg';
1651: // If a radio button in changed, we need to change the argfield
1652: if (current.radiovalue != choice) {
1653: current.radiovalue = choice;
1654: if (current.argfield != null) {
1655: currentform.elements[current.argfield].value = '';
1656: }
1657: if (choice == 'nochange') {
1658: current.argfield = null;
1659: } else {
1660: current.argfield = choicearg;
1661: switch(choice) {
1662: case 'krb':
1663: currentform.elements[current.argfield].value =
1664: "$in{'kerb_def_dom'}";
1665: break;
1666: default:
1667: break;
1668: }
1669: }
1670: }
1671: return;
1672: }
1.22 www 1673:
1.32 matthew 1674: function changed_text(choice,currentform) {
1675: var choicearg = choice + 'arg';
1676: if (currentform.elements[choicearg].value !='') {
1.80 albertel 1677: $Javascript_toUpperCase
1.32 matthew 1678: // clear old field
1679: if ((current.argfield != choicearg) && (current.argfield != null)) {
1680: currentform.elements[current.argfield].value = '';
1681: }
1682: current.argfield = choicearg;
1683: }
1684: set_auth_radio_buttons(choice,currentform);
1685: return;
1.20 www 1686: }
1.32 matthew 1687:
1688: function set_auth_radio_buttons(newvalue,currentform) {
1689: var i=0;
1690: while (i < currentform.login.length) {
1691: if (currentform.login[i].value == newvalue) { break; }
1692: i++;
1693: }
1694: if (i == currentform.login.length) {
1695: return;
1696: }
1697: current.radiovalue = newvalue;
1698: currentform.login[i].checked = true;
1699: return;
1700: }
1701: END
1702: return $result;
1703: }
1704:
1705: sub authform_authorwarning{
1706: my $result='';
1.144 matthew 1707: $result='<i>'.
1708: &mt('As a general rule, only authors or co-authors should be '.
1709: 'filesystem authenticated '.
1710: '(which allows access to the server filesystem).')."</i>\n";
1.32 matthew 1711: return $result;
1712: }
1713:
1714: sub authform_nochange{
1715: my %in = (
1716: formname => 'document.cu',
1717: kerb_def_dom => 'MSU.EDU',
1718: @_,
1719: );
1.281 albertel 1720: my $result = '<label>'.&mt('[_1] Do not change login data',
1.144 matthew 1721: '<input type="radio" name="login" value="nochange" '.
1722: 'checked="checked" onclick="'.
1.281 albertel 1723: "javascript:changed_radio('nochange',$in{'formname'});".'" />').
1724: '</label>';
1.32 matthew 1725: return $result;
1726: }
1727:
1728: sub authform_kerberos{
1729: my %in = (
1730: formname => 'document.cu',
1731: kerb_def_dom => 'MSU.EDU',
1.80 albertel 1732: kerb_def_auth => 'krb4',
1.32 matthew 1733: @_,
1734: );
1.165 raeburn 1735: my ($check4,$check5,$krbarg);
1.80 albertel 1736: if ($in{'kerb_def_auth'} eq 'krb5') {
1737: $check5 = " checked=\"on\"";
1738: } else {
1739: $check4 = " checked=\"on\"";
1740: }
1.165 raeburn 1741: $krbarg = $in{'kerb_def_dom'};
1742:
1743: my $krbcheck = "";
1744: if ( grep/^curr_authtype$/,(keys %in) ) {
1745: if ($in{'curr_authtype'} =~ m/^krb/) {
1746: $krbcheck = " checked=\"on\"";
1747: if ( grep/^curr_autharg$/,(keys %in) ) {
1748: $krbarg = $in{'curr_autharg'};
1749: }
1750: }
1751: }
1752:
1.144 matthew 1753: my $jscall = "javascript:changed_radio('krb',$in{'formname'});";
1754: my $result .= &mt
1755: ('[_1] Kerberos authenticated with domain [_2] '.
1.281 albertel 1756: '[_3] Version 4 [_4] Version 5 [_5]',
1757: '<label><input type="radio" name="login" value="krb" '.
1.165 raeburn 1758: 'onclick="'.$jscall.'" onchange="'.$jscall.'"'.$krbcheck.' />',
1.281 albertel 1759: '</label><input type="text" size="10" name="krbarg" '.
1.165 raeburn 1760: 'value="'.$krbarg.'" '.
1.144 matthew 1761: 'onchange="'.$jscall.'" />',
1.281 albertel 1762: '<label><input type="radio" name="krbver" value="4" '.$check4.' />',
1763: '</label><label><input type="radio" name="krbver" value="5" '.$check5.' />',
1764: '</label>');
1.32 matthew 1765: return $result;
1766: }
1767:
1768: sub authform_internal{
1769: my %args = (
1770: formname => 'document.cu',
1771: kerb_def_dom => 'MSU.EDU',
1772: @_,
1773: );
1.165 raeburn 1774:
1775: my $intcheck = "";
1776: my $intarg = 'value=""';
1777: if ( grep/^curr_authtype$/,(keys %args) ) {
1778: if ($args{'curr_authtype'} eq 'int') {
1779: $intcheck = " checked=\"on\"";
1780: if ( grep/^curr_autharg$/,(keys %args) ) {
1781: $intarg = "value=\"$args{'curr_autharg'}\"";
1782: }
1783: }
1784: }
1785:
1.144 matthew 1786: my $jscall = "javascript:changed_radio('int',$args{'formname'});";
1787: my $result.=&mt
1788: ('[_1] Internally authenticated (with initial password [_2])',
1.281 albertel 1789: '<label><input type="radio" name="login" value="int" '.$intcheck.
1.165 raeburn 1790: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.281 albertel 1791: '</label><input type="text" size="10" name="intarg" '.$intarg.
1.165 raeburn 1792: ' onchange="'.$jscall.'" />');
1.32 matthew 1793: return $result;
1794: }
1795:
1796: sub authform_local{
1797: my %in = (
1798: formname => 'document.cu',
1799: kerb_def_dom => 'MSU.EDU',
1800: @_,
1801: );
1.165 raeburn 1802:
1803: my $loccheck = "";
1804: my $locarg = 'value=""';
1805: if ( grep/^curr_authtype$/,(keys %in) ) {
1806: if ($in{'curr_authtype'} eq 'loc') {
1807: $loccheck = " checked=\"on\"";
1808: if ( grep/^curr_autharg$/,(keys %in) ) {
1809: $locarg = "value=\"$in{'curr_autharg'}\"";
1810: }
1811: }
1812: }
1813:
1.144 matthew 1814: my $jscall = "javascript:changed_radio('loc',$in{'formname'});";
1.160 matthew 1815: my $result.=&mt('[_1] Local Authentication with argument [_2]',
1.281 albertel 1816: '<label><input type="radio" name="login" value="loc" '.$loccheck.
1.165 raeburn 1817: ' onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.281 albertel 1818: '</label><input type="text" size="10" name="locarg" '.$locarg.
1.165 raeburn 1819: ' onchange="'.$jscall.'" />');
1.32 matthew 1820: return $result;
1821: }
1822:
1823: sub authform_filesystem{
1824: my %in = (
1825: formname => 'document.cu',
1826: kerb_def_dom => 'MSU.EDU',
1827: @_,
1828: );
1.144 matthew 1829: my $jscall = "javascript:changed_radio('fsys',$in{'formname'});";
1830: my $result.= &mt
1831: ('[_1] Filesystem Authenticated (with initial password [_2])',
1.281 albertel 1832: '<label><input type="radio" name="login" value="fsys" '.
1.144 matthew 1833: 'onchange="'.$jscall.'" onclick="'.$jscall.'" />',
1.281 albertel 1834: '</label><input type="text" size="10" name="fsysarg" value="" '.
1.144 matthew 1835: 'onchange="'.$jscall.'" />');
1.32 matthew 1836: return $result;
1837: }
1838:
1.80 albertel 1839: ###############################################################
1840: ## Get Authentication Defaults for Domain ##
1841: ###############################################################
1842:
1843: =pod
1844:
1.112 bowersj2 1845: =head1 Domains and Authentication
1846:
1847: Returns default authentication type and an associated argument as
1848: listed in file 'domain.tab'.
1849:
1850: =over 4
1851:
1852: =item * get_auth_defaults
1.80 albertel 1853:
1854: get_auth_defaults($target_domain) returns the default authentication
1855: type and an associated argument (initial password or a kerberos domain).
1856: These values are stored in lonTabs/domain.tab
1857:
1858: ($def_auth, $def_arg) = &get_auth_defaults($target_domain);
1859:
1860: If target_domain is not found in domain.tab, returns nothing ('').
1861:
1862: =cut
1863:
1864: #-------------------------------------------
1865: sub get_auth_defaults {
1866: my $domain=shift;
1.514 albertel 1867: return (&Apache::lonnet::domain($domain,'auth_def'),
1868: &Apache::lonnet::domain($domain,'auth_arg_def'));
1869:
1.80 albertel 1870: }
1871: ###############################################################
1872: ## End Get Authentication Defaults for Domain ##
1873: ###############################################################
1874:
1875: ###############################################################
1876: ## Get Kerberos Defaults for Domain ##
1877: ###############################################################
1878: ##
1879: ## Returns default kerberos version and an associated argument
1880: ## as listed in file domain.tab. If not listed, provides
1881: ## appropriate default domain and kerberos version.
1882: ##
1883: #-------------------------------------------
1884:
1885: =pod
1886:
1.112 bowersj2 1887: =item * get_kerberos_defaults
1.80 albertel 1888:
1889: get_kerberos_defaults($target_domain) returns the default kerberos
1890: version and domain. If not found in domain.tabs, it defaults to
1891: version 4 and the domain of the server.
1892:
1893: ($def_version, $def_krb_domain) = &get_kerberos_defaults($target_domain);
1894:
1895: =cut
1896:
1897: #-------------------------------------------
1898: sub get_kerberos_defaults {
1899: my $domain=shift;
1900: my ($krbdef,$krbdefdom) =
1901: &Apache::loncommon::get_auth_defaults($domain);
1902: unless ($krbdef =~/^krb/ && $krbdefdom) {
1903: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
1904: my $krbdefdom=$1;
1905: $krbdefdom=~tr/a-z/A-Z/;
1906: $krbdef = "krb4";
1907: }
1908: return ($krbdef,$krbdefdom);
1909: }
1.112 bowersj2 1910:
1911: =pod
1912:
1913: =back
1914:
1915: =cut
1.32 matthew 1916:
1.46 matthew 1917: ###############################################################
1918: ## Thesaurus Functions ##
1919: ###############################################################
1.20 www 1920:
1.46 matthew 1921: =pod
1.20 www 1922:
1.112 bowersj2 1923: =head1 Thesaurus Functions
1924:
1925: =over 4
1926:
1927: =item * initialize_keywords
1.46 matthew 1928:
1929: Initializes the package variable %Keywords if it is empty. Uses the
1930: package variable $thesaurus_db_file.
1931:
1932: =cut
1933:
1934: ###################################################
1935:
1936: sub initialize_keywords {
1937: return 1 if (scalar keys(%Keywords));
1938: # If we are here, %Keywords is empty, so fill it up
1939: # Make sure the file we need exists...
1940: if (! -e $thesaurus_db_file) {
1941: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file".
1942: " failed because it does not exist");
1943: return 0;
1944: }
1945: # Set up the hash as a database
1946: my %thesaurus_db;
1947: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 1948: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 1949: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ".
1950: $thesaurus_db_file);
1951: return 0;
1952: }
1953: # Get the average number of appearances of a word.
1954: my $avecount = $thesaurus_db{'average.count'};
1955: # Put keywords (those that appear > average) into %Keywords
1956: while (my ($word,$data)=each (%thesaurus_db)) {
1957: my ($count,undef) = split /:/,$data;
1958: $Keywords{$word}++ if ($count > $avecount);
1959: }
1960: untie %thesaurus_db;
1961: # Remove special values from %Keywords.
1.356 albertel 1962: foreach my $value ('total.count','average.count') {
1963: delete($Keywords{$value}) if (exists($Keywords{$value}));
1.46 matthew 1964: }
1965: return 1;
1966: }
1967:
1968: ###################################################
1969:
1970: =pod
1971:
1.112 bowersj2 1972: =item * keyword($word)
1.46 matthew 1973:
1974: Returns true if $word is a keyword. A keyword is a word that appears more
1975: than the average number of times in the thesaurus database. Calls
1976: &initialize_keywords
1977:
1978: =cut
1979:
1980: ###################################################
1.20 www 1981:
1982: sub keyword {
1.46 matthew 1983: return if (!&initialize_keywords());
1984: my $word=lc(shift());
1985: $word=~s/\W//g;
1986: return exists($Keywords{$word});
1.20 www 1987: }
1.46 matthew 1988:
1989: ###############################################################
1990:
1991: =pod
1.20 www 1992:
1.112 bowersj2 1993: =item * get_related_words
1.46 matthew 1994:
1.160 matthew 1995: Look up a word in the thesaurus. Takes a scalar argument and returns
1.46 matthew 1996: an array of words. If the keyword is not in the thesaurus, an empty array
1997: will be returned. The order of the words returned is determined by the
1998: database which holds them.
1999:
2000: Uses global $thesaurus_db_file.
2001:
2002: =cut
2003:
2004: ###############################################################
2005: sub get_related_words {
2006: my $keyword = shift;
2007: my %thesaurus_db;
2008: if (! -e $thesaurus_db_file) {
2009: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ".
2010: "failed because the file does not exist");
2011: return ();
2012: }
2013: if (! tie(%thesaurus_db,'GDBM_File',
1.53 albertel 2014: $thesaurus_db_file,&GDBM_READER(),0640)){
1.46 matthew 2015: return ();
2016: }
2017: my @Words=();
1.429 www 2018: my $count=0;
1.46 matthew 2019: if (exists($thesaurus_db{$keyword})) {
1.356 albertel 2020: # The first element is the number of times
2021: # the word appears. We do not need it now.
1.429 www 2022: my (undef,@RelatedWords) = (split(/:/,$thesaurus_db{$keyword}));
2023: my (undef,$mostfrequentcount)=split(/\,/,$RelatedWords[0]);
2024: my $threshold=$mostfrequentcount/10;
2025: foreach my $possibleword (@RelatedWords) {
2026: my ($word,$wordcount)=split(/\,/,$possibleword);
2027: if ($wordcount>$threshold) {
2028: push(@Words,$word);
2029: $count++;
2030: if ($count>10) { last; }
2031: }
1.20 www 2032: }
2033: }
1.46 matthew 2034: untie %thesaurus_db;
2035: return @Words;
1.14 harris41 2036: }
1.46 matthew 2037:
1.112 bowersj2 2038: =pod
2039:
2040: =back
2041:
2042: =cut
1.61 www 2043:
2044: # -------------------------------------------------------------- Plaintext name
1.81 albertel 2045: =pod
2046:
1.112 bowersj2 2047: =head1 User Name Functions
2048:
2049: =over 4
2050:
1.226 albertel 2051: =item * plainname($uname,$udom,$first)
1.81 albertel 2052:
1.112 bowersj2 2053: Takes a users logon name and returns it as a string in
1.226 albertel 2054: "first middle last generation" form
2055: if $first is set to 'lastname' then it returns it as
2056: 'lastname generation, firstname middlename' if their is a lastname
1.81 albertel 2057:
2058: =cut
1.61 www 2059:
1.295 www 2060:
1.81 albertel 2061: ###############################################################
1.61 www 2062: sub plainname {
1.226 albertel 2063: my ($uname,$udom,$first)=@_;
1.537 albertel 2064: return if (!defined($uname) || !defined($udom));
1.295 www 2065: my %names=&getnames($uname,$udom);
1.226 albertel 2066: my $name=&Apache::lonnet::format_name($names{'firstname'},
2067: $names{'middlename'},
2068: $names{'lastname'},
2069: $names{'generation'},$first);
2070: $name=~s/^\s+//;
1.62 www 2071: $name=~s/\s+$//;
2072: $name=~s/\s+/ /g;
1.353 albertel 2073: if ($name !~ /\S/) { $name=$uname.':'.$udom; }
1.62 www 2074: return $name;
1.61 www 2075: }
1.66 www 2076:
2077: # -------------------------------------------------------------------- Nickname
1.81 albertel 2078: =pod
2079:
1.112 bowersj2 2080: =item * nickname($uname,$udom)
1.81 albertel 2081:
2082: Gets a users name and returns it as a string as
2083:
2084: ""nickname""
1.66 www 2085:
1.81 albertel 2086: if the user has a nickname or
2087:
2088: "first middle last generation"
2089:
2090: if the user does not
2091:
2092: =cut
1.66 www 2093:
2094: sub nickname {
2095: my ($uname,$udom)=@_;
1.537 albertel 2096: return if (!defined($uname) || !defined($udom));
1.295 www 2097: my %names=&getnames($uname,$udom);
1.68 albertel 2098: my $name=$names{'nickname'};
1.66 www 2099: if ($name) {
2100: $name='"'.$name.'"';
2101: } else {
2102: $name=$names{'firstname'}.' '.$names{'middlename'}.' '.
2103: $names{'lastname'}.' '.$names{'generation'};
2104: $name=~s/\s+$//;
2105: $name=~s/\s+/ /g;
2106: }
2107: return $name;
2108: }
2109:
1.295 www 2110: sub getnames {
2111: my ($uname,$udom)=@_;
1.537 albertel 2112: return if (!defined($uname) || !defined($udom));
1.433 albertel 2113: if ($udom eq 'public' && $uname eq 'public') {
2114: return ('lastname' => &mt('Public'));
2115: }
1.295 www 2116: my $id=$uname.':'.$udom;
2117: my ($names,$cached)=&Apache::lonnet::is_cached_new('namescache',$id);
2118: if ($cached) {
2119: return %{$names};
2120: } else {
2121: my %loadnames=&Apache::lonnet::get('environment',
2122: ['firstname','middlename','lastname','generation','nickname'],
2123: $udom,$uname);
2124: &Apache::lonnet::do_cache_new('namescache',$id,\%loadnames);
2125: return %loadnames;
2126: }
2127: }
1.61 www 2128:
1.542 raeburn 2129: # -------------------------------------------------------------------- getemails
2130: =pod
2131:
2132: =item * getemails($uname,$udom)
2133:
2134: Gets a user's email information and returns it as a hash with keys:
2135: notification, critnotification, permanentemail
2136:
2137: For notification and critnotification, values are comma-separated lists
2138: of e-mail address(es); for permanentemail, value is a single e-mail address.
2139:
2140: =cut
2141:
1.466 albertel 2142: sub getemails {
2143: my ($uname,$udom)=@_;
2144: if ($udom eq 'public' && $uname eq 'public') {
2145: return;
2146: }
1.467 www 2147: if (!$udom) { $udom=$env{'user.domain'}; }
2148: if (!$uname) { $uname=$env{'user.name'}; }
1.466 albertel 2149: my $id=$uname.':'.$udom;
2150: my ($names,$cached)=&Apache::lonnet::is_cached_new('emailscache',$id);
2151: if ($cached) {
2152: return %{$names};
2153: } else {
2154: my %loadnames=&Apache::lonnet::get('environment',
2155: ['notification','critnotification',
2156: 'permanentemail'],
2157: $udom,$uname);
2158: &Apache::lonnet::do_cache_new('emailscache',$id,\%loadnames);
2159: return %loadnames;
2160: }
2161: }
2162:
1.551 albertel 2163: sub flush_email_cache {
2164: my ($uname,$udom)=@_;
2165: if (!$udom) { $udom =$env{'user.domain'}; }
2166: if (!$uname) { $uname=$env{'user.name'}; }
2167: return if ($udom eq 'public' && $uname eq 'public');
2168: my $id=$uname.':'.$udom;
2169: &Apache::lonnet::devalidate_cache_new('emailscache',$id);
2170: }
2171:
1.61 www 2172: # ------------------------------------------------------------------ Screenname
1.81 albertel 2173:
2174: =pod
2175:
1.112 bowersj2 2176: =item * screenname($uname,$udom)
1.81 albertel 2177:
2178: Gets a users screenname and returns it as a string
2179:
2180: =cut
1.61 www 2181:
2182: sub screenname {
2183: my ($uname,$udom)=@_;
1.258 albertel 2184: if ($uname eq $env{'user.name'} &&
2185: $udom eq $env{'user.domain'}) {return $env{'environment.screenname'};}
1.212 albertel 2186: my %names=&Apache::lonnet::get('environment',['screenname'],$udom,$uname);
1.68 albertel 2187: return $names{'screenname'};
1.62 www 2188: }
2189:
1.212 albertel 2190:
1.62 www 2191: # ------------------------------------------------------------- Message Wrapper
2192:
2193: sub messagewrapper {
1.369 www 2194: my ($link,$username,$domain,$subject,$text)=@_;
1.62 www 2195: return
1.441 albertel 2196: '<a href="/adm/email?compose=individual&'.
2197: 'recname='.$username.'&recdom='.$domain.
2198: '&subject='.&escape($subject).'&text='.&escape($text).'" '.
1.200 matthew 2199: 'title="'.&mt('Send message').'">'.$link.'</a>';
1.74 www 2200: }
2201: # --------------------------------------------------------------- Notes Wrapper
2202:
2203: sub noteswrapper {
2204: my ($link,$un,$do)=@_;
2205: return
2206: "<a href='/adm/email?recordftf=retrieve&recname=$un&recdom=$do'>$link</a>";
1.62 www 2207: }
2208: # ------------------------------------------------------------- Aboutme Wrapper
2209:
2210: sub aboutmewrapper {
1.166 www 2211: my ($link,$username,$domain,$target)=@_;
1.447 raeburn 2212: if (!defined($username) && !defined($domain)) {
2213: return;
2214: }
1.205 www 2215: return '<a href="/adm/'.$domain.'/'.$username.'/aboutme"'.
1.454 banghart 2216: ($target?' target="$target"':'').' title="'.&mt("View this user's personal page").'">'.$link.'</a>';
1.62 www 2217: }
2218:
2219: # ------------------------------------------------------------ Syllabus Wrapper
2220:
2221:
2222: sub syllabuswrapper {
1.109 matthew 2223: my ($linktext,$coursedir,$domain,$fontcolor)=@_;
2224: if ($fontcolor) {
2225: $linktext='<font color="'.$fontcolor.'">'.$linktext.'</font>';
2226: }
1.208 matthew 2227: return qq{<a href="/public/$domain/$coursedir/syllabus">$linktext</a>};
1.61 www 2228: }
1.14 harris41 2229:
1.208 matthew 2230: sub track_student_link {
1.268 albertel 2231: my ($linktext,$sname,$sdom,$target,$start) = @_;
2232: my $link ="/adm/trackstudent?";
1.208 matthew 2233: my $title = 'View recent activity';
2234: if (defined($sname) && $sname !~ /^\s*$/ &&
2235: defined($sdom) && $sdom !~ /^\s*$/) {
1.268 albertel 2236: $link .= "selected_student=$sname:$sdom";
1.208 matthew 2237: $title .= ' of this student';
1.268 albertel 2238: }
1.208 matthew 2239: if (defined($target) && $target !~ /^\s*$/) {
2240: $target = qq{target="$target"};
2241: } else {
2242: $target = '';
2243: }
1.268 albertel 2244: if ($start) { $link.='&start='.$start; }
1.554 albertel 2245: $title = &mt($title);
2246: $linktext = &mt($linktext);
1.448 albertel 2247: return qq{<a href="$link" title="$title" $target>$linktext</a>}.
2248: &help_open_topic('View_recent_activity');
1.208 matthew 2249: }
2250:
1.508 www 2251: # ===================================================== Display a student photo
2252:
2253:
1.509 albertel 2254: sub student_image_tag {
1.508 www 2255: my ($domain,$user)=@_;
2256: my $imgsrc=&Apache::lonnet::studentphoto($domain,$user,'jpg');
2257: if (($imgsrc) && ($imgsrc ne '/adm/lonKaputt/lonlogo_broken.gif')) {
2258: return '<img src="'.$imgsrc.'" align="right" />';
2259: } else {
2260: return '';
2261: }
2262: }
2263:
1.112 bowersj2 2264: =pod
2265:
2266: =back
2267:
2268: =head1 Access .tab File Data
2269:
2270: =over 4
2271:
2272: =item * languageids()
2273:
2274: returns list of all language ids
2275:
2276: =cut
2277:
1.14 harris41 2278: sub languageids {
1.16 harris41 2279: return sort(keys(%language));
1.14 harris41 2280: }
2281:
1.112 bowersj2 2282: =pod
2283:
2284: =item * languagedescription()
2285:
2286: returns description of a specified language id
2287:
2288: =cut
2289:
1.14 harris41 2290: sub languagedescription {
1.125 www 2291: my $code=shift;
2292: return ($supported_language{$code}?'* ':'').
2293: $language{$code}.
1.126 www 2294: ($supported_language{$code}?' ('.&mt('interface available').')':'');
1.145 www 2295: }
2296:
2297: sub plainlanguagedescription {
2298: my $code=shift;
2299: return $language{$code};
2300: }
2301:
2302: sub supportedlanguagecode {
2303: my $code=shift;
2304: return $supported_language{$code};
1.97 www 2305: }
2306:
1.112 bowersj2 2307: =pod
2308:
2309: =item * copyrightids()
2310:
2311: returns list of all copyrights
2312:
2313: =cut
2314:
2315: sub copyrightids {
2316: return sort(keys(%cprtag));
2317: }
2318:
2319: =pod
2320:
2321: =item * copyrightdescription()
2322:
2323: returns description of a specified copyright id
2324:
2325: =cut
2326:
2327: sub copyrightdescription {
1.166 www 2328: return &mt($cprtag{shift(@_)});
1.112 bowersj2 2329: }
1.197 matthew 2330:
2331: =pod
2332:
1.192 taceyjo1 2333: =item * source_copyrightids()
2334:
2335: returns list of all source copyrights
2336:
2337: =cut
2338:
2339: sub source_copyrightids {
2340: return sort(keys(%scprtag));
2341: }
2342:
2343: =pod
2344:
2345: =item * source_copyrightdescription()
2346:
2347: returns description of a specified source copyright id
2348:
2349: =cut
2350:
2351: sub source_copyrightdescription {
2352: return &mt($scprtag{shift(@_)});
2353: }
1.112 bowersj2 2354:
2355: =pod
2356:
2357: =item * filecategories()
2358:
2359: returns list of all file categories
2360:
2361: =cut
2362:
2363: sub filecategories {
2364: return sort(keys(%category_extensions));
2365: }
2366:
2367: =pod
2368:
2369: =item * filecategorytypes()
2370:
2371: returns list of file types belonging to a given file
2372: category
2373:
2374: =cut
2375:
2376: sub filecategorytypes {
1.356 albertel 2377: my ($cat) = @_;
2378: return @{$category_extensions{lc($cat)}};
1.112 bowersj2 2379: }
2380:
2381: =pod
2382:
2383: =item * fileembstyle()
2384:
2385: returns embedding style for a specified file type
2386:
2387: =cut
2388:
2389: sub fileembstyle {
2390: return $fe{lc(shift(@_))};
1.169 www 2391: }
2392:
1.351 www 2393: sub filemimetype {
2394: return $fm{lc(shift(@_))};
2395: }
2396:
1.169 www 2397:
2398: sub filecategoryselect {
2399: my ($name,$value)=@_;
1.189 matthew 2400: return &select_form($value,$name,
1.169 www 2401: '' => &mt('Any category'),
2402: map { $_,$_ } sort(keys(%category_extensions)));
1.112 bowersj2 2403: }
2404:
2405: =pod
2406:
2407: =item * filedescription()
2408:
2409: returns description for a specified file type
2410:
2411: =cut
2412:
2413: sub filedescription {
1.188 matthew 2414: my $file_description = $fd{lc(shift())};
2415: $file_description =~ s:([\[\]]):~$1:g;
2416: return &mt($file_description);
1.112 bowersj2 2417: }
2418:
2419: =pod
2420:
2421: =item * filedescriptionex()
2422:
2423: returns description for a specified file type with
2424: extra formatting
2425:
2426: =cut
2427:
2428: sub filedescriptionex {
2429: my $ex=shift;
1.188 matthew 2430: my $file_description = $fd{lc($ex)};
2431: $file_description =~ s:([\[\]]):~$1:g;
2432: return '.'.$ex.' '.&mt($file_description);
1.112 bowersj2 2433: }
2434:
2435: # End of .tab access
2436: =pod
2437:
2438: =back
2439:
2440: =cut
2441:
2442: # ------------------------------------------------------------------ File Types
2443: sub fileextensions {
2444: return sort(keys(%fe));
2445: }
2446:
1.97 www 2447: # ----------------------------------------------------------- Display Languages
2448: # returns a hash with all desired display languages
2449: #
2450:
2451: sub display_languages {
2452: my %languages=();
1.356 albertel 2453: foreach my $lang (&preferred_languages()) {
2454: $languages{$lang}=1;
1.97 www 2455: }
2456: &get_unprocessed_cgi($ENV{'QUERY_STRING'},['displaylanguage']);
1.258 albertel 2457: if ($env{'form.displaylanguage'}) {
1.356 albertel 2458: foreach my $lang (split(/\s*(\,|\;|\:)\s*/,$env{'form.displaylanguage'})) {
2459: $languages{$lang}=1;
1.97 www 2460: }
2461: }
2462: return %languages;
1.14 harris41 2463: }
2464:
1.117 www 2465: sub preferred_languages {
2466: my @languages=();
1.258 albertel 2467: if ($env{'course.'.$env{'request.course.id'}.'.languages'}) {
1.117 www 2468: @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,
1.258 albertel 2469: $env{'course.'.$env{'request.course.id'}.'.languages'}));
1.177 www 2470: }
1.258 albertel 2471: if ($env{'environment.languages'}) {
1.459 albertel 2472: @languages=(@languages,
2473: split(/\s*(\,|\;|\:)\s*/,$env{'environment.languages'}));
1.118 www 2474: }
1.162 www 2475: my $browser=(split(/\;/,$ENV{'HTTP_ACCEPT_LANGUAGE'}))[0];
2476: if ($browser) {
2477: @languages=(@languages,split(/\s*(\,|\;|\:)\s*/,$browser));
2478: }
1.514 albertel 2479: if (&Apache::lonnet::domain($env{'user.domain'},'lang_def')) {
1.118 www 2480: @languages=(@languages,
1.514 albertel 2481: &Apache::lonnet::domain($env{'user.domain'},
2482: 'lang_def'));
1.118 www 2483: }
1.514 albertel 2484: if (&Apache::lonnet::domain($env{'request.role.domain'},'lang_def')) {
1.118 www 2485: @languages=(@languages,
1.514 albertel 2486: &Apache::lonnet::domain($env{'request.role.domain'},
2487: 'lang_def'));
1.118 www 2488: }
1.514 albertel 2489: if (&Apache::lonnet::domain($Apache::lonnet::perlvar{'lonDefDomain'},
2490: 'lang_def')) {
1.118 www 2491: @languages=(@languages,
1.514 albertel 2492: &Apache::lonnet::domain($Apache::lonnet::perlvar{'lonDefDomain'},
2493: 'lang_def'));
1.118 www 2494: }
2495: # turn "en-ca" into "en-ca,en"
2496: my @genlanguages;
1.356 albertel 2497: foreach my $lang (@languages) {
2498: unless ($lang=~/\w/) { next; }
2499: push (@genlanguages,$lang);
2500: if ($lang=~/(\-|\_)/) {
2501: push(@genlanguages,(split(/(\-|\_)/,$lang))[0]);
1.118 www 2502: }
2503: }
2504: return @genlanguages;
1.117 www 2505: }
2506:
1.112 bowersj2 2507: ###############################################################
2508: ## Student Answer Attempts ##
2509: ###############################################################
2510:
2511: =pod
2512:
2513: =head1 Alternate Problem Views
2514:
2515: =over 4
2516:
2517: =item * get_previous_attempt($symb, $username, $domain, $course,
2518: $getattempt, $regexp, $gradesub)
2519:
2520: Return string with previous attempt on problem. Arguments:
2521:
2522: =over 4
2523:
2524: =item * $symb: Problem, including path
2525:
2526: =item * $username: username of the desired student
2527:
2528: =item * $domain: domain of the desired student
1.14 harris41 2529:
1.112 bowersj2 2530: =item * $course: Course ID
1.14 harris41 2531:
1.112 bowersj2 2532: =item * $getattempt: Leave blank for all attempts, otherwise put
2533: something
1.14 harris41 2534:
1.112 bowersj2 2535: =item * $regexp: if string matches this regexp, the string will be
2536: sent to $gradesub
1.14 harris41 2537:
1.112 bowersj2 2538: =item * $gradesub: routine that processes the string if it matches $regexp
1.14 harris41 2539:
1.112 bowersj2 2540: =back
1.14 harris41 2541:
1.112 bowersj2 2542: The output string is a table containing all desired attempts, if any.
1.16 harris41 2543:
1.112 bowersj2 2544: =cut
1.1 albertel 2545:
2546: sub get_previous_attempt {
1.43 ng 2547: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_;
1.1 albertel 2548: my $prevattempts='';
1.43 ng 2549: no strict 'refs';
1.1 albertel 2550: if ($symb) {
1.3 albertel 2551: my (%returnhash)=
2552: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 2553: if ($returnhash{'version'}) {
2554: my %lasthash=();
2555: my $version;
2556: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.356 albertel 2557: foreach my $key (sort(split(/\:/,$returnhash{$version.':keys'}))) {
2558: $lasthash{$key}=$returnhash{$version.':'.$key};
1.19 harris41 2559: }
1.1 albertel 2560: }
1.43 ng 2561: $prevattempts='<table border="0" width="100%"><tr><td bgcolor="#777777">';
1.40 ng 2562: $prevattempts.='<table border="0" width="100%"><tr bgcolor="#e6ffff"><td>History</td>';
1.356 albertel 2563: foreach my $key (sort(keys(%lasthash))) {
2564: my ($ign,@parts) = split(/\./,$key);
1.41 ng 2565: if ($#parts > 0) {
1.31 albertel 2566: my $data=$parts[-1];
2567: pop(@parts);
1.40 ng 2568: $prevattempts.='<td>Part '.join('.',@parts).'<br />'.$data.' </td>';
1.31 albertel 2569: } else {
1.41 ng 2570: if ($#parts == 0) {
2571: $prevattempts.='<th>'.$parts[0].'</th>';
2572: } else {
2573: $prevattempts.='<th>'.$ign.'</th>';
2574: }
1.31 albertel 2575: }
1.16 harris41 2576: }
1.40 ng 2577: if ($getattempt eq '') {
2578: for ($version=1;$version<=$returnhash{'version'};$version++) {
2579: $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>';
1.356 albertel 2580: foreach my $key (sort(keys(%lasthash))) {
1.40 ng 2581: my $value;
1.356 albertel 2582: if ($key =~ /timestamp/) {
2583: $value=scalar(localtime($returnhash{$version.':'.$key}));
1.40 ng 2584: } else {
1.356 albertel 2585: $value=$returnhash{$version.':'.$key};
1.40 ng 2586: }
1.369 www 2587: $prevattempts.='<td>'.&unescape($value).' </td>';
1.40 ng 2588: }
2589: }
1.1 albertel 2590: }
1.40 ng 2591: $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>';
1.356 albertel 2592: foreach my $key (sort(keys(%lasthash))) {
1.5 albertel 2593: my $value;
1.356 albertel 2594: if ($key =~ /timestamp/) {
2595: $value=scalar(localtime($lasthash{$key}));
1.5 albertel 2596: } else {
1.356 albertel 2597: $value=$lasthash{$key};
1.5 albertel 2598: }
1.369 www 2599: $value=&unescape($value);
1.356 albertel 2600: if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)}
1.40 ng 2601: $prevattempts.='<td>'.$value.' </td>';
1.16 harris41 2602: }
1.40 ng 2603: $prevattempts.='</tr></table></td></tr></table>';
1.1 albertel 2604: } else {
2605: $prevattempts='Nothing submitted - no attempts.';
2606: }
2607: } else {
2608: $prevattempts='No data.';
2609: }
1.10 albertel 2610: }
2611:
1.107 albertel 2612: sub relative_to_absolute {
2613: my ($url,$output)=@_;
2614: my $parser=HTML::TokeParser->new(\$output);
2615: my $token;
2616: my $thisdir=$url;
2617: my @rlinks=();
2618: while ($token=$parser->get_token) {
2619: if ($token->[0] eq 'S') {
2620: if ($token->[1] eq 'a') {
2621: if ($token->[2]->{'href'}) {
2622: $rlinks[$#rlinks+1]=$token->[2]->{'href'};
2623: }
2624: } elsif ($token->[1] eq 'img' || $token->[1] eq 'embed' ) {
2625: $rlinks[$#rlinks+1]=$token->[2]->{'src'};
2626: } elsif ($token->[1] eq 'base') {
2627: $thisdir=$token->[2]->{'href'};
2628: }
2629: }
2630: }
2631: $thisdir=~s-/[^/]*$--;
1.356 albertel 2632: foreach my $link (@rlinks) {
2633: unless (($link=~/^http:\/\//i) ||
2634: ($link=~/^\//) ||
2635: ($link=~/^javascript:/i) ||
2636: ($link=~/^mailto:/i) ||
2637: ($link=~/^\#/)) {
2638: my $newlocation=&Apache::lonnet::hreflocation($thisdir,$link);
2639: $output=~s/(\"|\'|\=\s*)\Q$link\E(\"|\'|\s|\>)/$1$newlocation$2/;
1.107 albertel 2640: }
2641: }
2642: # -------------------------------------------------- Deal with Applet codebases
2643: $output=~s/(\<applet[^\>]+)(codebase\=[^\S\>]+)*([^\>]*)\>/$1.($2?$2:' codebase="'.$thisdir.'"').$3.'>'/gei;
2644: return $output;
2645: }
2646:
1.112 bowersj2 2647: =pod
2648:
2649: =item * get_student_view
2650:
2651: show a snapshot of what student was looking at
2652:
2653: =cut
2654:
1.10 albertel 2655: sub get_student_view {
1.186 albertel 2656: my ($symb,$username,$domain,$courseid,$target,$moreenv) = @_;
1.114 www 2657: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 2658: my (%form);
1.10 albertel 2659: my @elements=('symb','courseid','domain','username');
2660: foreach my $element (@elements) {
1.186 albertel 2661: $form{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 2662: }
1.186 albertel 2663: if (defined($moreenv)) {
2664: %form=(%form,%{$moreenv});
2665: }
1.236 albertel 2666: if (defined($target)) { $form{'grade_target'} = $target; }
1.107 albertel 2667: $feedurl=&Apache::lonnet::clutter($feedurl);
1.186 albertel 2668: my $userview=&Apache::lonnet::ssi_body($feedurl,%form);
1.11 albertel 2669: $userview=~s/\<body[^\>]*\>//gi;
2670: $userview=~s/\<\/body\>//gi;
2671: $userview=~s/\<html\>//gi;
2672: $userview=~s/\<\/html\>//gi;
2673: $userview=~s/\<head\>//gi;
2674: $userview=~s/\<\/head\>//gi;
2675: $userview=~s/action\s*\=/would_be_action\=/gi;
1.107 albertel 2676: $userview=&relative_to_absolute($feedurl,$userview);
1.11 albertel 2677: return $userview;
2678: }
2679:
1.112 bowersj2 2680: =pod
2681:
2682: =item * get_student_answers()
2683:
2684: show a snapshot of how student was answering problem
2685:
2686: =cut
2687:
1.11 albertel 2688: sub get_student_answers {
1.100 sakharuk 2689: my ($symb,$username,$domain,$courseid,%form) = @_;
1.114 www 2690: my ($map,$id,$feedurl) = &Apache::lonnet::decode_symb($symb);
1.186 albertel 2691: my (%moreenv);
1.11 albertel 2692: my @elements=('symb','courseid','domain','username');
2693: foreach my $element (@elements) {
1.186 albertel 2694: $moreenv{'grade_'.$element}=eval '$'.$element #'
1.10 albertel 2695: }
1.186 albertel 2696: $moreenv{'grade_target'}='answer';
2697: %moreenv=(%form,%moreenv);
1.497 raeburn 2698: $feedurl = &Apache::lonnet::clutter($feedurl);
2699: my $userview=&Apache::lonnet::ssi($feedurl,%moreenv);
1.10 albertel 2700: return $userview;
1.1 albertel 2701: }
1.116 albertel 2702:
2703: =pod
2704:
2705: =item * &submlink()
2706:
1.242 albertel 2707: Inputs: $text $uname $udom $symb $target
1.116 albertel 2708:
2709: Returns: A link to grades.pm such as to see the SUBM view of a student
2710:
2711: =cut
2712:
2713: ###############################################
2714: sub submlink {
1.242 albertel 2715: my ($text,$uname,$udom,$symb,$target)=@_;
1.116 albertel 2716: if (!($uname && $udom)) {
2717: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 2718: &Apache::lonnet::whichuser($symb);
1.116 albertel 2719: if (!$symb) { $symb=$cursymb; }
2720: }
1.254 matthew 2721: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 2722: $symb=&escape($symb);
1.242 albertel 2723: if ($target) { $target="target=\"$target\""; }
2724: return '<a href="/adm/grades?&command=submission&'.
2725: 'symb='.$symb.'&student='.$uname.
2726: '&userdom='.$udom.'" '.$target.'>'.$text.'</a>';
2727: }
2728: ##############################################
2729:
2730: =pod
2731:
2732: =item * &pgrdlink()
2733:
2734: Inputs: $text $uname $udom $symb $target
2735:
2736: Returns: A link to grades.pm such as to see the PGRD view of a student
2737:
2738: =cut
2739:
2740: ###############################################
2741: sub pgrdlink {
2742: my $link=&submlink(@_);
2743: $link=~s/(&command=submission)/$1&showgrading=yes/;
2744: return $link;
2745: }
2746: ##############################################
2747:
2748: =pod
2749:
2750: =item * &pprmlink()
2751:
2752: Inputs: $text $uname $udom $symb $target
2753:
2754: Returns: A link to parmset.pm such as to see the PPRM view of a
1.283 albertel 2755: student and a specific resource
1.242 albertel 2756:
2757: =cut
2758:
2759: ###############################################
2760: sub pprmlink {
2761: my ($text,$uname,$udom,$symb,$target)=@_;
2762: if (!($uname && $udom)) {
2763: (my $cursymb, my $courseid,$udom,$uname)=
1.463 albertel 2764: &Apache::lonnet::whichuser($symb);
1.242 albertel 2765: if (!$symb) { $symb=$cursymb; }
2766: }
1.254 matthew 2767: if (!$symb) { $symb=&Apache::lonnet::symbread(); }
1.369 www 2768: $symb=&escape($symb);
1.242 albertel 2769: if ($target) { $target="target=\"$target\""; }
2770: return '<a href="/adm/parmset?&command=set&'.
2771: 'symb='.$symb.'&uname='.$uname.
2772: '&udom='.$udom.'" '.$target.'>'.$text.'</a>';
1.116 albertel 2773: }
2774: ##############################################
1.37 matthew 2775:
1.112 bowersj2 2776: =pod
2777:
2778: =back
2779:
2780: =cut
2781:
1.37 matthew 2782: ###############################################
1.51 www 2783:
2784:
2785: sub timehash {
2786: my @ltime=localtime(shift);
2787: return ( 'seconds' => $ltime[0],
2788: 'minutes' => $ltime[1],
2789: 'hours' => $ltime[2],
2790: 'day' => $ltime[3],
2791: 'month' => $ltime[4]+1,
2792: 'year' => $ltime[5]+1900,
2793: 'weekday' => $ltime[6],
2794: 'dayyear' => $ltime[7]+1,
2795: 'dlsav' => $ltime[8] );
2796: }
2797:
1.370 www 2798: sub utc_string {
2799: my ($date)=@_;
1.371 www 2800: return strftime("%Y%m%dT%H%M%SZ",gmtime($date));
1.370 www 2801: }
2802:
1.51 www 2803: sub maketime {
2804: my %th=@_;
2805: return POSIX::mktime(
2806: ($th{'seconds'},$th{'minutes'},$th{'hours'},
1.210 www 2807: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
1.70 www 2808: }
2809:
2810: #########################################
1.51 www 2811:
2812: sub findallcourses {
1.482 raeburn 2813: my ($roles,$uname,$udom) = @_;
1.355 albertel 2814: my %roles;
2815: if (ref($roles)) { %roles = map { $_ => 1 } @{$roles}; }
1.348 albertel 2816: my %courses;
1.51 www 2817: my $now=time;
1.482 raeburn 2818: if (!defined($uname)) {
2819: $uname = $env{'user.name'};
2820: }
2821: if (!defined($udom)) {
2822: $udom = $env{'user.domain'};
2823: }
2824: if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
2825: my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname);
2826: if (!%roles) {
2827: %roles = (
2828: cc => 1,
2829: in => 1,
2830: ep => 1,
2831: ta => 1,
2832: cr => 1,
2833: st => 1,
2834: );
2835: }
2836: foreach my $entry (keys(%roleshash)) {
2837: my ($trole,$tend,$tstart) = split(/_/,$roleshash{$entry});
2838: if ($trole =~ /^cr/) {
2839: next if (!exists($roles{$trole}) && !exists($roles{'cr'}));
2840: } else {
2841: next if (!exists($roles{$trole}));
2842: }
2843: if ($tend) {
2844: next if ($tend < $now);
2845: }
2846: if ($tstart) {
2847: next if ($tstart > $now);
2848: }
2849: my ($cdom,$cnum,$sec,$cnumpart,$secpart,$role,$realsec);
2850: (undef,$cdom,$cnumpart,$secpart) = split(/\//,$entry);
2851: if ($secpart eq '') {
2852: ($cnum,$role) = split(/_/,$cnumpart);
2853: $sec = 'none';
2854: $realsec = '';
2855: } else {
2856: $cnum = $cnumpart;
2857: ($sec,$role) = split(/_/,$secpart);
2858: $realsec = $sec;
1.490 raeburn 2859: }
1.482 raeburn 2860: $courses{$cdom.'_'.$cnum}{$sec} = $trole.'/'.$cdom.'/'.$cnum.'/'.$realsec;
2861: }
2862: } else {
2863: foreach my $key (keys(%env)) {
1.483 albertel 2864: if ( $key=~m{^user\.role\.(\w+)\./($match_domain)/($match_courseid)/?(\w*)$} ||
2865: $key=~m{^user\.role\.(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_courseid)/?(\w*)$}) {
1.482 raeburn 2866: my ($role,$cdom,$cnum,$sec) = ($1,$2,$3,$4);
2867: next if ($role eq 'ca' || $role eq 'aa');
2868: next if (%roles && !exists($roles{$role}));
2869: my ($starttime,$endtime)=split(/\./,$env{$key});
2870: my $active=1;
2871: if ($starttime) {
2872: if ($now<$starttime) { $active=0; }
2873: }
2874: if ($endtime) {
2875: if ($now>$endtime) { $active=0; }
2876: }
2877: if ($active) {
2878: if ($sec eq '') {
2879: $sec = 'none';
2880: }
2881: $courses{$cdom.'_'.$cnum}{$sec} =
2882: $role.'/'.$cdom.'/'.$cnum.'/'.$sec;
1.474 raeburn 2883: }
2884: }
1.51 www 2885: }
2886: }
1.474 raeburn 2887: return %courses;
1.51 www 2888: }
1.37 matthew 2889:
1.54 www 2890: ###############################################
1.474 raeburn 2891:
2892: sub blockcheck {
1.482 raeburn 2893: my ($setters,$activity,$uname,$udom) = @_;
1.490 raeburn 2894:
2895: if (!defined($udom)) {
2896: $udom = $env{'user.domain'};
2897: }
2898: if (!defined($uname)) {
2899: $uname = $env{'user.name'};
2900: }
2901:
2902: # If uname and udom are for a course, check for blocks in the course.
2903:
2904: if (&Apache::lonnet::is_course($udom,$uname)) {
2905: my %records = &Apache::lonnet::dump('comm_block',$udom,$uname);
1.502 raeburn 2906: my ($startblock,$endblock)=&get_blocks($setters,$activity,$udom,$uname);
1.490 raeburn 2907: return ($startblock,$endblock);
2908: }
1.474 raeburn 2909:
1.502 raeburn 2910: my $startblock = 0;
2911: my $endblock = 0;
1.482 raeburn 2912: my %live_courses = &findallcourses(undef,$uname,$udom);
1.474 raeburn 2913:
1.490 raeburn 2914: # If uname is for a user, and activity is course-specific, i.e.,
2915: # boards, chat or groups, check for blocking in current course only.
1.474 raeburn 2916:
1.490 raeburn 2917: if (($activity eq 'boards' || $activity eq 'chat' ||
2918: $activity eq 'groups') && ($env{'request.course.id'})) {
2919: foreach my $key (keys(%live_courses)) {
2920: if ($key ne $env{'request.course.id'}) {
2921: delete($live_courses{$key});
2922: }
2923: }
2924: }
2925:
2926: my $otheruser = 0;
2927: my %own_courses;
2928: if ((($uname ne $env{'user.name'})) || ($udom ne $env{'user.domain'})) {
2929: # Resource belongs to user other than current user.
2930: $otheruser = 1;
2931: # Gather courses for current user
2932: %own_courses =
2933: &findallcourses(undef,$env{'user.name'},$env{'user.domain'});
2934: }
2935:
2936: # Gather active course roles - course coordinator, instructor,
2937: # exam proctor, ta, student, or custom role.
1.474 raeburn 2938:
2939: foreach my $course (keys(%live_courses)) {
1.482 raeburn 2940: my ($cdom,$cnum);
2941: if ((defined($env{'course.'.$course.'.domain'})) && (defined($env{'course.'.$course.'.num'}))) {
2942: $cdom = $env{'course.'.$course.'.domain'};
2943: $cnum = $env{'course.'.$course.'.num'};
2944: } else {
1.490 raeburn 2945: ($cdom,$cnum) = split(/_/,$course);
1.482 raeburn 2946: }
2947: my $no_ownblock = 0;
2948: my $no_userblock = 0;
1.533 raeburn 2949: if ($otheruser && $activity ne 'com') {
1.490 raeburn 2950: # Check if current user has 'evb' priv for this
2951: if (defined($own_courses{$course})) {
2952: foreach my $sec (keys(%{$own_courses{$course}})) {
2953: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
2954: if ($sec ne 'none') {
2955: $checkrole .= '/'.$sec;
2956: }
2957: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
2958: $no_ownblock = 1;
2959: last;
2960: }
2961: }
2962: }
2963: # if they have 'evb' priv and are currently not playing student
2964: next if (($no_ownblock) &&
2965: ($env{'request.role'} !~ m{^st\./$cdom/$cnum}));
2966: }
1.474 raeburn 2967: foreach my $sec (keys(%{$live_courses{$course}})) {
1.482 raeburn 2968: my $checkrole = 'cm./'.$cdom.'/'.$cnum;
1.474 raeburn 2969: if ($sec ne 'none') {
1.482 raeburn 2970: $checkrole .= '/'.$sec;
1.474 raeburn 2971: }
1.490 raeburn 2972: if ($otheruser) {
2973: # Resource belongs to user other than current user.
2974: # Assemble privs for that user, and check for 'evb' priv.
1.482 raeburn 2975: my ($trole,$tdom,$tnum,$tsec);
2976: my $entry = $live_courses{$course}{$sec};
2977: if ($entry =~ /^cr/) {
2978: ($trole,$tdom,$tnum,$tsec) =
2979: ($entry =~ m|^(cr/$match_domain/$match_username/\w+)\./($match_domain)/($match_username)/?(\w*)$|);
2980: } else {
2981: ($trole,$tdom,$tnum,$tsec) = split(/\//,$entry);
2982: }
2983: my ($spec,$area,$trest,%allroles,%userroles);
2984: $area = '/'.$tdom.'/'.$tnum;
2985: $trest = $tnum;
2986: if ($tsec ne '') {
2987: $area .= '/'.$tsec;
2988: $trest .= '/'.$tsec;
2989: }
2990: $spec = $trole.'.'.$area;
2991: if ($trole =~ /^cr/) {
2992: &Apache::lonnet::custom_roleprivs(\%allroles,$trole,
2993: $tdom,$spec,$trest,$area);
2994: } else {
2995: &Apache::lonnet::standard_roleprivs(\%allroles,$trole,
2996: $tdom,$spec,$trest,$area);
2997: }
2998: my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles);
1.486 raeburn 2999: if ($userroles{'user.priv.'.$checkrole} =~ /evb\&([^\:]*)/) {
3000: if ($1) {
3001: $no_userblock = 1;
3002: last;
3003: }
3004: }
1.490 raeburn 3005: } else {
3006: # Resource belongs to current user
3007: # Check for 'evb' priv via lonnet::allowed().
1.482 raeburn 3008: if (&Apache::lonnet::allowed('evb',undef,undef,$checkrole)) {
3009: $no_ownblock = 1;
3010: last;
3011: }
1.474 raeburn 3012: }
3013: }
3014: # if they have the evb priv and are currently not playing student
1.482 raeburn 3015: next if (($no_ownblock) &&
1.491 albertel 3016: ($env{'request.role'} !~ m{^st\./\Q$cdom\E/\Q$cnum\E}));
1.482 raeburn 3017: next if ($no_userblock);
1.474 raeburn 3018:
1.490 raeburn 3019: # Retrieve blocking times and identity of blocker for course
3020: # of specified user, unless user has 'evb' privilege.
1.502 raeburn 3021:
3022: my ($start,$end)=&get_blocks($setters,$activity,$cdom,$cnum);
3023: if (($start != 0) &&
3024: (($startblock == 0) || ($startblock > $start))) {
3025: $startblock = $start;
3026: }
3027: if (($end != 0) &&
3028: (($endblock == 0) || ($endblock < $end))) {
3029: $endblock = $end;
3030: }
1.490 raeburn 3031: }
3032: return ($startblock,$endblock);
3033: }
3034:
3035: sub get_blocks {
3036: my ($setters,$activity,$cdom,$cnum) = @_;
3037: my $startblock = 0;
3038: my $endblock = 0;
3039: my $course = $cdom.'_'.$cnum;
3040: $setters->{$course} = {};
3041: $setters->{$course}{'staff'} = [];
3042: $setters->{$course}{'times'} = [];
3043: my %records = &Apache::lonnet::dump('comm_block',$cdom,$cnum);
3044: foreach my $record (keys(%records)) {
3045: my ($start,$end) = ($record =~ m/^(\d+)____(\d+)$/);
3046: if ($start <= time && $end >= time) {
3047: my ($staff_name,$staff_dom,$title,$blocks) =
3048: &parse_block_record($records{$record});
3049: if ($blocks->{$activity} eq 'on') {
3050: push(@{$$setters{$course}{'staff'}},[$staff_name,$staff_dom]);
3051: push(@{$$setters{$course}{'times'}}, [$start,$end]);
1.491 albertel 3052: if ( ($startblock == 0) || ($startblock > $start) ) {
3053: $startblock = $start;
1.490 raeburn 3054: }
1.491 albertel 3055: if ( ($endblock == 0) || ($endblock < $end) ) {
3056: $endblock = $end;
1.474 raeburn 3057: }
3058: }
3059: }
3060: }
3061: return ($startblock,$endblock);
3062: }
3063:
3064: sub parse_block_record {
3065: my ($record) = @_;
3066: my ($setuname,$setudom,$title,$blocks);
3067: if (ref($record) eq 'HASH') {
3068: ($setuname,$setudom) = split(/:/,$record->{'setter'});
3069: $title = &unescape($record->{'event'});
3070: $blocks = $record->{'blocks'};
3071: } else {
3072: my @data = split(/:/,$record,3);
3073: if (scalar(@data) eq 2) {
3074: $title = $data[1];
3075: ($setuname,$setudom) = split(/@/,$data[0]);
3076: } else {
3077: ($setuname,$setudom,$title) = @data;
3078: }
3079: $blocks = { 'com' => 'on' };
3080: }
3081: return ($setuname,$setudom,$title,$blocks);
3082: }
3083:
3084: sub build_block_table {
3085: my ($startblock,$endblock,$setters) = @_;
3086: my %lt = &Apache::lonlocal::texthash(
3087: 'cacb' => 'Currently active communication blocks',
3088: 'cour' => 'Course',
3089: 'dura' => 'Duration',
3090: 'blse' => 'Block set by'
3091: );
3092: my $output;
1.476 raeburn 3093: $output = '<br />'.$lt{'cacb'}.':<br />';
1.474 raeburn 3094: $output .= &start_data_table();
3095: $output .= '
3096: <tr>
3097: <th>'.$lt{'cour'}.'</th>
3098: <th>'.$lt{'dura'}.'</th>
3099: <th>'.$lt{'blse'}.'</th>
3100: </tr>
3101: ';
3102: foreach my $course (keys(%{$setters})) {
3103: my %courseinfo=&Apache::lonnet::coursedescription($course);
3104: for (my $i=0; $i<@{$$setters{$course}{staff}}; $i++) {
3105: my ($uname,$udom) = @{$$setters{$course}{staff}[$i]};
1.490 raeburn 3106: my $fullname = &plainname($uname,$udom);
3107: if (defined($env{'user.name'}) && defined($env{'user.domain'})
3108: && $env{'user.name'} ne 'public'
3109: && $env{'user.domain'} ne 'public') {
3110: $fullname = &aboutmewrapper($fullname,$uname,$udom);
3111: }
1.474 raeburn 3112: my ($openblock,$closeblock) = @{$$setters{$course}{times}[$i]};
3113: $openblock = &Apache::lonlocal::locallocaltime($openblock);
3114: $closeblock= &Apache::lonlocal::locallocaltime($closeblock);
3115: $output .= &Apache::loncommon::start_data_table_row().
3116: '<td>'.$courseinfo{'description'}.'</td>'.
3117: '<td>'.$openblock.' to '.$closeblock.'</td>'.
1.490 raeburn 3118: '<td>'.$fullname.'</td>'.
1.474 raeburn 3119: &Apache::loncommon::end_data_table_row();
3120: }
3121: }
3122: $output .= &end_data_table();
3123: }
3124:
1.490 raeburn 3125: sub blocking_status {
3126: my ($activity,$uname,$udom) = @_;
3127: my %setters;
3128: my ($blocked,$output,$ownitem,$is_course);
3129: my ($startblock,$endblock)=&blockcheck(\%setters,$activity,$uname,$udom);
3130: if ($startblock && $endblock) {
3131: $blocked = 1;
3132: if (wantarray) {
3133: my $category;
3134: if ($activity eq 'boards') {
3135: $category = 'Discussion posts in this course';
3136: } elsif ($activity eq 'blogs') {
3137: $category = 'Blogs';
3138: } elsif ($activity eq 'port') {
3139: if (defined($uname) && defined($udom)) {
3140: if ($uname eq $env{'user.name'} &&
3141: $udom eq $env{'user.domain'}) {
3142: $ownitem = 1;
3143: }
3144: }
3145: $is_course = &Apache::lonnet::is_course($udom,$uname);
3146: if ($ownitem) {
3147: $category = 'Your portfolio files';
3148: } elsif ($is_course) {
3149: my $coursedesc;
3150: foreach my $course (keys(%setters)) {
3151: my %courseinfo =
3152: &Apache::lonnet::coursedescription($course);
3153: $coursedesc = $courseinfo{'description'};
3154: }
3155: $category = "Group files in the course '$coursedesc'";
3156: } else {
3157: $category = 'Portfolio files belonging to ';
3158: if ($env{'user.name'} eq 'public' &&
3159: $env{'user.domain'} eq 'public') {
3160: $category .= &plainname($uname,$udom);
3161: } else {
3162: $category .= &aboutmewrapper(&plainname($uname,$udom),$uname,$udom);
3163: }
3164: }
3165: } elsif ($activity eq 'groups') {
3166: $category = 'Groups in this course';
3167: }
3168: my $showstart = &Apache::lonlocal::locallocaltime($startblock);
3169: my $showend = &Apache::lonlocal::locallocaltime($endblock);
3170: $output = '<br />'.&mt('[_1] will be inaccessible between [_2] and [_3] because communication is being blocked.',$category,$showstart,$showend).'<br />';
3171: if (!($activity eq 'port' && !($ownitem) && !($is_course))) {
3172: $output .= &build_block_table($startblock,$endblock,\%setters);
3173: }
3174: }
3175: }
3176: if (wantarray) {
3177: return ($blocked,$output);
3178: } else {
3179: return $blocked;
3180: }
3181: }
3182:
1.60 matthew 3183: ###############################################
3184:
3185: =pod
3186:
1.112 bowersj2 3187: =head1 Domain Template Functions
3188:
3189: =over 4
3190:
3191: =item * &determinedomain()
1.60 matthew 3192:
3193: Inputs: $domain (usually will be undef)
3194:
1.63 www 3195: Returns: Determines which domain should be used for designs
1.60 matthew 3196:
3197: =cut
1.54 www 3198:
1.60 matthew 3199: ###############################################
1.63 www 3200: sub determinedomain {
3201: my $domain=shift;
1.531 albertel 3202: if (! $domain) {
1.60 matthew 3203: # Determine domain if we have not been given one
3204: $domain = $Apache::lonnet::perlvar{'lonDefDomain'};
1.258 albertel 3205: if ($env{'user.domain'}) { $domain=$env{'user.domain'}; }
3206: if ($env{'request.role.domain'}) {
3207: $domain=$env{'request.role.domain'};
1.60 matthew 3208: }
3209: }
1.63 www 3210: return $domain;
3211: }
3212: ###############################################
1.517 raeburn 3213:
1.518 albertel 3214: sub devalidate_domconfig_cache {
3215: my ($udom)=@_;
3216: &Apache::lonnet::devalidate_cache_new('domainconfig',$udom);
3217: }
3218:
3219: # ---------------------- Get domain configuration for a domain
3220: sub get_domainconf {
3221: my ($udom) = @_;
3222: my $cachetime=1800;
3223: my ($result,$cached)=&Apache::lonnet::is_cached_new('domainconfig',$udom);
3224: if (defined($cached)) { return %{$result}; }
3225:
3226: my %domconfig = &Apache::lonnet::get_dom('configuration',
3227: ['login','rolecolors'],$udom);
3228: my %designhash;
3229: if (keys(%domconfig) > 0) {
3230: if (ref($domconfig{'login'}) eq 'HASH') {
3231: foreach my $key (keys(%{$domconfig{'login'}})) {
3232: $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key};
3233: }
3234: }
3235: if (ref($domconfig{'rolecolors'}) eq 'HASH') {
3236: foreach my $role (keys(%{$domconfig{'rolecolors'}})) {
3237: if (ref($domconfig{'rolecolors'}{$role}) eq 'HASH') {
3238: foreach my $item (keys(%{$domconfig{'rolecolors'}{$role}})) {
3239: $designhash{$udom.'.'.$role.'.'.$item}=$domconfig{'rolecolors'}{$role}{$item};
3240: }
3241: }
3242: }
3243: }
3244: } else {
3245: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors';
3246: my $designfile = $designdir.'/'.$udom.'.tab';
3247: if (-e $designfile) {
3248: if ( open (my $fh,"<$designfile") ) {
3249: while (my $line = <$fh>) {
3250: next if ($line =~ /^\#/);
3251: chomp($line);
3252: my ($key,$val)=(split(/\=/,$line));
3253: if ($val) { $designhash{$udom.'.'.$key}=$val; }
3254: }
3255: close($fh);
3256: }
3257: }
3258: if (-e '/home/httpd/html/adm/lonDomLogos/'.$udom.'.gif') {
1.519 raeburn 3259: $designhash{$udom.'.login.domlogo'} = "/adm/lonDomLogos/$udom.gif";
1.518 albertel 3260: }
3261: }
3262: &Apache::lonnet::do_cache_new('domainconfig',$udom,\%designhash,
3263: $cachetime);
3264: return %designhash;
3265: }
3266:
1.63 www 3267: =pod
3268:
1.112 bowersj2 3269: =item * &domainlogo()
1.63 www 3270:
3271: Inputs: $domain (usually will be undef)
3272:
3273: Returns: A link to a domain logo, if the domain logo exists.
3274: If the domain logo does not exist, a description of the domain.
3275:
3276: =cut
1.112 bowersj2 3277:
1.63 www 3278: ###############################################
3279: sub domainlogo {
1.517 raeburn 3280: my $domain = &determinedomain(shift);
1.518 albertel 3281: my %designhash = &get_domainconf($domain);
1.517 raeburn 3282: # See if there is a logo
3283: if ($designhash{$domain.'.login.domlogo'} ne '') {
1.519 raeburn 3284: my $imgsrc = $designhash{$domain.'.login.domlogo'};
1.538 albertel 3285: if ($imgsrc =~ m{^/(adm|res)/}) {
3286: if ($imgsrc =~ m{^/res/}) {
3287: my $local_name = &Apache::lonnet::filelocation('',$imgsrc);
3288: &Apache::lonnet::repcopy($local_name);
3289: }
3290: $imgsrc = &lonhttpdurl($imgsrc);
1.519 raeburn 3291: }
3292: return '<img src="'.$imgsrc.'" alt="'.$domain.'" />';
1.514 albertel 3293: } elsif (defined(&Apache::lonnet::domain($domain,'description'))) {
3294: return &Apache::lonnet::domain($domain,'description');
1.59 www 3295: } else {
1.60 matthew 3296: return '';
1.59 www 3297: }
3298: }
1.63 www 3299: ##############################################
3300:
3301: =pod
3302:
1.112 bowersj2 3303: =item * &designparm()
1.63 www 3304:
3305: Inputs: $which parameter; $domain (usually will be undef)
3306:
3307: Returns: value of designparamter $which
3308:
3309: =cut
1.112 bowersj2 3310:
1.397 albertel 3311:
1.400 albertel 3312: ##############################################
1.397 albertel 3313: sub designparm {
3314: my ($which,$domain)=@_;
1.258 albertel 3315: if ($env{'browser.blackwhite'} eq 'on') {
1.110 www 3316: if ($which=~/\.(font|alink|vlink|link)$/) {
3317: return '#000000';
3318: }
3319: if ($which=~/\.(pgbg|sidebg)$/) {
3320: return '#FFFFFF';
3321: }
3322: if ($which=~/\.tabbg$/) {
3323: return '#CCCCCC';
3324: }
3325: }
1.397 albertel 3326: if (exists($env{'environment.color.'.$which})) {
1.258 albertel 3327: return $env{'environment.color.'.$which};
1.96 www 3328: }
1.63 www 3329: $domain=&determinedomain($domain);
1.518 albertel 3330: my %domdesign = &get_domainconf($domain);
1.520 raeburn 3331: my $output;
1.517 raeburn 3332: if ($domdesign{$domain.'.'.$which} ne '') {
1.520 raeburn 3333: $output = $domdesign{$domain.'.'.$which};
1.63 www 3334: } else {
1.520 raeburn 3335: $output = $defaultdesign{$which};
3336: }
3337: if (($which =~ /^(student|coordinator|author|admin)\.img$/) ||
3338: ($which =~ /login\.(img|logo|domlogo)/)) {
1.538 albertel 3339: if ($output =~ m{^/(adm|res)/}) {
3340: if ($output =~ m{^/res/}) {
3341: my $local_name = &Apache::lonnet::filelocation('',$output);
3342: &Apache::lonnet::repcopy($local_name);
3343: }
1.520 raeburn 3344: $output = &lonhttpdurl($output);
3345: }
1.63 www 3346: }
1.520 raeburn 3347: return $output;
1.63 www 3348: }
1.59 www 3349:
1.60 matthew 3350: ###############################################
3351: ###############################################
3352:
3353: =pod
3354:
1.112 bowersj2 3355: =back
3356:
1.549 albertel 3357: =head1 HTML Helpers
1.112 bowersj2 3358:
3359: =over 4
3360:
3361: =item * &bodytag()
1.60 matthew 3362:
3363: Returns a uniform header for LON-CAPA web pages.
3364:
3365: Inputs:
3366:
1.112 bowersj2 3367: =over 4
3368:
3369: =item * $title, A title to be displayed on the page.
3370:
3371: =item * $function, the current role (can be undef).
3372:
3373: =item * $addentries, extra parameters for the <body> tag.
3374:
3375: =item * $bodyonly, if defined, only return the <body> tag.
3376:
3377: =item * $domain, if defined, force a given domain.
3378:
3379: =item * $forcereg, if page should register as content page (relevant for
1.86 www 3380: text interface only)
1.60 matthew 3381:
1.326 albertel 3382: =item * $customtitle, alternate text to use instead of $title
3383: in the title box that appears, this text
3384: is not auto translated like the $title is
1.309 albertel 3385:
3386: =item * $notopbar, if true, keep the 'what is this' info but remove the
3387: navigational links
1.317 albertel 3388:
1.338 albertel 3389: =item * $bgcolor, used to override the bgcolor on a webpage to a specific value
3390:
3391: =item * $notitle, if true keep the nav controls, but remove the title bar
3392:
1.361 albertel 3393: =item * $no_inline_link, if true and in remote mode, don't show the
3394: 'Switch To Inline Menu' link
3395:
1.460 albertel 3396: =item * $args, optional argument valid values are
3397: no_auto_mt_title -> prevents &mt()ing the title arg
3398:
1.112 bowersj2 3399: =back
3400:
1.60 matthew 3401: Returns: A uniform header for LON-CAPA web pages.
3402: If $bodyonly is nonzero, a string containing a <body> tag will be returned.
3403: If $bodyonly is undef or zero, an html string containing a <body> tag and
3404: other decorations will be returned.
3405:
3406: =cut
3407:
1.54 www 3408: sub bodytag {
1.309 albertel 3409: my ($title,$function,$addentries,$bodyonly,$domain,$forcereg,$customtitle,
1.460 albertel 3410: $notopbar,$bgcolor,$notitle,$no_inline_link,$args)=@_;
1.339 albertel 3411:
1.460 albertel 3412: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
1.339 albertel 3413:
1.183 matthew 3414: $function = &get_users_function() if (!$function);
1.339 albertel 3415: my $img = &designparm($function.'.img',$domain);
3416: my $font = &designparm($function.'.font',$domain);
3417: my $pgbg = $bgcolor || &designparm($function.'.pgbg',$domain);
3418:
3419: my %design = ( 'style' => 'margin-top: 0px',
1.535 albertel 3420: 'bgcolor' => $pgbg,
1.339 albertel 3421: 'text' => $font,
3422: 'alink' => &designparm($function.'.alink',$domain),
3423: 'vlink' => &designparm($function.'.vlink',$domain),
3424: 'link' => &designparm($function.'.link',$domain),);
1.438 albertel 3425: @design{keys(%$addentries)} = @$addentries{keys(%$addentries)};
1.339 albertel 3426:
1.63 www 3427: # role and realm
1.378 raeburn 3428: my ($role,$realm) = split(/\./,$env{'request.role'},2);
3429: if ($role eq 'ca') {
1.479 albertel 3430: my ($rdom,$rname) = ($realm =~ m{^/($match_domain)/($match_username)$});
1.500 albertel 3431: $realm = &plainname($rname,$rdom);
1.378 raeburn 3432: }
1.55 www 3433: # realm
1.258 albertel 3434: if ($env{'request.course.id'}) {
1.378 raeburn 3435: if ($env{'request.role'} !~ /^cr/) {
3436: $role = &Apache::lonnet::plaintext($role,&course_type());
3437: }
1.359 albertel 3438: $realm = $env{'course.'.$env{'request.course.id'}.'.description'};
1.378 raeburn 3439: } else {
3440: $role = &Apache::lonnet::plaintext($role);
1.54 www 3441: }
1.433 albertel 3442:
1.359 albertel 3443: if (!$realm) { $realm=' '; }
1.55 www 3444: # Set messages
1.60 matthew 3445: my $messages=&domainlogo($domain);
1.101 www 3446: # Port for miniserver
1.83 albertel 3447: my $lonhttpdPort=$Apache::lonnet::perlvar{'lonhttpdPort'};
3448: if (!defined($lonhttpdPort)) { $lonhttpdPort='8080'; }
1.330 albertel 3449:
1.438 albertel 3450: my $extra_body_attr = &make_attr_string($forcereg,\%design);
1.329 albertel 3451:
1.101 www 3452: # construct main body tag
1.359 albertel 3453: my $bodytag = "<body $extra_body_attr>".
3454: &Apache::lontexconvert::init_math_support();
1.252 albertel 3455:
1.530 albertel 3456: if ($bodyonly) {
1.60 matthew 3457: return $bodytag;
1.258 albertel 3458: } elsif ($env{'browser.interface'} eq 'textual') {
1.95 www 3459: # Accessibility
1.224 raeburn 3460:
1.337 albertel 3461: $bodytag.=&Apache::lonmenu::menubuttons($forcereg,$forcereg);
1.338 albertel 3462: if (!$notitle) {
1.337 albertel 3463: $bodytag.='<h1>LON-CAPA: '.$title.'</h1>';
3464: }
3465: return $bodytag;
1.359 albertel 3466: }
3467:
1.410 albertel 3468: my $name = &plainname($env{'user.name'},$env{'user.domain'});
1.433 albertel 3469: if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') {
3470: undef($role);
1.434 albertel 3471: } else {
3472: $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'});
1.433 albertel 3473: }
1.359 albertel 3474:
3475: my $roleinfo=(<<ENDROLE);
3476: <td class="LC_title_bar_who">
3477: <div class="LC_title_bar_name">
1.410 albertel 3478: $name
1.361 albertel 3479:
1.359 albertel 3480: </div>
3481: <div class="LC_title_bar_role">
1.361 albertel 3482: $role
1.359 albertel 3483: </div>
3484: <div class="LC_title_bar_realm">
1.361 albertel 3485: $realm
1.359 albertel 3486: </div>
1.206 albertel 3487: </td>
3488: ENDROLE
1.235 raeburn 3489:
1.359 albertel 3490: my $titleinfo = '<span class="LC_title_bar_title">'.$title.'</span>';
3491: if ($customtitle) {
3492: $titleinfo = $customtitle;
3493: }
3494: #
3495: # Extra info if you are the DC
3496: my $dc_info = '';
3497: if ($env{'user.adv'} && exists($env{'user.role.dc./'.
3498: $env{'course.'.$env{'request.course.id'}.
3499: '.domain'}.'/'})) {
3500: my $cid = $env{'request.course.id'};
3501: $dc_info.= $cid.' '.$env{'course.'.$cid.'.internal.coursecode'};
1.380 www 3502: $dc_info =~ s/\s+$//;
1.359 albertel 3503: $dc_info = '('.$dc_info.')';
3504: }
3505:
3506: if ($env{'environment.remote'} eq 'off') {
3507: # No Remote
1.258 albertel 3508: if ($env{'request.state'} eq 'construct') {
1.359 albertel 3509: $forcereg=1;
3510: }
3511:
3512: if (!$customtitle && $env{'request.state'} eq 'construct') {
3513: # this is for resources; directories have customtitle, and crumbs
3514: # and select recent are created in lonpubdir.pm
1.229 albertel 3515: my ($uname,$thisdisfn)=
1.258 albertel 3516: ($env{'request.filename'} =~ m|^/home/([^/]+)/public_html/(.*)|);
1.229 albertel 3517: my $formaction='/priv/'.$uname.'/'.$thisdisfn;
3518: $formaction=~s/\/+/\//g;
3519:
1.359 albertel 3520: my $parentpath = '';
3521: my $lastitem = '';
3522: if ($thisdisfn =~ m-(.+/)([^/]*)$-) {
3523: $parentpath = $1;
3524: $lastitem = $2;
3525: } else {
3526: $lastitem = $thisdisfn;
3527: }
3528: $titleinfo =
1.401 albertel 3529: &Apache::loncommon::help_open_menu('','',3,'Authoring').
1.359 albertel 3530: '<b>Construction Space</b>: '.
3531: '<form name="dirs" method="post" action="'.$formaction
3532: .'" target="_top"><tt><b>'
3533: .&Apache::lonhtmlcommon::crumbs($uname.'/'.$parentpath,'_top','/priv','','+1',1)."<font size=\"+1\">$lastitem</font></b></tt><br />"
3534: .&Apache::lonhtmlcommon::select_recent('construct','recent','this.form.action=this.form.recent.value;this.form.submit()')
3535: .'</form>'
3536: .&Apache::lonmenu::constspaceform();
1.235 raeburn 3537: }
1.359 albertel 3538:
1.337 albertel 3539: my $titletable;
1.338 albertel 3540: if (!$notitle) {
1.337 albertel 3541: $titletable =
1.359 albertel 3542: '<table id="LC_title_bar">'.
3543: "<tr><td> $titleinfo $dc_info</td>".$roleinfo.
3544: '</tr></table>';
1.337 albertel 3545: }
1.359 albertel 3546: if ($notopbar) {
3547: $bodytag .= $titletable;
3548: } else {
3549: if ($env{'request.state'} eq 'construct') {
1.337 albertel 3550: $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg,
3551: $titletable);
1.272 raeburn 3552: } else {
1.336 albertel 3553: $bodytag .= &Apache::lonmenu::menubuttons($forcereg,$forcereg).
1.359 albertel 3554: $titletable;
1.272 raeburn 3555: }
1.235 raeburn 3556: }
3557: return $bodytag;
1.94 www 3558: }
1.95 www 3559:
1.93 www 3560: #
1.95 www 3561: # Top frame rendering, Remote is up
1.93 www 3562: #
1.359 albertel 3563:
1.517 raeburn 3564: my $imgsrc = $img;
3565: if ($img =~ /^\/adm/) {
3566: $imgsrc = 'http://'.$ENV{'HTTP_HOST'}.':'.$lonhttpdPort.$img;
3567: }
3568: my $upperleft='<img src="'.$imgsrc.'" alt="'.$function.'" />';
1.359 albertel 3569:
1.305 www 3570: # Explicit link to get inline menu
1.361 albertel 3571: my $menu= ($no_inline_link?''
3572: :'<br /><a href="/adm/remote?action=collapse">'.&mt('Switch to Inline Menu Mode').'</a>');
1.245 matthew 3573: #
1.338 albertel 3574: if ($notitle) {
1.337 albertel 3575: return $bodytag;
3576: }
1.94 www 3577: return(<<ENDBODY);
1.60 matthew 3578: $bodytag
1.359 albertel 3579: <table id="LC_title_bar" class="LC_with_remote">
1.368 albertel 3580: <tr><td class="LC_title_bar_role_logo">$upperleft</td>
1.359 albertel 3581: <td class="LC_title_bar_domain_logo">$messages </td>
1.54 www 3582: </tr>
1.359 albertel 3583: <tr><td>$titleinfo $dc_info $menu</td>
3584: $roleinfo
1.368 albertel 3585: </tr>
1.356 albertel 3586: </table>
1.54 www 3587: ENDBODY
1.182 matthew 3588: }
3589:
1.330 albertel 3590: sub make_attr_string {
3591: my ($register,$attr_ref) = @_;
3592:
3593: if ($attr_ref && !ref($attr_ref)) {
3594: die("addentries Must be a hash ref ".
3595: join(':',caller(1))." ".
3596: join(':',caller(0))." ");
3597: }
3598:
3599: if ($register) {
1.339 albertel 3600: my ($on_load,$on_unload);
3601: foreach my $key (keys(%{$attr_ref})) {
3602: if (lc($key) eq 'onload') {
3603: $on_load.=$attr_ref->{$key}.';';
3604: delete($attr_ref->{$key});
3605:
3606: } elsif (lc($key) eq 'onunload') {
3607: $on_unload.=$attr_ref->{$key}.';';
3608: delete($attr_ref->{$key});
3609: }
3610: }
3611: $attr_ref->{'onload'} =
3612: &Apache::lonmenu::loadevents(). $on_load;
3613: $attr_ref->{'onunload'}=
3614: &Apache::lonmenu::unloadevents().$on_unload;
3615: }
3616:
3617: # Accessibility font enhance
3618: if ($env{'browser.fontenhance'} eq 'on') {
3619: my $style;
3620: foreach my $key (keys(%{$attr_ref})) {
3621: if (lc($key) eq 'style') {
3622: $style.=$attr_ref->{$key}.';';
3623: delete($attr_ref->{$key});
3624: }
3625: }
3626: $attr_ref->{'style'}=$style.'; font-size: x-large;';
1.330 albertel 3627: }
1.339 albertel 3628:
3629: if ($env{'browser.blackwhite'} eq 'on') {
3630: delete($attr_ref->{'font'});
3631: delete($attr_ref->{'link'});
3632: delete($attr_ref->{'alink'});
3633: delete($attr_ref->{'vlink'});
3634: delete($attr_ref->{'bgcolor'});
3635: delete($attr_ref->{'background'});
3636: }
3637:
1.330 albertel 3638: my $attr_string;
3639: foreach my $attr (keys(%$attr_ref)) {
3640: $attr_string .= " $attr=\"".$attr_ref->{$attr}.'" ';
3641: }
3642: return $attr_string;
3643: }
3644:
3645:
1.182 matthew 3646: ###############################################
1.251 albertel 3647: ###############################################
3648:
3649: =pod
3650:
3651: =item * &endbodytag()
3652:
3653: Returns a uniform footer for LON-CAPA web pages.
3654:
1.306 albertel 3655: Inputs: none
1.251 albertel 3656:
3657: =cut
3658:
3659: sub endbodytag {
3660: my $endbodytag='</body>';
1.269 albertel 3661: $endbodytag=&Apache::lontexconvert::jsMath_process()."\n".$endbodytag;
1.315 albertel 3662: if ( exists( $env{'internal.head.redirect'} ) ) {
3663: $endbodytag=
3664: "<br /><a href=\"$env{'internal.head.redirect'}\">".
3665: &mt('Continue').'</a>'.
3666: $endbodytag;
3667: }
1.251 albertel 3668: return $endbodytag;
3669: }
3670:
1.352 albertel 3671: =pod
3672:
3673: =item * &standard_css()
3674:
3675: Returns a style sheet
3676:
3677: Inputs: (all optional)
3678: domain -> force to color decorate a page for a specific
3679: domain
3680: function -> force usage of a specific rolish color scheme
3681: bgcolor -> override the default page bgcolor
3682:
3683: =cut
3684:
1.343 albertel 3685: sub standard_css {
1.345 albertel 3686: my ($function,$domain,$bgcolor) = @_;
1.352 albertel 3687: $function = &get_users_function() if (!$function);
3688: my $img = &designparm($function.'.img', $domain);
3689: my $tabbg = &designparm($function.'.tabbg', $domain);
3690: my $font = &designparm($function.'.font', $domain);
1.345 albertel 3691: my $sidebg = &designparm($function.'.sidebg',$domain);
1.382 albertel 3692: my $pgbg_or_bgcolor =
3693: $bgcolor ||
1.352 albertel 3694: &designparm($function.'.pgbg', $domain);
1.382 albertel 3695: my $pgbg = &designparm($function.'.pgbg', $domain);
1.352 albertel 3696: my $alink = &designparm($function.'.alink', $domain);
3697: my $vlink = &designparm($function.'.vlink', $domain);
3698: my $link = &designparm($function.'.link', $domain);
3699:
3700: my $sans = 'Arial,Helvetica,sans-serif';
1.395 albertel 3701: my $mono = 'monospace';
1.352 albertel 3702: my $data_table_head = $tabbg;
3703: my $data_table_light = '#EEEEEE';
1.470 banghart 3704: my $data_table_dark = '#DDDDDD';
3705: my $data_table_darker = '#CCCCCC';
1.349 albertel 3706: my $data_table_highlight = '#FFFF00';
1.352 albertel 3707: my $mail_new = '#FFBB77';
3708: my $mail_new_hover = '#DD9955';
3709: my $mail_read = '#BBBB77';
3710: my $mail_read_hover = '#999944';
3711: my $mail_replied = '#AAAA88';
3712: my $mail_replied_hover = '#888855';
3713: my $mail_other = '#99BBBB';
3714: my $mail_other_hover = '#669999';
1.391 albertel 3715: my $table_header = '#DDDDDD';
1.489 raeburn 3716: my $feedback_link_bg = '#BBBBBB';
1.392 albertel 3717:
3718: my $border = ($env{'browser.type'} eq 'explorer') ? '0px 2px 0px 2px'
3719: : '0px 3px 0px 4px';
1.448 albertel 3720:
1.523 albertel 3721:
1.343 albertel 3722: return <<END;
1.345 albertel 3723: h1, h2, h3, th { font-family: $sans }
1.343 albertel 3724: a:focus { color: red; background: yellow }
1.510 albertel 3725: table.thinborder,
1.523 albertel 3726:
1.510 albertel 3727: table.thinborder tr th {
3728: border-style: solid;
3729: border-width: 1px;
3730: background: $tabbg;
3731: }
1.523 albertel 3732: table.thinborder tr td {
1.510 albertel 3733: border-style: solid;
3734: border-width: 1px
3735: }
1.426 albertel 3736:
1.343 albertel 3737: form, .inline { display: inline; }
3738: .center { text-align: center; }
1.395 albertel 3739: .LC_filename {font-family: $mono;}
1.350 albertel 3740: .LC_error {
3741: color: red;
3742: font-size: larger;
3743: }
1.457 albertel 3744: .LC_warning,
3745: .LC_diff_removed {
1.394 albertel 3746: color: red;
3747: }
1.532 albertel 3748:
3749: .LC_info,
1.457 albertel 3750: .LC_success,
3751: .LC_diff_added {
1.350 albertel 3752: color: green;
3753: }
1.543 albertel 3754: .LC_unknown {
3755: color: yellow;
3756: }
3757:
1.440 albertel 3758: .LC_icon {
3759: border: 0px;
3760: }
1.539 albertel 3761: .LC_indexer_icon {
3762: border: 0px;
3763: height: 22px;
3764: }
1.543 albertel 3765: .LC_docs_spacer {
3766: width: 25px;
3767: height: 1px;
3768: border: 0px;
3769: }
1.346 albertel 3770:
1.532 albertel 3771: .LC_internal_info {
3772: color: #999;
3773: }
3774:
1.458 albertel 3775: table.LC_pastsubmission {
3776: border: 1px solid black;
3777: margin: 2px;
3778: }
3779:
1.392 albertel 3780: table#LC_top_nav, table#LC_menubuttons {
1.345 albertel 3781: width: 100%;
3782: background: $pgbg;
1.392 albertel 3783: border: 2px;
1.402 albertel 3784: border-collapse: separate;
1.403 albertel 3785: padding: 0px;
1.345 albertel 3786: }
1.392 albertel 3787:
1.409 albertel 3788: table#LC_title_bar, table.LC_breadcrumbs, table#LC_nav_location,
1.393 albertel 3789: table#LC_title_bar.LC_with_remote {
1.359 albertel 3790: width: 100%;
1.392 albertel 3791: border-color: $pgbg;
3792: border-style: solid;
3793: border-width: $border;
3794:
1.379 albertel 3795: background: $pgbg;
3796: font-family: $sans;
1.392 albertel 3797: border-collapse: collapse;
1.403 albertel 3798: padding: 0px;
1.359 albertel 3799: }
1.392 albertel 3800:
1.409 albertel 3801: table.LC_docs_path {
3802: width: 100%;
3803: border: 0;
3804: background: $pgbg;
3805: font-family: $sans;
3806: border-collapse: collapse;
3807: padding: 0px;
3808: }
3809:
1.359 albertel 3810: table#LC_title_bar td {
3811: background: $tabbg;
3812: }
3813: table#LC_title_bar td.LC_title_bar_who {
3814: background: $tabbg;
3815: color: $font;
1.427 albertel 3816: font: small $sans;
1.359 albertel 3817: text-align: right;
3818: }
1.469 banghart 3819: span.LC_metadata {
3820: font-family: $sans;
3821: }
1.359 albertel 3822: span.LC_title_bar_title {
1.416 albertel 3823: font: bold x-large $sans;
1.359 albertel 3824: }
3825: table#LC_title_bar td.LC_title_bar_domain_logo {
3826: background: $sidebg;
3827: text-align: right;
1.368 albertel 3828: padding: 0px;
3829: }
3830: table#LC_title_bar td.LC_title_bar_role_logo {
3831: background: $sidebg;
3832: padding: 0px;
1.359 albertel 3833: }
3834:
1.346 albertel 3835: table#LC_menubuttons_mainmenu {
1.526 www 3836: width: 100%;
1.346 albertel 3837: border: 0px;
3838: border-spacing: 1px;
1.372 albertel 3839: padding: 0px 1px;
1.346 albertel 3840: margin: 0px;
3841: border-collapse: separate;
3842: }
3843: table#LC_menubuttons img, table#LC_menubuttons_mainmenu img {
3844: border: 0px;
3845: }
1.345 albertel 3846: table#LC_top_nav td {
3847: background: $tabbg;
1.392 albertel 3848: border: 0px;
1.407 albertel 3849: font-size: small;
1.345 albertel 3850: }
3851: table#LC_top_nav td a, div#LC_top_nav a {
3852: color: $font;
3853: font-family: $sans;
3854: }
1.364 albertel 3855: table#LC_top_nav td.LC_top_nav_logo {
3856: background: $tabbg;
1.432 albertel 3857: text-align: left;
1.408 albertel 3858: white-space: nowrap;
1.432 albertel 3859: width: 31px;
1.408 albertel 3860: }
3861: table#LC_top_nav td.LC_top_nav_logo img {
1.432 albertel 3862: border: 0px;
1.408 albertel 3863: vertical-align: bottom;
1.364 albertel 3864: }
1.432 albertel 3865: table#LC_top_nav td.LC_top_nav_exit,
3866: table#LC_top_nav td.LC_top_nav_help {
3867: width: 2.0em;
3868: }
1.442 albertel 3869: table#LC_top_nav td.LC_top_nav_login {
3870: width: 4.0em;
3871: text-align: center;
3872: }
1.409 albertel 3873: table.LC_breadcrumbs td, table.LC_docs_path td {
1.357 albertel 3874: background: $tabbg;
3875: color: $font;
3876: font-family: $sans;
1.358 albertel 3877: font-size: smaller;
1.357 albertel 3878: }
1.411 albertel 3879: table.LC_breadcrumbs td.LC_breadcrumbs_component,
1.409 albertel 3880: table.LC_docs_path td.LC_docs_path_component {
1.357 albertel 3881: background: $tabbg;
3882: color: $font;
3883: font-family: $sans;
3884: font-size: larger;
3885: text-align: right;
3886: }
1.383 albertel 3887: td.LC_table_cell_checkbox {
3888: text-align: center;
3889: }
3890:
1.522 albertel 3891: table#LC_mainmenu td.LC_mainmenu_column {
3892: vertical-align: top;
3893: }
3894:
1.346 albertel 3895: .LC_menubuttons_inline_text {
3896: color: $font;
3897: font-family: $sans;
3898: font-size: smaller;
3899: }
3900:
1.526 www 3901: .LC_menubuttons_link {
3902: text-decoration: none;
3903: }
3904:
1.522 albertel 3905: .LC_menubuttons_category {
1.521 www 3906: color: $font;
1.526 www 3907: background: $pgbg;
1.521 www 3908: font-family: $sans;
3909: font-size: larger;
3910: font-weight: bold;
3911: }
3912:
1.346 albertel 3913: td.LC_menubuttons_text {
1.526 www 3914: width: 90%;
1.346 albertel 3915: color: $font;
3916: font-family: $sans;
3917: }
1.526 www 3918:
1.346 albertel 3919: td.LC_menubuttons_img {
3920: }
1.526 www 3921:
1.346 albertel 3922: .LC_current_location {
3923: font-family: $sans;
3924: background: $tabbg;
3925: }
3926: .LC_new_mail {
3927: font-family: $sans;
3928: font-weight: bold;
3929: }
1.347 albertel 3930:
1.526 www 3931: .LC_rolesmenu_is {
3932: font-family: $sans;
3933: }
3934:
3935: .LC_rolesmenu_selected {
3936: font-family: $sans;
3937: }
3938:
3939: .LC_rolesmenu_future {
3940: font-family: $sans;
3941: }
3942:
3943:
3944: .LC_rolesmenu_will {
3945: font-family: $sans;
3946: }
3947:
3948: .LC_rolesmenu_will_not {
3949: font-family: $sans;
3950: }
3951:
3952: .LC_rolesmenu_expired {
3953: font-family: $sans;
3954: }
3955:
3956: .LC_rolesinfo {
3957: font-family: $sans;
3958: }
3959:
1.527 www 3960: .LC_dropadd_labeltext {
3961: font-family: $sans;
3962: text-align: right;
3963: }
3964:
3965: .LC_preferences_labeltext {
3966: font-family: $sans;
3967: text-align: right;
3968: }
3969:
1.440 albertel 3970: table.LC_aboutme_port {
3971: border: 0px;
3972: border-collapse: collapse;
3973: border-spacing: 0px;
3974: }
1.349 albertel 3975: table.LC_data_table, table.LC_mail_list {
1.347 albertel 3976: border: 1px solid #000000;
1.402 albertel 3977: border-collapse: separate;
1.426 albertel 3978: border-spacing: 1px;
1.347 albertel 3979: }
1.422 albertel 3980: .LC_data_table_dense {
3981: font-size: small;
3982: }
1.507 raeburn 3983: table.LC_nested_outer {
3984: border: 1px solid #000000;
3985: border-collapse: separate;
3986: border-spacing: 0px;
3987: width: 100%;
3988: }
3989: table.LC_nested {
3990: border: 0px;
3991: border-collapse: separate;
3992: border-spacing: 0px;
3993: width: 100%;
3994: }
1.523 albertel 3995: table.LC_data_table tr th, table.LC_calendar tr th, table.LC_mail_list tr th,
3996: table.LC_prior_tries tr th {
1.349 albertel 3997: font-weight: bold;
3998: background-color: $data_table_head;
1.421 albertel 3999: font-size: smaller;
1.347 albertel 4000: }
1.440 albertel 4001: table.LC_data_table tr td,
4002: table.LC_aboutme_port tr td {
1.349 albertel 4003: background-color: $data_table_light;
1.425 albertel 4004: padding: 2px;
1.347 albertel 4005: }
1.440 albertel 4006: table.LC_data_table tr.LC_even_row td,
4007: table.LC_aboutme_port tr.LC_even_row td {
1.349 albertel 4008: background-color: $data_table_dark;
1.347 albertel 4009: }
1.425 albertel 4010: table.LC_data_table tr.LC_data_table_highlight td {
4011: background-color: $data_table_darker;
4012: }
1.451 albertel 4013: table.LC_data_table tr.LC_empty_row td,
1.507 raeburn 4014: table.LC_nested tr.LC_empty_row td {
1.347 albertel 4015: background-color: #FFFFFF;
1.421 albertel 4016: font-weight: bold;
4017: font-style: italic;
4018: text-align: center;
4019: padding: 8px;
1.347 albertel 4020: }
1.507 raeburn 4021: table.LC_nested tr.LC_empty_row td {
1.465 albertel 4022: padding: 4ex
4023: }
1.507 raeburn 4024: table.LC_nested_outer tr th {
4025: font-weight: bold;
4026: background-color: $data_table_head;
4027: font-size: smaller;
4028: border-bottom: 1px solid #000000;
4029: }
4030: table.LC_nested_outer tr td.LC_subheader {
4031: background-color: $data_table_head;
4032: font-weight: bold;
4033: font-size: small;
4034: border-bottom: 1px solid #000000;
4035: text-align: right;
1.451 albertel 4036: }
1.507 raeburn 4037: table.LC_nested tr.LC_info_row td {
1.451 albertel 4038: background-color: #CCC;
4039: font-weight: bold;
4040: font-size: small;
1.507 raeburn 4041: text-align: center;
4042: }
4043: table.LC_nested tr.LC_info_row td.LC_left_item {
4044: text-align: left;
1.451 albertel 4045: }
1.507 raeburn 4046: table.LC_nested td {
1.451 albertel 4047: background-color: #FFF;
4048: font-size: small;
1.507 raeburn 4049: }
4050: table.LC_nested_outer tr th.LC_right_item,
4051: table.LC_nested tr.LC_info_row td.LC_right_item,
4052: table.LC_nested tr.LC_odd_row td.LC_right_item,
4053: table.LC_nested tr td.LC_right_item {
1.451 albertel 4054: text-align: right;
4055: }
4056:
1.507 raeburn 4057: table.LC_nested tr.LC_odd_row td {
1.451 albertel 4058: background-color: #EEE;
4059: }
4060:
1.473 raeburn 4061: table.LC_createuser {
4062: }
4063:
4064: table.LC_createuser tr.LC_section_row td {
4065: font-size: smaller;
4066: }
4067:
4068: table.LC_createuser tr.LC_info_row td {
4069: background-color: #CCC;
4070: font-weight: bold;
4071: text-align: center;
4072: }
4073:
1.349 albertel 4074: table.LC_calendar {
4075: border: 1px solid #000000;
4076: border-collapse: collapse;
4077: }
4078: table.LC_calendar_pickdate {
4079: font-size: xx-small;
4080: }
4081: table.LC_calendar tr td {
4082: border: 1px solid #000000;
4083: vertical-align: top;
4084: }
4085: table.LC_calendar tr td.LC_calendar_day_empty {
4086: background-color: $data_table_dark;
4087: }
4088: table.LC_calendar tr td.LC_calendar_day_current {
4089: background-color: $data_table_highlight;
4090: }
4091:
4092: table.LC_mail_list tr.LC_mail_new {
4093: background-color: $mail_new;
4094: }
4095: table.LC_mail_list tr.LC_mail_new:hover {
4096: background-color: $mail_new_hover;
4097: }
4098: table.LC_mail_list tr.LC_mail_read {
4099: background-color: $mail_read;
4100: }
4101: table.LC_mail_list tr.LC_mail_read:hover {
4102: background-color: $mail_read_hover;
4103: }
4104: table.LC_mail_list tr.LC_mail_replied {
4105: background-color: $mail_replied;
4106: }
4107: table.LC_mail_list tr.LC_mail_replied:hover {
4108: background-color: $mail_replied_hover;
4109: }
4110: table.LC_mail_list tr.LC_mail_other {
4111: background-color: $mail_other;
4112: }
4113: table.LC_mail_list tr.LC_mail_other:hover {
4114: background-color: $mail_other_hover;
4115: }
1.494 raeburn 4116: table.LC_mail_list tr.LC_mail_even {
4117: }
4118: table.LC_mail_list tr.LC_mail_odd {
4119: }
4120:
1.385 albertel 4121:
1.386 albertel 4122: table#LC_portfolio_actions {
4123: width: auto;
4124: background: $pgbg;
4125: border: 0px;
4126: border-spacing: 2px 2px;
4127: padding: 0px;
4128: margin: 0px;
4129: border-collapse: separate;
4130: }
4131: table#LC_portfolio_actions td.LC_label {
4132: background: $tabbg;
4133: text-align: right;
4134: }
4135: table#LC_portfolio_actions td.LC_value {
4136: background: $tabbg;
4137: }
1.385 albertel 4138:
1.391 albertel 4139: table#LC_cstr_controls {
4140: width: 100%;
4141: border-collapse: collapse;
4142: }
4143: table#LC_cstr_controls tr td {
4144: border: 4px solid $pgbg;
4145: padding: 4px;
4146: text-align: center;
4147: background: $tabbg;
4148: }
4149: table#LC_cstr_controls tr th {
4150: border: 4px solid $pgbg;
4151: background: $table_header;
4152: text-align: center;
4153: font-family: $sans;
4154: font-size: smaller;
4155: }
4156:
1.389 albertel 4157: table#LC_browser {
4158:
4159: }
4160: table#LC_browser tr th {
1.391 albertel 4161: background: $table_header;
1.389 albertel 4162: }
1.390 albertel 4163: table#LC_browser tr td {
4164: padding: 2px;
4165: }
1.389 albertel 4166: table#LC_browser tr.LC_browser_file,
4167: table#LC_browser tr.LC_browser_file_published {
4168: background: #CCFF88;
4169: }
4170: table#LC_browser tr.LC_browser_file_locked,
4171: table#LC_browser tr.LC_browser_file_unpublished {
4172: background: #FFAA99;
1.387 albertel 4173: }
1.389 albertel 4174: table#LC_browser tr.LC_browser_file_obsolete {
4175: background: #AAAAAA;
1.387 albertel 4176: }
1.455 albertel 4177: table#LC_browser tr.LC_browser_file_modified,
4178: table#LC_browser tr.LC_browser_file_metamodified {
1.389 albertel 4179: background: #FFFF77;
1.387 albertel 4180: }
1.389 albertel 4181: table#LC_browser tr.LC_browser_folder {
4182: background: #CCCCFF;
1.387 albertel 4183: }
1.388 albertel 4184: span.LC_current_location {
4185: font-size: x-large;
4186: background: $pgbg;
4187: }
1.387 albertel 4188:
1.395 albertel 4189: span.LC_parm_menu_item {
4190: font-size: larger;
4191: font-family: $sans;
4192: }
4193: span.LC_parm_scope_all {
4194: color: red;
4195: }
4196: span.LC_parm_scope_folder {
4197: color: green;
4198: }
4199: span.LC_parm_scope_resource {
4200: color: orange;
4201: }
4202: span.LC_parm_part {
4203: color: blue;
4204: }
4205: span.LC_parm_folder, span.LC_parm_symb {
4206: font-size: x-small;
4207: font-family: $mono;
4208: color: #AAAAAA;
4209: }
4210:
1.396 albertel 4211: td.LC_parm_overview_level_menu, td.LC_parm_overview_map_menu,
4212: td.LC_parm_overview_parm_selectors, td.LC_parm_overview_parm_restrictions {
4213: border: 1px solid black;
4214: border-collapse: collapse;
4215: }
4216: table.LC_parm_overview_restrictions td {
4217: border-width: 1px 4px 1px 4px;
4218: border-style: solid;
4219: border-color: $pgbg;
4220: text-align: center;
4221: }
4222: table.LC_parm_overview_restrictions th {
4223: background: $tabbg;
4224: border-width: 1px 4px 1px 4px;
4225: border-style: solid;
4226: border-color: $pgbg;
4227: }
1.398 albertel 4228: table#LC_helpmenu {
4229: border: 0px;
4230: height: 55px;
4231: border-spacing: 0px;
4232: }
4233:
4234: table#LC_helpmenu fieldset legend {
4235: font-size: larger;
4236: font-weight: bold;
4237: }
1.397 albertel 4238: table#LC_helpmenu_links {
4239: width: 100%;
4240: border: 1px solid black;
4241: background: $pgbg;
4242: padding: 0px;
4243: border-spacing: 1px;
4244: }
4245: table#LC_helpmenu_links tr td {
4246: padding: 1px;
4247: background: $tabbg;
1.399 albertel 4248: text-align: center;
4249: font-weight: bold;
1.397 albertel 4250: }
1.396 albertel 4251:
1.397 albertel 4252: table#LC_helpmenu_links a:link, table#LC_helpmenu_links a:visited,
4253: table#LC_helpmenu_links a:active {
4254: text-decoration: none;
4255: color: $font;
4256: }
4257: table#LC_helpmenu_links a:hover {
4258: text-decoration: underline;
4259: color: $vlink;
4260: }
1.396 albertel 4261:
1.417 albertel 4262: .LC_chrt_popup_exists {
4263: border: 1px solid #339933;
4264: margin: -1px;
4265: }
4266: .LC_chrt_popup_up {
4267: border: 1px solid yellow;
4268: margin: -1px;
4269: }
4270: .LC_chrt_popup {
4271: border: 1px solid #8888FF;
4272: background: #CCCCFF;
4273: }
4274:
1.421 albertel 4275: table.LC_pick_box {
4276: width: 100%;
4277: border-collapse: separate;
4278: background: white;
4279: border: 1px solid black;
4280: border-spacing: 1px;
4281: }
4282: table.LC_pick_box td.LC_pick_box_title {
4283: background: $tabbg;
4284: font-weight: bold;
4285: text-align: right;
4286: width: 184px;
4287: padding: 8px;
4288: }
1.424 albertel 4289: table.LC_pick_box td.LC_pick_box_separator {
1.421 albertel 4290: padding: 0px;
4291: height: 1px;
4292: background: black;
4293: }
4294: table.LC_pick_box td.LC_pick_box_submit {
4295: text-align: right;
4296: }
4297:
1.424 albertel 4298: table.LC_group_priv_box {
4299: background: white;
4300: border: 1px solid black;
4301: border-spacing: 1px;
4302: }
4303: table.LC_group_priv_box td.LC_pick_box_title {
4304: background: $tabbg;
4305: font-weight: bold;
4306: text-align: right;
4307: width: 184px;
4308: }
4309: table.LC_group_priv_box td.LC_groups_fixed {
4310: background: $data_table_light;
4311: text-align: center;
4312: }
4313: table.LC_group_priv_box td.LC_groups_optional {
4314: background: $data_table_dark;
4315: text-align: center;
4316: }
4317: table.LC_group_priv_box td.LC_groups_functionality {
4318: background: $data_table_darker;
4319: text-align: center;
4320: font-weight: bold;
4321: }
4322: table.LC_group_priv td {
4323: text-align: left;
4324: padding: 0px;
4325: }
4326:
1.421 albertel 4327: table.LC_notify_front_page {
4328: background: white;
4329: border: 1px solid black;
4330: padding: 8px;
4331: }
4332: table.LC_notify_front_page td {
4333: padding: 8px;
4334: }
1.424 albertel 4335: .LC_navbuttons {
4336: margin: 2ex 0ex 2ex 0ex;
4337: }
1.423 albertel 4338: .LC_topic_bar {
4339: font-family: $sans;
4340: font-weight: bold;
4341: width: 100%;
4342: background: $tabbg;
4343: vertical-align: middle;
4344: margin: 2ex 0ex 2ex 0ex;
4345: }
4346: .LC_topic_bar span {
4347: vertical-align: middle;
4348: }
4349: .LC_topic_bar img {
4350: vertical-align: bottom;
4351: }
4352: table.LC_course_group_status {
4353: margin: 20px;
4354: }
4355: table.LC_status_selector td {
4356: vertical-align: top;
4357: text-align: center;
1.424 albertel 4358: padding: 4px;
4359: }
4360: table.LC_descriptive_input td.LC_description {
4361: vertical-align: top;
4362: text-align: right;
4363: font-weight: bold;
1.423 albertel 4364: }
1.489 raeburn 4365: table.LC_feedback_link {
4366: background: $feedback_link_bg;
4367: }
4368: span.LC_feedback_link {
4369: background: $feedback_link_bg;
4370: font-size: larger;
4371: }
1.421 albertel 4372:
1.515 albertel 4373: table.LC_prior_tries {
1.524 albertel 4374: border: 1px solid #000000;
4375: border-collapse: separate;
4376: border-spacing: 1px;
1.515 albertel 4377: }
1.523 albertel 4378:
1.515 albertel 4379: table.LC_prior_tries td {
1.524 albertel 4380: padding: 2px;
1.515 albertel 4381: }
1.523 albertel 4382:
4383: .LC_answer_correct {
4384: background: #AAFFAA;
4385: color: black;
4386: }
4387: .LC_answer_charged_try {
4388: background: #FFAAAA ! important;
4389: color: black;
4390: }
4391: .LC_answer_not_charged_try,
4392: .LC_answer_no_grade,
4393: .LC_answer_late {
4394: background: #FFFFAA;
4395: color: black;
4396: }
4397: .LC_answer_previous {
4398: background: #AAAAFF;
4399: color: black;
4400: }
4401: .LC_answer_no_message {
4402: background: #FFFFFF;
4403: color: black;
4404: }
4405: .LC_answer_unknown {
4406: background: orange;
4407: color: black;
4408: }
4409:
4410:
1.529 albertel 4411: span.LC_prior_numerical,
4412: span.LC_prior_string,
4413: span.LC_prior_custom,
4414: span.LC_prior_reaction,
4415: span.LC_prior_math {
1.523 albertel 4416: font-family: monospace;
4417: white-space: pre;
4418: }
4419:
1.525 albertel 4420: span.LC_prior_string {
4421: font-family: monospace;
4422: white-space: pre;
4423: }
4424:
1.523 albertel 4425: table.LC_prior_option {
4426: width: 100%;
4427: border-collapse: collapse;
4428: }
1.528 albertel 4429: table.LC_prior_rank, table.LC_prior_match {
4430: border-collapse: collapse;
4431: }
4432: table.LC_prior_option tr td,
4433: table.LC_prior_rank tr td,
4434: table.LC_prior_match tr td {
1.524 albertel 4435: border: 1px solid #000000;
1.515 albertel 4436: }
4437:
1.519 raeburn 4438: span.LC_nobreak {
1.544 albertel 4439: white-space: nowrap;
1.519 raeburn 4440: }
4441:
1.545 albertel 4442: table.LC_docs_documents {
4443: background: #BBBBBB;
1.547 albertel 4444: border-width: 0px;
1.545 albertel 4445: border-collapse: collapse;
4446: }
4447:
4448: table.LC_docs_documents td.LC_docs_document {
4449: border: 2px solid black;
4450: padding: 4px;
4451: }
4452:
4453: .LC_docs_course_commands div {
4454: float: left;
4455: border: 4px solid #AAAAAA;
4456: padding: 4px;
4457: background: #DDDDCC;
4458: }
4459:
4460: .LC_docs_entry_move {
4461: border: 0px;
4462: border-collapse: collapse;
1.544 albertel 4463: }
4464:
1.545 albertel 4465: .LC_docs_entry_move td {
4466: border: 2px solid #BBBBBB;
4467: background: #DDDDDD;
4468: }
4469:
4470: .LC_docs_editor td.LC_docs_entry_commands {
4471: background: #DDDDDD;
4472: font-size: x-small;
4473: }
1.544 albertel 4474: .LC_docs_copy {
1.545 albertel 4475: color: #000099;
1.544 albertel 4476: }
4477: .LC_docs_cut {
1.545 albertel 4478: color: #550044;
1.544 albertel 4479: }
4480: .LC_docs_rename {
1.545 albertel 4481: color: #009900;
1.544 albertel 4482: }
4483: .LC_docs_remove {
1.545 albertel 4484: color: #990000;
4485: }
4486:
1.547 albertel 4487: .LC_docs_reinit_warn,
4488: .LC_docs_ext_edit {
4489: font-size: x-small;
4490: }
4491:
1.545 albertel 4492: .LC_docs_editor td.LC_docs_entry_title,
4493: .LC_docs_editor td.LC_docs_entry_icon {
4494: background: #FFFFBB;
4495: }
4496: .LC_docs_editor td.LC_docs_entry_parameter {
4497: background: #BBBBFF;
4498: font-size: x-small;
4499: white-space: nowrap;
4500: }
4501:
4502: table.LC_docs_adddocs td,
4503: table.LC_docs_adddocs th {
4504: border: 1px solid #BBBBBB;
4505: padding: 4px;
4506: background: #DDDDDD;
1.543 albertel 4507: }
4508:
1.343 albertel 4509: END
4510: }
4511:
1.306 albertel 4512: =pod
4513:
4514: =item * &headtag()
4515:
4516: Returns a uniform footer for LON-CAPA web pages.
4517:
1.307 albertel 4518: Inputs: $title - optional title for the head
4519: $head_extra - optional extra HTML to put inside the <head>
1.315 albertel 4520: $args - optional arguments
1.319 albertel 4521: force_register - if is true call registerurl so the remote is
4522: informed
1.415 albertel 4523: redirect -> array ref of
4524: 1- seconds before redirect occurs
4525: 2- url to redirect to
4526: 3- whether the side effect should occur
1.315 albertel 4527: (side effect of setting
4528: $env{'internal.head.redirect'} to the url
4529: redirected too)
1.352 albertel 4530: domain -> force to color decorate a page for a specific
4531: domain
4532: function -> force usage of a specific rolish color scheme
4533: bgcolor -> override the default page bgcolor
1.460 albertel 4534: no_auto_mt_title
4535: -> prevent &mt()ing the title arg
1.464 albertel 4536:
1.306 albertel 4537: =cut
4538:
4539: sub headtag {
1.313 albertel 4540: my ($title,$head_extra,$args) = @_;
1.306 albertel 4541:
1.363 albertel 4542: my $function = $args->{'function'} || &get_users_function();
4543: my $domain = $args->{'domain'} || &determinedomain();
4544: my $bgcolor = $args->{'bgcolor'} || &designparm($function.'.pgbg',$domain);
1.418 albertel 4545: my $url = join(':',$env{'user.name'},$env{'user.domain'},
1.458 albertel 4546: $Apache::lonnet::perlvar{'lonVersion'},
1.531 albertel 4547: #time(),
1.418 albertel 4548: $env{'environment.color.timestamp'},
1.363 albertel 4549: $function,$domain,$bgcolor);
4550:
1.369 www 4551: $url = '/adm/css/'.&escape($url).'.css';
1.363 albertel 4552:
1.308 albertel 4553: my $result =
4554: '<head>'.
1.461 albertel 4555: &font_settings();
1.319 albertel 4556:
1.461 albertel 4557: if (!$args->{'frameset'}) {
4558: $result .= &Apache::lonhtmlcommon::htmlareaheaders();
4559: }
1.319 albertel 4560: if ($args->{'force_register'}) {
4561: $result .= &Apache::lonmenu::registerurl(1);
4562: }
1.436 albertel 4563: if (!$args->{'no_nav_bar'}
4564: && !$args->{'only_body'}
4565: && !$args->{'frameset'}) {
4566: $result .= &help_menu_js();
4567: }
1.319 albertel 4568:
1.314 albertel 4569: if (ref($args->{'redirect'})) {
1.414 albertel 4570: my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};
1.315 albertel 4571: $url = &Apache::lonenc::check_encrypt($url);
1.414 albertel 4572: if (!$inhibit_continue) {
4573: $env{'internal.head.redirect'} = $url;
4574: }
1.313 albertel 4575: $result.=<<ADDMETA
4576: <meta http-equiv="pragma" content="no-cache" />
1.344 albertel 4577: <meta http-equiv="Refresh" content="$time; url=$url" />
1.313 albertel 4578: ADDMETA
4579: }
1.306 albertel 4580: if (!defined($title)) {
4581: $title = 'The LearningOnline Network with CAPA';
4582: }
1.460 albertel 4583: if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); }
4584: $result .= '<title> LON-CAPA '.$title.'</title>'
1.414 albertel 4585: .'<link rel="stylesheet" type="text/css" href="'.$url.'" />'
4586: .$head_extra;
1.306 albertel 4587: return $result;
4588: }
4589:
4590: =pod
4591:
1.340 albertel 4592: =item * &font_settings()
4593:
4594: Returns neccessary <meta> to set the proper encoding
4595:
4596: Inputs: none
4597:
4598: =cut
4599:
4600: sub font_settings {
4601: my $headerstring='';
4602: if (($env{'browser.os'} eq 'mac') && (!$env{'browser.mathml'})) {
4603: $headerstring.=
4604: '<meta Content-Type="text/html; charset=x-mac-roman" />';
4605: } elsif (!$env{'browser.mathml'} && $env{'browser.unicode'}) {
4606: $headerstring.=
4607: '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />';
4608: }
4609: return $headerstring;
4610: }
4611:
1.341 albertel 4612: =pod
4613:
4614: =item * &xml_begin()
4615:
4616: Returns the needed doctype and <html>
4617:
4618: Inputs: none
4619:
4620: =cut
4621:
4622: sub xml_begin {
4623: my $output='';
4624:
1.342 albertel 4625: &Apache::lonhtmlcommon::init_htmlareafields();
4626:
1.341 albertel 4627: if ($env{'browser.mathml'}) {
4628: $output='<?xml version="1.0"?>'
4629: #.'<?xml-stylesheet type="text/css" href="/adm/MathML/mathml.css"?>'."\n"
4630: # .'<!DOCTYPE html SYSTEM "/adm/MathML/mathml.dtd" '
4631:
4632: # .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" [<!ENTITY mathns "http://www.w3.org/1998/Math/MathML">] >'
4633: .'<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN" "http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd">'
4634: .'<html xmlns:math="http://www.w3.org/1998/Math/MathML" '
4635: .'xmlns="http://www.w3.org/1999/xhtml">';
4636: } else {
4637: $output='<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html>';
4638: }
4639: return $output;
4640: }
1.340 albertel 4641:
4642: =pod
4643:
1.306 albertel 4644: =item * &endheadtag()
4645:
4646: Returns a uniform </head> for LON-CAPA web pages.
4647:
4648: Inputs: none
4649:
4650: =cut
4651:
4652: sub endheadtag {
4653: return '</head>';
4654: }
4655:
4656: =pod
4657:
4658: =item * &head()
4659:
4660: Returns a uniform complete <head>..</head> section for LON-CAPA web pages.
4661:
4662: Inputs: $title - optional title for the page
1.307 albertel 4663: $head_extra - optional extra HTML to put inside the <head>
1.405 albertel 4664:
1.306 albertel 4665: =cut
4666:
4667: sub head {
1.325 albertel 4668: my ($title,$head_extra,$args) = @_;
4669: return &headtag($title,$head_extra,$args).&endheadtag();
1.306 albertel 4670: }
4671:
4672: =pod
4673:
4674: =item * &start_page()
4675:
4676: Returns a complete <html> .. <body> section for LON-CAPA web pages.
4677:
4678: Inputs: $title - optional title for the page
4679: $head_extra - optional extra HTML to incude inside the <head>
1.315 albertel 4680: $args - additional optional args supported are:
1.317 albertel 4681: only_body -> is true will set &bodytag() onlybodytag
4682: arg on
4683: no_nav_bar -> is true will set &bodytag() notopbar arg on
4684: add_entries -> additional attributes to add to the <body>
4685: domain -> force to color decorate a page for a
4686: specific domain
4687: function -> force usage of a specific rolish color
4688: scheme
4689: redirect -> see &headtag()
4690: bgcolor -> override the default page bg color
4691: js_ready -> return a string ready for being used in
4692: a javascript writeln
1.320 albertel 4693: html_encode -> return a string ready for being used in
4694: a html attribute
1.317 albertel 4695: force_register -> if is true will turn on the &bodytag()
4696: $forcereg arg
1.326 albertel 4697: body_title -> alternate text to use instead of $title
4698: in the title box that appears, this text
4699: is not auto translated like the $title is
1.330 albertel 4700: frameset -> if true will start with a <frameset>
4701: rather than <body>
1.338 albertel 4702: no_title -> if true the title bar won't be shown
4703: skip_phases -> hash ref of
4704: head -> skip the <html><head> generation
4705: body -> skip all <body> generation
1.337 albertel 4706:
1.361 albertel 4707: no_inline_link -> if true and in remote mode, don't show the
4708: 'Switch To Inline Menu' link
4709:
1.460 albertel 4710: no_auto_mt_title -> prevent &mt()ing the title arg
4711:
1.306 albertel 4712: =cut
4713:
4714: sub start_page {
1.309 albertel 4715: my ($title,$head_extra,$args) = @_;
1.318 albertel 4716: #&Apache::lonnet::logthis("start_page ".join(':',caller(0)));
1.313 albertel 4717: my %head_args;
1.352 albertel 4718: foreach my $arg ('redirect','force_register','domain','function',
1.460 albertel 4719: 'bgcolor','frameset','no_nav_bar','only_body',
4720: 'no_auto_mt_title') {
1.319 albertel 4721: if (defined($args->{$arg})) {
1.324 raeburn 4722: $head_args{$arg} = $args->{$arg};
1.319 albertel 4723: }
1.313 albertel 4724: }
1.319 albertel 4725:
1.315 albertel 4726: $env{'internal.start_page'}++;
1.338 albertel 4727: my $result;
4728: if (! exists($args->{'skip_phases'}{'head'}) ) {
4729: $result.=
1.341 albertel 4730: &xml_begin().
1.338 albertel 4731: &headtag($title,$head_extra,\%head_args).&endheadtag();
4732: }
4733:
4734: if (! exists($args->{'skip_phases'}{'body'}) ) {
4735: if ($args->{'frameset'}) {
4736: my $attr_string = &make_attr_string($args->{'force_register'},
4737: $args->{'add_entries'});
4738: $result .= "\n<frameset $attr_string>\n";
4739: } else {
4740: $result .=
4741: &bodytag($title,
4742: $args->{'function'}, $args->{'add_entries'},
4743: $args->{'only_body'}, $args->{'domain'},
4744: $args->{'force_register'}, $args->{'body_title'},
4745: $args->{'no_nav_bar'}, $args->{'bgcolor'},
1.460 albertel 4746: $args->{'no_title'}, $args->{'no_inline_link'},
4747: $args);
1.338 albertel 4748: }
1.330 albertel 4749: }
1.338 albertel 4750:
1.315 albertel 4751: if ($args->{'js_ready'}) {
1.317 albertel 4752: $result = &js_ready($result);
1.315 albertel 4753: }
1.320 albertel 4754: if ($args->{'html_encode'}) {
4755: $result = &html_encode($result);
4756: }
1.315 albertel 4757: return $result;
1.306 albertel 4758: }
4759:
1.330 albertel 4760:
1.306 albertel 4761: =pod
4762:
4763: =item * &head()
4764:
4765: Returns a complete </body></html> section for LON-CAPA web pages.
4766:
1.315 albertel 4767: Inputs: $args - additional optional args supported are:
4768: js_ready -> return a string ready for being used in
4769: a javascript writeln
1.320 albertel 4770: html_encode -> return a string ready for being used in
4771: a html attribute
1.330 albertel 4772: frameset -> if true will start with a <frameset>
4773: rather than <body>
1.493 albertel 4774: dicsussion -> if true will get discussion from
4775: lonxml::xmlend
4776: (you can pass the target and parser arguments
4777: through optional 'target' and 'parser' args
4778: to this routine)
1.306 albertel 4779:
4780: =cut
4781:
4782: sub end_page {
1.315 albertel 4783: my ($args) = @_;
4784: $env{'internal.end_page'}++;
1.330 albertel 4785: my $result;
1.335 albertel 4786: if ($args->{'discussion'}) {
4787: my ($target,$parser);
4788: if (ref($args->{'discussion'})) {
4789: ($target,$parser) =($args->{'discussion'}{'target'},
4790: $args->{'discussion'}{'parser'});
4791: }
4792: $result .= &Apache::lonxml::xmlend($target,$parser);
4793: }
4794:
1.330 albertel 4795: if ($args->{'frameset'}) {
4796: $result .= '</frameset>';
4797: } else {
4798: $result .= &endbodytag();
4799: }
4800: $result .= "\n</html>";
4801:
1.315 albertel 4802: if ($args->{'js_ready'}) {
1.317 albertel 4803: $result = &js_ready($result);
1.315 albertel 4804: }
1.335 albertel 4805:
1.320 albertel 4806: if ($args->{'html_encode'}) {
4807: $result = &html_encode($result);
4808: }
1.335 albertel 4809:
1.315 albertel 4810: return $result;
4811: }
4812:
1.320 albertel 4813: sub html_encode {
4814: my ($result) = @_;
4815:
1.322 albertel 4816: $result = &HTML::Entities::encode($result,'<>&"');
1.320 albertel 4817:
4818: return $result;
4819: }
1.317 albertel 4820: sub js_ready {
4821: my ($result) = @_;
4822:
1.323 albertel 4823: $result =~ s/[\n\r]/ /xmsg;
4824: $result =~ s/\\/\\\\/xmsg;
4825: $result =~ s/'/\\'/xmsg;
1.372 albertel 4826: $result =~ s{</}{<\\/}xmsg;
1.317 albertel 4827:
4828: return $result;
4829: }
4830:
1.315 albertel 4831: sub validate_page {
4832: if ( exists($env{'internal.start_page'})
1.316 albertel 4833: && $env{'internal.start_page'} > 1) {
4834: &Apache::lonnet::logthis('start_page called multiple times '.
1.318 albertel 4835: $env{'internal.start_page'}.' '.
1.316 albertel 4836: $ENV{'request.filename'});
1.315 albertel 4837: }
4838: if ( exists($env{'internal.end_page'})
1.316 albertel 4839: && $env{'internal.end_page'} > 1) {
4840: &Apache::lonnet::logthis('end_page called multiple times '.
1.318 albertel 4841: $env{'internal.end_page'}.' '.
1.316 albertel 4842: $env{'request.filename'});
1.315 albertel 4843: }
4844: if ( exists($env{'internal.start_page'})
4845: && ! exists($env{'internal.end_page'})) {
1.316 albertel 4846: &Apache::lonnet::logthis('start_page called without end_page '.
4847: $env{'request.filename'});
1.315 albertel 4848: }
4849: if ( ! exists($env{'internal.start_page'})
4850: && exists($env{'internal.end_page'})) {
1.316 albertel 4851: &Apache::lonnet::logthis('end_page called without start_page'.
4852: $env{'request.filename'});
1.315 albertel 4853: }
1.306 albertel 4854: }
1.315 albertel 4855:
1.318 albertel 4856: sub simple_error_page {
4857: my ($r,$title,$msg) = @_;
4858: my $page =
4859: &Apache::loncommon::start_page($title).
4860: &mt($msg).
4861: &Apache::loncommon::end_page();
4862: if (ref($r)) {
4863: $r->print($page);
1.327 albertel 4864: return;
1.318 albertel 4865: }
4866: return $page;
4867: }
1.347 albertel 4868:
4869: {
4870: my $row_count;
4871: sub start_data_table {
1.422 albertel 4872: my ($add_class) = @_;
4873: my $css_class = (join(' ','LC_data_table',$add_class));
1.347 albertel 4874: undef($row_count);
1.422 albertel 4875: return '<table class="'.$css_class.'">'."\n";
1.347 albertel 4876: }
4877:
4878: sub end_data_table {
4879: undef($row_count);
1.389 albertel 4880: return '</table>'."\n";;
1.347 albertel 4881: }
4882:
4883: sub start_data_table_row {
1.422 albertel 4884: my ($add_class) = @_;
1.347 albertel 4885: $row_count++;
1.422 albertel 4886: my $css_class = ($row_count % 2)?'':'LC_even_row';
1.428 albertel 4887: $css_class = (join(' ',$css_class,$add_class));
1.422 albertel 4888: return '<tr class="'.$css_class.'">'."\n";;
1.347 albertel 4889: }
1.471 banghart 4890:
4891: sub continue_data_table_row {
4892: my ($add_class) = @_;
4893: my $css_class = ($row_count % 2)?'':'LC_even_row';
4894: $css_class = (join(' ',$css_class,$add_class));
4895: return '<tr class="'.$css_class.'">'."\n";;
4896: }
1.347 albertel 4897:
4898: sub end_data_table_row {
1.389 albertel 4899: return '</tr>'."\n";;
1.347 albertel 4900: }
1.367 www 4901:
1.421 albertel 4902: sub start_data_table_empty_row {
4903: $row_count++;
4904: return '<tr class="LC_empty_row" >'."\n";;
4905: }
4906:
4907: sub end_data_table_empty_row {
4908: return '</tr>'."\n";;
4909: }
4910:
1.367 www 4911: sub start_data_table_header_row {
1.389 albertel 4912: return '<tr class="LC_header_row">'."\n";;
1.367 www 4913: }
4914:
4915: sub end_data_table_header_row {
1.389 albertel 4916: return '</tr>'."\n";;
1.367 www 4917: }
1.347 albertel 4918: }
4919:
1.548 albertel 4920: =pod
4921:
4922: =item * &inhibit_menu_check($arg)
4923:
4924: Checks for a inhibitmenu state and generates output to preserve it
4925:
4926: Inputs: $arg - can be any of
4927: - undef - in which case the return value is a string
4928: to add into arguments list of a uri
4929: - 'input' - in which case the return value is a HTML
4930: <form> <input> field of type hidden to
4931: preserve the value
4932: - a url - in which case the return value is the url with
4933: the neccesary cgi args added to preserve the
4934: inhibitmenu state
4935: - a ref to a url - no return value, but the string is
4936: updated to include the neccessary cgi
4937: args to preserve the inhibitmenu state
4938:
4939: =cut
4940:
4941: sub inhibit_menu_check {
4942: my ($arg) = @_;
4943: &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']);
4944: if ($arg eq 'input') {
4945: if ($env{'form.inhibitmenu'}) {
4946: return '<input type="hidden" name="inhibitmenu" value="'.$env{'form.inhibitmenu'}.'" />';
4947: } else {
4948: return
4949: }
4950: }
4951: if ($env{'form.inhibitmenu'}) {
4952: if (ref($arg)) {
4953: $$arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
4954: } elsif ($arg eq '') {
4955: $arg .= 'inhibitmenu='.$env{'form.inhibitmenu'};
4956: } else {
4957: $arg .= '?inhibitmenu='.$env{'form.inhibitmenu'};
4958: }
4959: }
4960: if (!ref($arg)) {
4961: return $arg;
4962: }
4963: }
4964:
1.251 albertel 4965: ###############################################
1.182 matthew 4966:
4967: =pod
4968:
1.549 albertel 4969: =back
4970:
4971: =head1 User Information Routines
4972:
4973: =over 4
4974:
1.405 albertel 4975: =item * &get_users_function()
1.182 matthew 4976:
4977: Used by &bodytag to determine the current users primary role.
4978: Returns either 'student','coordinator','admin', or 'author'.
4979:
4980: =cut
4981:
4982: ###############################################
4983: sub get_users_function {
4984: my $function = 'student';
1.258 albertel 4985: if ($env{'request.role'}=~/^(cc|in|ta|ep)/) {
1.182 matthew 4986: $function='coordinator';
4987: }
1.258 albertel 4988: if ($env{'request.role'}=~/^(su|dc|ad|li)/) {
1.182 matthew 4989: $function='admin';
4990: }
1.258 albertel 4991: if (($env{'request.role'}=~/^(au|ca)/) ||
1.182 matthew 4992: ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) {
4993: $function='author';
4994: }
4995: return $function;
1.54 www 4996: }
1.99 www 4997:
4998: ###############################################
4999:
1.233 raeburn 5000: =pod
5001:
1.542 raeburn 5002: =item * &check_user_status()
1.274 raeburn 5003:
5004: Determines current status of supplied role for a
5005: specific user. Roles can be active, previous or future.
5006:
5007: Inputs:
5008: user's domain, user's username, course's domain,
1.375 raeburn 5009: course's number, optional section ID.
1.274 raeburn 5010:
5011: Outputs:
5012: role status: active, previous or future.
5013:
5014: =cut
5015:
5016: sub check_user_status {
1.412 raeburn 5017: my ($udom,$uname,$cdom,$crs,$role,$sec) = @_;
1.274 raeburn 5018: my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname);
5019: my @uroles = keys %userinfo;
5020: my $srchstr;
5021: my $active_chk = 'none';
1.412 raeburn 5022: my $now = time;
1.274 raeburn 5023: if (@uroles > 0) {
1.412 raeburn 5024: if (($role eq 'cc') || ($sec eq '') || (!defined($sec))) {
1.274 raeburn 5025: $srchstr = '/'.$cdom.'/'.$crs.'_'.$role;
5026: } else {
1.412 raeburn 5027: $srchstr = '/'.$cdom.'/'.$crs.'/'.$sec.'_'.$role;
5028: }
5029: if (grep/^\Q$srchstr\E$/,@uroles) {
1.274 raeburn 5030: my $role_end = 0;
5031: my $role_start = 0;
5032: $active_chk = 'active';
1.412 raeburn 5033: if ($userinfo{$srchstr} =~ m/^\Q$role\E_(\d+)/) {
5034: $role_end = $1;
5035: if ($userinfo{$srchstr} =~ m/^\Q$role\E_\Q$role_end\E_(\d+)$/) {
5036: $role_start = $1;
1.274 raeburn 5037: }
5038: }
5039: if ($role_start > 0) {
1.412 raeburn 5040: if ($now < $role_start) {
1.274 raeburn 5041: $active_chk = 'future';
5042: }
5043: }
5044: if ($role_end > 0) {
1.412 raeburn 5045: if ($now > $role_end) {
1.274 raeburn 5046: $active_chk = 'previous';
5047: }
5048: }
5049: }
5050: }
5051: return $active_chk;
5052: }
5053:
5054: ###############################################
5055:
5056: =pod
5057:
1.405 albertel 5058: =item * &get_sections()
1.233 raeburn 5059:
5060: Determines all the sections for a course including
5061: sections with students and sections containing other roles.
1.419 raeburn 5062: Incoming parameters:
5063:
5064: 1. domain
5065: 2. course number
5066: 3. reference to array containing roles for which sections should
5067: be gathered (optional).
5068: 4. reference to array containing status types for which sections
5069: should be gathered (optional).
5070:
5071: If the third argument is undefined, sections are gathered for any role.
5072: If the fourth argument is undefined, sections are gathered for any status.
5073: Permissible values are 'active' or 'future' or 'previous'.
1.233 raeburn 5074:
1.374 raeburn 5075: Returns section hash (keys are section IDs, values are
5076: number of users in each section), subject to the
1.419 raeburn 5077: optional roles filter, optional status filter
1.233 raeburn 5078:
5079: =cut
5080:
5081: ###############################################
5082: sub get_sections {
1.419 raeburn 5083: my ($cdom,$cnum,$possible_roles,$possible_status) = @_;
1.366 albertel 5084: if (!defined($cdom) || !defined($cnum)) {
5085: my $cid = $env{'request.course.id'};
5086:
5087: return if (!defined($cid));
5088:
5089: $cdom = $env{'course.'.$cid.'.domain'};
5090: $cnum = $env{'course.'.$cid.'.num'};
5091: }
5092:
5093: my %sectioncount;
1.419 raeburn 5094: my $now = time;
1.240 albertel 5095:
1.366 albertel 5096: if (!defined($possible_roles) || (grep(/^st$/,@$possible_roles))) {
1.276 albertel 5097: my ($classlist) = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.240 albertel 5098: my $sec_index = &Apache::loncoursedata::CL_SECTION();
5099: my $status_index = &Apache::loncoursedata::CL_STATUS();
1.419 raeburn 5100: my $start_index = &Apache::loncoursedata::CL_START();
5101: my $end_index = &Apache::loncoursedata::CL_END();
5102: my $status;
1.366 albertel 5103: while (my ($student,$data) = each(%$classlist)) {
1.419 raeburn 5104: my ($section,$stu_status,$start,$end) = ($data->[$sec_index],
5105: $data->[$status_index],
5106: $data->[$start_index],
5107: $data->[$end_index]);
5108: if ($stu_status eq 'Active') {
5109: $status = 'active';
5110: } elsif ($end < $now) {
5111: $status = 'previous';
5112: } elsif ($start > $now) {
5113: $status = 'future';
5114: }
5115: if ($section ne '-1' && $section !~ /^\s*$/) {
5116: if ((!defined($possible_status)) || (($status ne '') &&
5117: (grep/^\Q$status\E$/,@{$possible_status}))) {
5118: $sectioncount{$section}++;
5119: }
1.240 albertel 5120: }
5121: }
5122: }
5123: my %courseroles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
5124: foreach my $user (sort(keys(%courseroles))) {
5125: if ($user !~ /^(\w{2})/) { next; }
5126: my ($role) = ($user =~ /^(\w{2})/);
5127: if ($possible_roles && !(grep(/^$role$/,@$possible_roles))) { next; }
1.419 raeburn 5128: my ($section,$status);
1.240 albertel 5129: if ($role eq 'cr' &&
5130: $user =~ m-^$role/[^/]*/[^/]*/[^/]*:[^:]*:[^:]*:(\w+)-) {
5131: $section=$1;
5132: }
5133: if ($user =~ /^$role:[^:]*:[^:]*:(\w+)/) { $section=$1; }
5134: if (!defined($section) || $section eq '-1') { next; }
1.419 raeburn 5135: my ($end,$start) = ($courseroles{$user} =~ /^([^:]*):([^:]*)$/);
5136: if ($end == -1 && $start == -1) {
5137: next; #deleted role
5138: }
5139: if (!defined($possible_status)) {
5140: $sectioncount{$section}++;
5141: } else {
5142: if ((!$end || $end >= $now) && (!$start || $start <= $now)) {
5143: $status = 'active';
5144: } elsif ($end < $now) {
5145: $status = 'future';
5146: } elsif ($start > $now) {
5147: $status = 'previous';
5148: }
5149: if (($status ne '') && (grep/^\Q$status\E$/,@{$possible_status})) {
5150: $sectioncount{$section}++;
5151: }
5152: }
1.233 raeburn 5153: }
1.366 albertel 5154: return %sectioncount;
1.233 raeburn 5155: }
5156:
1.274 raeburn 5157: ###############################################
1.294 raeburn 5158:
5159: =pod
1.405 albertel 5160:
5161: =item * &get_course_users()
5162:
1.275 raeburn 5163: Retrieves usernames:domains for users in the specified course
5164: with specific role(s), and access status.
5165:
5166: Incoming parameters:
1.277 albertel 5167: 1. course domain
5168: 2. course number
5169: 3. access status: users must have - either active,
1.275 raeburn 5170: previous, future, or all.
1.277 albertel 5171: 4. reference to array of permissible roles
1.288 raeburn 5172: 5. reference to array of section restrictions (optional)
5173: 6. reference to results object (hash of hashes).
5174: 7. reference to optional userdata hash
1.275 raeburn 5175: Keys of top level hash are roles.
5176: Keys of inner hashes are username:domain, with
5177: values set to access type.
1.288 raeburn 5178: Optional userdata hash returns an array with arguments in the
5179: same order as loncoursedata::get_classlist() for student data.
5180:
5181: Entries for end, start, section and status are blank because
5182: of the possibility of multiple values for non-student roles.
5183:
1.275 raeburn 5184: =cut
1.405 albertel 5185:
1.275 raeburn 5186: ###############################################
1.405 albertel 5187:
1.275 raeburn 5188: sub get_course_users {
1.288 raeburn 5189: my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_;
5190: my %idx = ();
1.419 raeburn 5191: my %seclists;
1.288 raeburn 5192:
5193: $idx{udom} = &Apache::loncoursedata::CL_SDOM();
5194: $idx{uname} = &Apache::loncoursedata::CL_SNAME();
5195: $idx{end} = &Apache::loncoursedata::CL_END();
5196: $idx{start} = &Apache::loncoursedata::CL_START();
5197: $idx{id} = &Apache::loncoursedata::CL_ID();
5198: $idx{section} = &Apache::loncoursedata::CL_SECTION();
5199: $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME();
5200: $idx{status} = &Apache::loncoursedata::CL_STATUS();
5201:
1.290 albertel 5202: if (grep(/^st$/,@{$roles})) {
1.276 albertel 5203: my ($classlist,$keylist)=&Apache::loncoursedata::get_classlist($cdom,$cnum);
1.278 raeburn 5204: my $now = time;
1.277 albertel 5205: foreach my $student (keys(%{$classlist})) {
1.288 raeburn 5206: my $match = 0;
1.412 raeburn 5207: my $secmatch = 0;
1.419 raeburn 5208: my $section = $$classlist{$student}[$idx{section}];
5209: if ($section eq '') {
5210: $section = 'none';
5211: }
1.291 albertel 5212: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 5213: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 5214: $secmatch = 1;
5215: } elsif ($$classlist{$student}[$idx{section}] eq '') {
1.420 albertel 5216: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 5217: $secmatch = 1;
5218: }
5219: } else {
1.419 raeburn 5220: if (grep(/^\Q$section\E$/,@{$sections})) {
1.412 raeburn 5221: $secmatch = 1;
5222: }
1.290 albertel 5223: }
1.412 raeburn 5224: if (!$secmatch) {
5225: next;
5226: }
1.419 raeburn 5227: }
1.420 albertel 5228: push(@{$seclists{$student}},$section);
1.275 raeburn 5229: if (defined($$types{'active'})) {
1.288 raeburn 5230: if ($$classlist{$student}[$idx{status}] eq 'Active') {
1.275 raeburn 5231: push(@{$$users{st}{$student}},'active');
1.288 raeburn 5232: $match = 1;
1.275 raeburn 5233: }
5234: }
5235: if (defined($$types{'previous'})) {
1.288 raeburn 5236: if ($$classlist{$student}[$idx{end}] <= $now) {
1.275 raeburn 5237: push(@{$$users{st}{$student}},'previous');
1.288 raeburn 5238: $match = 1;
1.275 raeburn 5239: }
5240: }
5241: if (defined($$types{'future'})) {
1.288 raeburn 5242: if (($$classlist{$student}[$idx{start}] > $now) && ($$classlist{$student}[$idx{end}] > $now) || ($$classlist{$student}[$idx{end}] == 0) || ($$classlist{$student}[$idx{end}] eq '')) {
1.275 raeburn 5243: push(@{$$users{st}{$student}},'future');
1.288 raeburn 5244: $match = 1;
1.275 raeburn 5245: }
5246: }
1.412 raeburn 5247: if ($match && ref($userdata) eq 'HASH') {
1.288 raeburn 5248: $$userdata{$student} = $$classlist{$student};
5249: }
1.275 raeburn 5250: }
5251: }
1.412 raeburn 5252: if ((@{$roles} > 1) || ((@{$roles} == 1) && ($$roles[0] ne "st"))) {
1.439 raeburn 5253: my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
5254: my $now = time;
5255: foreach my $person (sort(keys(%coursepersonnel))) {
1.288 raeburn 5256: my $match = 0;
1.412 raeburn 5257: my $secmatch = 0;
1.439 raeburn 5258: my $status;
1.412 raeburn 5259: my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/);
1.275 raeburn 5260: $user =~ s/:$//;
1.439 raeburn 5261: my ($end,$start) = split(/:/,$coursepersonnel{$person});
5262: if ($end == -1 || $start == -1) {
5263: next;
5264: }
5265: if (($role) && ((grep(/^\Q$role\E$/,@{$roles})) ||
5266: (grep(/^cr$/,@{$roles}) && $role =~ /^cr\//))) {
1.412 raeburn 5267: my ($uname,$udom) = split(/:/,$user);
5268: if ((ref($sections) eq 'ARRAY') && (@{$sections} > 0)) {
1.420 albertel 5269: if (grep(/^all$/,@{$sections})) {
1.412 raeburn 5270: $secmatch = 1;
5271: } elsif ($usec eq '') {
1.420 albertel 5272: if (grep(/^none$/,@{$sections})) {
1.412 raeburn 5273: $secmatch = 1;
5274: }
5275: } else {
5276: if (grep(/^\Q$usec\E$/,@{$sections})) {
5277: $secmatch = 1;
5278: }
5279: }
5280: if (!$secmatch) {
5281: next;
5282: }
1.288 raeburn 5283: }
1.419 raeburn 5284: if ($usec eq '') {
5285: $usec = 'none';
5286: }
1.275 raeburn 5287: if ($uname ne '' && $udom ne '') {
1.503 raeburn 5288: if ($end > 0 && $end < $now) {
1.439 raeburn 5289: $status = 'previous';
5290: } elsif ($start > $now) {
5291: $status = 'future';
5292: } else {
5293: $status = 'active';
5294: }
1.277 albertel 5295: foreach my $type (keys(%{$types})) {
1.275 raeburn 5296: if ($status eq $type) {
1.420 albertel 5297: if (!grep(/^\Q$type\E$/,@{$$users{$role}{$user}})) {
1.419 raeburn 5298: push(@{$$users{$role}{$user}},$type);
5299: }
1.288 raeburn 5300: $match = 1;
5301: }
5302: }
1.419 raeburn 5303: if (($match) && (ref($userdata) eq 'HASH')) {
5304: if (!exists($$userdata{$uname.':'.$udom})) {
5305: &get_user_info($udom,$uname,\%idx,$userdata);
5306: }
1.420 albertel 5307: if (!grep(/^\Q$usec\E$/,@{$seclists{$uname.':'.$udom}})) {
1.419 raeburn 5308: push(@{$seclists{$uname.':'.$udom}},$usec);
5309: }
1.275 raeburn 5310: }
5311: }
5312: }
5313: }
1.290 albertel 5314: if (grep(/^ow$/,@{$roles})) {
1.279 raeburn 5315: if ((defined($cdom)) && (defined($cnum))) {
5316: my %csettings = &Apache::lonnet::get('environment',['internal.courseowner'],$cdom,$cnum);
5317: if ( defined($csettings{'internal.courseowner'}) ) {
5318: my $owner = $csettings{'internal.courseowner'};
1.439 raeburn 5319: if ($owner !~ /^[^:]+:[^:]+$/) {
5320: $owner = $owner.':'.$cdom;
5321: }
5322: @{$$users{'ow'}{$owner}} = 'any';
1.290 albertel 5323: if (defined($userdata) &&
5324: !exists($$userdata{$owner.':'.$cdom})) {
5325: &get_user_info($cdom,$owner,\%idx,$userdata);
1.420 albertel 5326: if (!grep(/^none$/,@{$seclists{$owner.':'.$cdom}})) {
1.419 raeburn 5327: push(@{$seclists{$owner.':'.$cdom}},'none');
5328: }
1.290 albertel 5329: }
1.279 raeburn 5330: }
5331: }
5332: }
1.419 raeburn 5333: foreach my $user (keys(%seclists)) {
5334: @{$seclists{$user}} = (sort {$a <=> $b} @{$seclists{$user}});
5335: $$userdata{$user}[$idx{section}] = join(',',@{$seclists{$user}});
5336: }
1.275 raeburn 5337: }
5338: return;
5339: }
5340:
1.288 raeburn 5341: sub get_user_info {
5342: my ($udom,$uname,$idx,$userdata) = @_;
1.289 albertel 5343: $$userdata{$uname.':'.$udom}[$$idx{fullname}] =
5344: &plainname($uname,$udom,'lastname');
1.291 albertel 5345: $$userdata{$uname.':'.$udom}[$$idx{uname}] = $uname;
1.297 raeburn 5346: $$userdata{$uname.':'.$udom}[$$idx{udom}] = $udom;
1.288 raeburn 5347: return;
5348: }
1.275 raeburn 5349:
1.472 raeburn 5350: ###############################################
5351:
5352: =pod
5353:
5354: =item * &get_user_quota()
5355:
5356: Retrieves quota assigned for storage of portfolio files for a user
5357:
5358: Incoming parameters:
5359: 1. user's username
5360: 2. user's domain
5361:
5362: Returns:
1.536 raeburn 5363: 1. Disk quota (in Mb) assigned to student.
5364: 2. (Optional) Type of setting: custom or default
5365: (individually assigned or default for user's
5366: institutional status).
5367: 3. (Optional) - User's institutional status (e.g., faculty, staff
5368: or student - types as defined in localenroll::inst_usertypes
5369: for user's domain, which determines default quota for user.
5370: 4. (Optional) - Default quota which would apply to the user.
1.472 raeburn 5371:
5372: If a value has been stored in the user's environment,
1.536 raeburn 5373: it will return that, otherwise it returns the maximal default
5374: defined for the user's instituional status(es) in the domain.
1.472 raeburn 5375:
5376: =cut
5377:
5378: ###############################################
5379:
5380:
5381: sub get_user_quota {
5382: my ($uname,$udom) = @_;
1.536 raeburn 5383: my ($quota,$quotatype,$settingstatus,$defquota);
1.472 raeburn 5384: if (!defined($udom)) {
5385: $udom = $env{'user.domain'};
5386: }
5387: if (!defined($uname)) {
5388: $uname = $env{'user.name'};
5389: }
5390: if (($udom eq '' || $uname eq '') ||
5391: ($udom eq 'public') && ($uname eq 'public')) {
5392: $quota = 0;
1.536 raeburn 5393: $quotatype = 'default';
5394: $defquota = 0;
1.472 raeburn 5395: } else {
1.536 raeburn 5396: my $inststatus;
1.472 raeburn 5397: if ($udom eq $env{'user.domain'} && $uname eq $env{'user.name'}) {
5398: $quota = $env{'environment.portfolioquota'};
1.536 raeburn 5399: $inststatus = $env{'environment.inststatus'};
1.472 raeburn 5400: } else {
1.536 raeburn 5401: my %userenv =
5402: &Apache::lonnet::get('environment',['portfolioquota',
5403: 'inststatus'],$udom,$uname);
1.472 raeburn 5404: my ($tmp) = keys(%userenv);
5405: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
5406: $quota = $userenv{'portfolioquota'};
1.536 raeburn 5407: $inststatus = $userenv{'inststatus'};
1.472 raeburn 5408: } else {
5409: undef(%userenv);
5410: }
5411: }
1.536 raeburn 5412: ($defquota,$settingstatus) = &default_quota($udom,$inststatus);
1.472 raeburn 5413: if ($quota eq '') {
1.536 raeburn 5414: $quota = $defquota;
5415: $quotatype = 'default';
5416: } else {
5417: $quotatype = 'custom';
1.472 raeburn 5418: }
5419: }
1.536 raeburn 5420: if (wantarray) {
5421: return ($quota,$quotatype,$settingstatus,$defquota);
5422: } else {
5423: return $quota;
5424: }
1.472 raeburn 5425: }
5426:
5427: ###############################################
5428:
5429: =pod
5430:
5431: =item * &default_quota()
5432:
1.536 raeburn 5433: Retrieves default quota assigned for storage of user portfolio files,
5434: given an (optional) user's institutional status.
1.472 raeburn 5435:
5436: Incoming parameters:
5437: 1. domain
1.536 raeburn 5438: 2. (Optional) institutional status(es). This is a : separated list of
5439: status types (e.g., faculty, staff, student etc.)
5440: which apply to the user for whom the default is being retrieved.
5441: If the institutional status string in undefined, the domain
5442: default quota will be returned.
1.472 raeburn 5443:
5444: Returns:
5445: 1. Default disk quota (in Mb) for user portfolios in the domain.
1.536 raeburn 5446: 2. (Optional) institutional type which determined the value of the
5447: default quota.
1.472 raeburn 5448:
5449: If a value has been stored in the domain's configuration db,
5450: it will return that, otherwise it returns 20 (for backwards
5451: compatibility with domains which have not set up a configuration
5452: db file; the original statically defined portfolio quota was 20 Mb).
5453:
1.536 raeburn 5454: If the user's status includes multiple types (e.g., staff and student),
5455: the largest default quota which applies to the user determines the
5456: default quota returned.
5457:
1.472 raeburn 5458: =cut
5459:
5460: ###############################################
5461:
5462:
5463: sub default_quota {
1.536 raeburn 5464: my ($udom,$inststatus) = @_;
5465: my ($defquota,$settingstatus);
5466: my %quotahash = &Apache::lonnet::get_dom('configuration',
5467: ['quota'],$udom);
5468: if (ref($quotahash{'quota'}) eq 'HASH') {
5469: if ($inststatus ne '') {
5470: my @statuses = split(/:/,$inststatus);
5471: foreach my $item (@statuses) {
5472: if ($quotahash{'quota'}{$item} ne '') {
5473: if ($defquota eq '') {
5474: $defquota = $quotahash{'quota'}{$item};
5475: $settingstatus = $item;
5476: } elsif ($quotahash{'quota'}{$item} > $defquota) {
5477: $defquota = $quotahash{'quota'}{$item};
5478: $settingstatus = $item;
5479: }
5480: }
5481: }
5482: }
5483: if ($defquota eq '') {
5484: $defquota = $quotahash{'quota'}{'default'};
5485: $settingstatus = 'default';
5486: }
5487: } else {
5488: $settingstatus = 'default';
5489: $defquota = 20;
5490: }
5491: if (wantarray) {
5492: return ($defquota,$settingstatus);
1.472 raeburn 5493: } else {
1.536 raeburn 5494: return $defquota;
1.472 raeburn 5495: }
5496: }
5497:
1.384 raeburn 5498: sub get_secgrprole_info {
5499: my ($cdom,$cnum,$needroles,$type) = @_;
5500: my %sections_count = &get_sections($cdom,$cnum);
5501: my @sections = (sort {$a <=> $b} keys(%sections_count));
5502: my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum);
5503: my @groups = sort(keys(%curr_groups));
5504: my $allroles = [];
5505: my $rolehash;
5506: my $accesshash = {
5507: active => 'Currently has access',
5508: future => 'Will have future access',
5509: previous => 'Previously had access',
5510: };
5511: if ($needroles) {
5512: $rolehash = {'all' => 'all'};
1.385 albertel 5513: my %user_roles = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum);
5514: if (&Apache::lonnet::error(%user_roles)) {
5515: undef(%user_roles);
5516: }
5517: foreach my $item (keys(%user_roles)) {
1.384 raeburn 5518: my ($role)=split(/\:/,$item,2);
5519: if ($role eq 'cr') { next; }
5520: if ($role =~ /^cr/) {
5521: $$rolehash{$role} = (split('/',$role))[3];
5522: } else {
5523: $$rolehash{$role} = &Apache::lonnet::plaintext($role,$type);
5524: }
5525: }
5526: foreach my $key (sort(keys(%{$rolehash}))) {
5527: push(@{$allroles},$key);
5528: }
5529: push (@{$allroles},'st');
5530: $$rolehash{'st'} = &Apache::lonnet::plaintext('st',$type);
5531: }
5532: return (\@sections,\@groups,$allroles,$rolehash,$accesshash);
5533: }
5534:
1.555 raeburn 5535: sub user_picker {
5536: my ($dom,$srch,$forcenewuser) = @_;
5537: my $currdom = $dom;
5538: my %curr_selected = (
5539: srchin => 'dom',
5540: srchby => 'uname',
5541: );
5542: my $srchterm;
5543: if (ref($srch) eq 'HASH') {
5544: if ($srch->{'srchby'} ne '') {
5545: $curr_selected{'srchby'} = $srch->{'srchby'};
5546: }
5547: if ($srch->{'srchin'} ne '') {
5548: $curr_selected{'srchin'} = $srch->{'srchin'};
5549: }
5550: if ($srch->{'srchtype'} ne '') {
5551: $curr_selected{'srchtype'} = $srch->{'srchtype'};
5552: }
5553: if ($srch->{'srchdomain'} ne '') {
5554: $currdom = $srch->{'srchdomain'};
5555: }
5556: $srchterm = $srch->{'srchterm'};
5557: }
5558:
5559: my %lt=&Apache::lonlocal::texthash(
5560: 'usr' => 'Search for',
5561: 'or' => 'or',
5562: 'in' => 'in',
5563: 'doma' => 'domain',
5564: 'uname' => 'username',
5565: 'lastname' => 'last name',
5566: 'lastfirst' => 'last name, first name',
5567: 'crs' => 'this course',
5568: 'dom' => 'this domain',
5569: 'alc' => 'all LON-CAPA',
5570: 'instd' => 'institutional directory',
5571: 'exact' => 'as exact match to',
5572: 'contains' => 'contained in',
5573: );
5574: my $domform = &select_dom_form($currdom,'srchdomain',1);
5575:
5576: my $srchinsel = ' <select name="srchin">';
5577:
5578: my @srchins = ('crs','dom','alc','instd');
5579:
5580: foreach my $option (@srchins) {
5581: # FIXME 'alc' option unavailable until
5582: # loncreateuser::print_user_query_page()
5583: # has been completed.
5584: next if ($option eq 'alc');
5585: next if ($option eq 'crs' && !$env{'request.course.id'});
5586: if ($curr_selected{'srchin'} eq $option) {
5587: $srchinsel .= '
5588: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
5589: } else {
5590: $srchinsel .= '
5591: <option value="'.$option.'">'.$lt{$option}.'</option>';
5592: }
5593: }
5594: $srchinsel .= "\n </select>\n";
5595:
5596: my $srchbysel = ' <select name="srchby">';
5597: foreach my $option ('uname','lastname','lastfirst') {
5598: if ($curr_selected{'srchby'} eq $option) {
5599: $srchbysel .= '
5600: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
5601: } else {
5602: $srchbysel .= '
5603: <option value="'.$option.'">'.$lt{$option}.'</option>';
5604: }
5605: }
5606: $srchbysel .= "\n </select>\n";
5607:
5608: my $srchtypesel = ' <select name="srchtype">';
5609: foreach my $option ('exact','contains') {
5610: if ($curr_selected{'srchtype'} eq $option) {
5611: $srchtypesel .= '
5612: <option value="'.$option.'" selected="selected">'.$lt{$option}.'</option>';
5613: } else {
5614: $srchtypesel .= '
5615: <option value="'.$option.'">'.$lt{$option}.'</option>';
5616: }
5617: }
5618: $srchtypesel .= "\n </select>\n";
5619:
1.556 ! raeburn 5620: my ($newuserscript,$newuservalidate);
! 5621:
! 5622: if ($forcenewuser) {
! 5623: $newuserscript = <<"ENDSCRIPT";
! 5624:
! 5625: function setSearch() {
! 5626: var createnew = 0;
! 5627: for (var i=0; i<document.crtuser.forcenew.length; i++) {
! 5628: if (document.crtuser.forcenew[i].checked) {
! 5629: if (document.crtuser.forcenew[i].value == 1) {
! 5630: createnew = 1;
! 5631: }
! 5632: }
! 5633: }
! 5634: if (createnew == 1) {
! 5635: for (var i=0; i<document.crtuser.srchby.length; i++) {
! 5636: if (document.crtuser.srchby.options[i].value == 'uname') {
! 5637: document.crtuser.srchby.selectedIndex = i;
! 5638: }
! 5639: }
! 5640: for (var i=0; i<document.crtuser.srchin.length; i++) {
! 5641: if (document.crtuser.srchin.options[i].value == 'dom') {
! 5642: document.crtuser.srchin.selectedIndex = i;
! 5643: }
! 5644: }
! 5645: for (var i=0; i<document.crtuser.srchtype.length; i++) {
! 5646: if (document.crtuser.srchtype.options[i].value == 'exact') {
! 5647: document.crtuser.srchtype.selectedIndex = i;
! 5648: }
! 5649: }
! 5650: for (var i=0; i<document.crtuser.srchdomain.length; i++) {
! 5651: if (document.crtuser.srchdomain.options[i].value == '$env{'request.role.domain'}') {
! 5652: document.crtuser.srchdomain.selectedIndex = i;
! 5653: }
! 5654: }
! 5655: }
! 5656: }
! 5657: ENDSCRIPT
! 5658: $newuservalidate = <<"ENDBLOCK";
! 5659: setSearch();
! 5660: ENDBLOCK
! 5661: }
! 5662:
1.555 raeburn 5663: my $output = <<"END_BLOCK";
1.556 ! raeburn 5664: <script type="text/javascript">
! 5665: function validateEntry() {
! 5666: $newuservalidate
! 5667: var checkok = 1;
! 5668: var srchin = document.crtuser.srchin.options[document.crtuser.srchin.selectedIndex].value;
! 5669: var srchtype = document.crtuser.srchtype.options[document.crtuser.srchtype.selectedIndex].value;
! 5670: var srchby = document.crtuser.srchby.options[document.crtuser.srchby.selectedIndex].value;
! 5671: var srchdomain = document.crtuser.srchdomain.options[document.crtuser.srchdomain.selectedIndex].value;
! 5672: var srchterm = document.crtuser.srchterm.value;
! 5673: var msg = "";
! 5674:
! 5675: if (srchterm == "") {
! 5676: checkok = 0;
! 5677: msg += "You must include some text to search for.\\n";
! 5678: }
! 5679:
! 5680: if (srchtype== 'contains') {
! 5681: if (srchterm.length < 3) {
! 5682: checkok = 0;
! 5683: msg += "The text you are searching for must contain at least three characters when using a 'contained in' type search.\\n";
! 5684: }
! 5685: }
! 5686: if (srchin == 'instd') {
! 5687: if (srchdomain == '') {
! 5688: checkok = 0;
! 5689: msg += "You must choose a domain when using an institutional directory search.\\n";
! 5690: }
! 5691: }
! 5692: if (srchin == 'dom') {
! 5693: if (srchdomain == '') {
! 5694: checkok = 0;
! 5695: msg += "You must choose a domain when using a domain search.\\n";
! 5696: }
! 5697: }
! 5698: if (srchby == 'lastfirst') {
! 5699: if (srchterm.indexOf(",") == -1) {
! 5700: checkok = 0;
! 5701: msg += "When using searching by last,first you must include a comma as separator between last name and first name.\\n";
! 5702: }
! 5703: if (srchterm.indexOf(",") == srchterm.length -1) {
! 5704: checkok = 0;
! 5705: msg += "When searching by last,first you must include at least one character in the first name.\\n";
! 5706: }
! 5707: }
! 5708: if (checkok == 0) {
! 5709: alert("The following need to be corrected before the search can be run:\\n"+msg);
! 5710: return;
! 5711: }
! 5712: if (checkok == 1) {
! 5713: document.crtuser.submit();
! 5714: }
! 5715: }
! 5716:
! 5717: $newuserscript
! 5718:
! 5719: </script>
1.555 raeburn 5720: <table>
5721: <tr>
5722: <td align="right">$lt{'usr'}:</td><td><input type="text" size="15" name="srchterm" value="$srchterm" /></td>
5723: <td>
5724: $srchtypesel
5725: </td>
5726: <td>
5727: $srchbysel
5728: </td>
5729: </tr>
5730: <tr>
5731: <td align="right">$lt{'in'}:</td>
5732: <td colspan="2">
5733: $srchinsel
5734: </td>
5735: </tr>
5736: <tr>
5737: <td align="right">$lt{'doma'}:</td><td colspan="2">$domform</td>
5738: </tr>
5739: </table>
5740: <br />
5741: END_BLOCK
5742: if ($forcenewuser) {
5743: $output .= '<span class="LC_nobreak">'.&mt('Make new user if no match found: ').'<input type="radio" name="forcenew" value="1" onclick="javascript:setSearch()" />'.&mt('Yes').' <input type="radio" name="forcenew" value="0" checked="checked" />'.&mt('No').'</span><br />';
5744: }
5745: return $output;
5746: }
5747:
1.556 ! raeburn 5748:
! 5749:
1.112 bowersj2 5750: =pod
5751:
1.549 albertel 5752: =back
5753:
5754: =head1 HTTP Helpers
5755:
5756: =over 4
5757:
1.112 bowersj2 5758: =item * get_unprocessed_cgi($query,$possible_names)
5759:
1.258 albertel 5760: Modify the %env hash to contain unprocessed CGI form parameters held in
1.112 bowersj2 5761: $query. The parameters listed in $possible_names (an array reference),
1.258 albertel 5762: will be set in $env{'form.name'} if they do not already exist.
1.112 bowersj2 5763:
5764: Typically called with $ENV{'QUERY_STRING'} as the first parameter.
5765: $possible_names is an ref to an array of form element names. As an example:
5766: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']);
1.258 albertel 5767: will result in $env{'form.uname'} and $env{'form.udom'} being set.
1.112 bowersj2 5768:
5769: =cut
1.1 albertel 5770:
1.6 albertel 5771: sub get_unprocessed_cgi {
1.25 albertel 5772: my ($query,$possible_names)= @_;
1.26 matthew 5773: # $Apache::lonxml::debug=1;
1.356 albertel 5774: foreach my $pair (split(/&/,$query)) {
5775: my ($name, $value) = split(/=/,$pair);
1.369 www 5776: $name = &unescape($name);
1.25 albertel 5777: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
5778: $value =~ tr/+/ /;
5779: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
1.258 albertel 5780: unless (defined($env{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 5781: }
1.16 harris41 5782: }
1.6 albertel 5783: }
5784:
1.112 bowersj2 5785: =pod
5786:
5787: =item * cacheheader()
5788:
5789: returns cache-controlling header code
5790:
5791: =cut
5792:
1.7 albertel 5793: sub cacheheader {
1.258 albertel 5794: unless ($env{'request.method'} eq 'GET') { return ''; }
1.216 albertel 5795: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
5796: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
1.7 albertel 5797: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
5798: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
1.216 albertel 5799: return $output;
1.7 albertel 5800: }
5801:
1.112 bowersj2 5802: =pod
5803:
5804: =item * no_cache($r)
5805:
5806: specifies header code to not have cache
5807:
5808: =cut
5809:
1.9 albertel 5810: sub no_cache {
1.216 albertel 5811: my ($r) = @_;
5812: if ($ENV{'REQUEST_METHOD'} ne 'GET' &&
1.258 albertel 5813: $env{'request.method'} ne 'GET') { return ''; }
1.216 albertel 5814: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime(time));
5815: $r->no_cache(1);
5816: $r->header_out("Expires" => $date);
5817: $r->header_out("Pragma" => "no-cache");
1.123 www 5818: }
5819:
5820: sub content_type {
1.181 albertel 5821: my ($r,$type,$charset) = @_;
1.299 foxr 5822: if ($r) {
5823: # Note that printout.pl calls this with undef for $r.
5824: &no_cache($r);
5825: }
1.258 albertel 5826: if ($env{'browser.mathml'} && $type eq 'text/html') { $type='text/xml'; }
1.181 albertel 5827: unless ($charset) {
5828: $charset=&Apache::lonlocal::current_encoding;
5829: }
5830: if ($charset) { $type.='; charset='.$charset; }
5831: if ($r) {
5832: $r->content_type($type);
5833: } else {
5834: print("Content-type: $type\n\n");
5835: }
1.9 albertel 5836: }
1.25 albertel 5837:
1.112 bowersj2 5838: =pod
5839:
5840: =item * add_to_env($name,$value)
5841:
1.258 albertel 5842: adds $name to the %env hash with value
1.112 bowersj2 5843: $value, if $name already exists, the entry is converted to an array
5844: reference and $value is added to the array.
5845:
5846: =cut
5847:
1.25 albertel 5848: sub add_to_env {
5849: my ($name,$value)=@_;
1.258 albertel 5850: if (defined($env{$name})) {
5851: if (ref($env{$name})) {
1.25 albertel 5852: #already have multiple values
1.258 albertel 5853: push(@{ $env{$name} },$value);
1.25 albertel 5854: } else {
5855: #first time seeing multiple values, convert hash entry to an arrayref
1.258 albertel 5856: my $first=$env{$name};
5857: undef($env{$name});
5858: push(@{ $env{$name} },$first,$value);
1.25 albertel 5859: }
5860: } else {
1.258 albertel 5861: $env{$name}=$value;
1.25 albertel 5862: }
1.31 albertel 5863: }
1.149 albertel 5864:
5865: =pod
5866:
5867: =item * get_env_multiple($name)
5868:
1.258 albertel 5869: gets $name from the %env hash, it seemlessly handles the cases where multiple
1.149 albertel 5870: values may be defined and end up as an array ref.
5871:
5872: returns an array of values
5873:
5874: =cut
5875:
5876: sub get_env_multiple {
5877: my ($name) = @_;
5878: my @values;
1.258 albertel 5879: if (defined($env{$name})) {
1.149 albertel 5880: # exists is it an array
1.258 albertel 5881: if (ref($env{$name})) {
5882: @values=@{ $env{$name} };
1.149 albertel 5883: } else {
1.258 albertel 5884: $values[0]=$env{$name};
1.149 albertel 5885: }
5886: }
5887: return(@values);
5888: }
5889:
1.31 albertel 5890:
1.41 ng 5891: =pod
1.45 matthew 5892:
1.464 albertel 5893: =back
1.41 ng 5894:
1.112 bowersj2 5895: =head1 CSV Upload/Handling functions
1.38 albertel 5896:
1.41 ng 5897: =over 4
5898:
1.112 bowersj2 5899: =item * upfile_store($r)
1.41 ng 5900:
5901: Store uploaded file, $r should be the HTTP Request object,
1.258 albertel 5902: needs $env{'form.upfile'}
1.41 ng 5903: returns $datatoken to be put into hidden field
5904:
5905: =cut
1.31 albertel 5906:
5907: sub upfile_store {
5908: my $r=shift;
1.258 albertel 5909: $env{'form.upfile'}=~s/\r/\n/gs;
5910: $env{'form.upfile'}=~s/\f/\n/gs;
5911: $env{'form.upfile'}=~s/\n+/\n/gs;
5912: $env{'form.upfile'}=~s/\n+$//gs;
1.31 albertel 5913:
1.258 albertel 5914: my $datatoken=$env{'user.name'}.'_'.$env{'user.domain'}.
5915: '_enroll_'.$env{'request.course.id'}.'_'.time.'_'.$$;
1.31 albertel 5916: {
1.158 raeburn 5917: my $datafile = $r->dir_config('lonDaemons').
5918: '/tmp/'.$datatoken.'.tmp';
5919: if ( open(my $fh,">$datafile") ) {
1.258 albertel 5920: print $fh $env{'form.upfile'};
1.158 raeburn 5921: close($fh);
5922: }
1.31 albertel 5923: }
5924: return $datatoken;
5925: }
5926:
1.56 matthew 5927: =pod
5928:
1.112 bowersj2 5929: =item * load_tmp_file($r)
1.41 ng 5930:
5931: Load uploaded file from tmp, $r should be the HTTP Request object,
1.258 albertel 5932: needs $env{'form.datatoken'},
5933: sets $env{'form.upfile'} to the contents of the file
1.41 ng 5934:
5935: =cut
1.31 albertel 5936:
5937: sub load_tmp_file {
5938: my $r=shift;
5939: my @studentdata=();
5940: {
1.158 raeburn 5941: my $studentfile = $r->dir_config('lonDaemons').
1.258 albertel 5942: '/tmp/'.$env{'form.datatoken'}.'.tmp';
1.158 raeburn 5943: if ( open(my $fh,"<$studentfile") ) {
5944: @studentdata=<$fh>;
5945: close($fh);
5946: }
1.31 albertel 5947: }
1.258 albertel 5948: $env{'form.upfile'}=join('',@studentdata);
1.31 albertel 5949: }
5950:
1.56 matthew 5951: =pod
5952:
1.112 bowersj2 5953: =item * upfile_record_sep()
1.41 ng 5954:
5955: Separate uploaded file into records
5956: returns array of records,
1.258 albertel 5957: needs $env{'form.upfile'} and $env{'form.upfiletype'}
1.41 ng 5958:
5959: =cut
1.31 albertel 5960:
5961: sub upfile_record_sep {
1.258 albertel 5962: if ($env{'form.upfiletype'} eq 'xml') {
1.31 albertel 5963: } else {
1.248 albertel 5964: my @records;
1.258 albertel 5965: foreach my $line (split(/\n/,$env{'form.upfile'})) {
1.248 albertel 5966: if ($line=~/^\s*$/) { next; }
5967: push(@records,$line);
5968: }
5969: return @records;
1.31 albertel 5970: }
5971: }
5972:
1.56 matthew 5973: =pod
5974:
1.112 bowersj2 5975: =item * record_sep($record)
1.41 ng 5976:
1.258 albertel 5977: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $env{'form.upfiletype'}
1.41 ng 5978:
5979: =cut
5980:
1.263 www 5981: sub takeleft {
5982: my $index=shift;
5983: return substr('0000'.$index,-4,4);
5984: }
5985:
1.31 albertel 5986: sub record_sep {
5987: my $record=shift;
5988: my %components=();
1.258 albertel 5989: if ($env{'form.upfiletype'} eq 'xml') {
5990: } elsif ($env{'form.upfiletype'} eq 'space') {
1.31 albertel 5991: my $i=0;
1.356 albertel 5992: foreach my $field (split(/\s+/,$record)) {
1.31 albertel 5993: $field=~s/^(\"|\')//;
5994: $field=~s/(\"|\')$//;
1.263 www 5995: $components{&takeleft($i)}=$field;
1.31 albertel 5996: $i++;
5997: }
1.258 albertel 5998: } elsif ($env{'form.upfiletype'} eq 'tab') {
1.31 albertel 5999: my $i=0;
1.356 albertel 6000: foreach my $field (split(/\t/,$record)) {
1.31 albertel 6001: $field=~s/^(\"|\')//;
6002: $field=~s/(\"|\')$//;
1.263 www 6003: $components{&takeleft($i)}=$field;
1.31 albertel 6004: $i++;
6005: }
6006: } else {
1.480 banghart 6007: my @allfields;
6008: if ($env{'form.upfiletype'} eq 'semisv') {
1.504 albertel 6009: @allfields=split(/;/,$record,-1);
1.480 banghart 6010: } else {
1.504 albertel 6011: @allfields=split(/\,/,$record,-1);
1.480 banghart 6012: }
1.31 albertel 6013: my $i=0;
6014: my $j;
6015: for ($j=0;$j<=$#allfields;$j++) {
6016: my $field=$allfields[$j];
6017: if ($field=~/^\s*(\"|\')/) {
6018: my $delimiter=$1;
6019: while (($field!~/$delimiter$/) && ($j<$#allfields)) {
6020: $j++;
6021: $field.=','.$allfields[$j];
6022: }
6023: $field=~s/^\s*$delimiter//;
6024: $field=~s/$delimiter\s*$//;
6025: }
1.263 www 6026: $components{&takeleft($i)}=$field;
1.31 albertel 6027: $i++;
6028: }
6029: }
6030: return %components;
6031: }
6032:
1.144 matthew 6033: ######################################################
6034: ######################################################
6035:
1.56 matthew 6036: =pod
6037:
1.112 bowersj2 6038: =item * upfile_select_html()
1.41 ng 6039:
1.144 matthew 6040: Return HTML code to select a file from the users machine and specify
6041: the file type.
1.41 ng 6042:
6043: =cut
6044:
1.144 matthew 6045: ######################################################
6046: ######################################################
1.31 albertel 6047: sub upfile_select_html {
1.144 matthew 6048: my %Types = (
6049: csv => &mt('CSV (comma separated values, spreadsheet)'),
1.480 banghart 6050: semisv => &mt('Semicolon separated values'),
1.144 matthew 6051: space => &mt('Space separated'),
6052: tab => &mt('Tabulator separated'),
6053: # xml => &mt('HTML/XML'),
6054: );
6055: my $Str = '<input type="file" name="upfile" size="50" />'.
6056: '<br />Type: <select name="upfiletype">';
6057: foreach my $type (sort(keys(%Types))) {
6058: $Str .= '<option value="'.$type.'" >'.$Types{$type}."</option>\n";
6059: }
6060: $Str .= "</select>\n";
6061: return $Str;
1.31 albertel 6062: }
6063:
1.301 albertel 6064: sub get_samples {
6065: my ($records,$toget) = @_;
6066: my @samples=({});
6067: my $got=0;
6068: foreach my $rec (@$records) {
6069: my %temp = &record_sep($rec);
6070: if (! grep(/\S/, values(%temp))) { next; }
6071: if (%temp) {
6072: $samples[$got]=\%temp;
6073: $got++;
6074: if ($got == $toget) { last; }
6075: }
6076: }
6077: return \@samples;
6078: }
6079:
1.144 matthew 6080: ######################################################
6081: ######################################################
6082:
1.56 matthew 6083: =pod
6084:
1.112 bowersj2 6085: =item * csv_print_samples($r,$records)
1.41 ng 6086:
6087: Prints a table of sample values from each column uploaded $r is an
6088: Apache Request ref, $records is an arrayref from
6089: &Apache::loncommon::upfile_record_sep
6090:
6091: =cut
6092:
1.144 matthew 6093: ######################################################
6094: ######################################################
1.31 albertel 6095: sub csv_print_samples {
6096: my ($r,$records) = @_;
1.301 albertel 6097: my $samples = &get_samples($records,3);
6098:
1.144 matthew 6099: $r->print(&mt('Samples').'<br /><table border="2"><tr>');
1.356 albertel 6100: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
6101: $r->print('<th>'.&mt('Column [_1]',($sample+1)).'</th>'); }
1.31 albertel 6102: $r->print('</tr>');
1.301 albertel 6103: foreach my $hash (@$samples) {
1.31 albertel 6104: $r->print('<tr>');
1.356 albertel 6105: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
1.31 albertel 6106: $r->print('<td>');
1.356 albertel 6107: if (defined($$hash{$sample})) { $r->print($$hash{$sample}); }
1.31 albertel 6108: $r->print('</td>');
6109: }
6110: $r->print('</tr>');
6111: }
6112: $r->print('</tr></table><br />'."\n");
6113: }
6114:
1.144 matthew 6115: ######################################################
6116: ######################################################
6117:
1.56 matthew 6118: =pod
6119:
1.112 bowersj2 6120: =item * csv_print_select_table($r,$records,$d)
1.41 ng 6121:
6122: Prints a table to create associations between values and table columns.
1.144 matthew 6123:
1.41 ng 6124: $r is an Apache Request ref,
6125: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
1.174 matthew 6126: $d is an array of 2 element arrays (internal name, displayed name,defaultcol)
1.41 ng 6127:
6128: =cut
6129:
1.144 matthew 6130: ######################################################
6131: ######################################################
1.31 albertel 6132: sub csv_print_select_table {
6133: my ($r,$records,$d) = @_;
1.301 albertel 6134: my $i=0;
6135: my $samples = &get_samples($records,1);
1.144 matthew 6136: $r->print(&mt('Associate columns with student attributes.')."\n".
6137: '<table border="2"><tr>'.
6138: '<th>'.&mt('Attribute').'</th>'.
6139: '<th>'.&mt('Column').'</th></tr>'."\n");
1.356 albertel 6140: foreach my $array_ref (@$d) {
6141: my ($value,$display,$defaultcol)=@{ $array_ref };
1.31 albertel 6142: $r->print('<tr><td>'.$display.'</td>');
6143:
6144: $r->print('<td><select name=f'.$i.
1.32 matthew 6145: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 6146: $r->print('<option value="none"></option>');
1.356 albertel 6147: foreach my $sample (sort({$a <=> $b} keys(%{ $samples->[0] }))) {
6148: $r->print('<option value="'.$sample.'"'.
6149: ($sample eq $defaultcol ? ' selected="selected" ' : '').
6150: '>Column '.($sample+1).'</option>');
1.31 albertel 6151: }
6152: $r->print('</select></td></tr>'."\n");
6153: $i++;
6154: }
6155: $i--;
6156: return $i;
6157: }
1.56 matthew 6158:
1.144 matthew 6159: ######################################################
6160: ######################################################
6161:
1.56 matthew 6162: =pod
1.31 albertel 6163:
1.112 bowersj2 6164: =item * csv_samples_select_table($r,$records,$d)
1.41 ng 6165:
6166: Prints a table of sample values from the upload and can make associate samples to internal names.
6167:
6168: $r is an Apache Request ref,
6169: $records is an arrayref from &Apache::loncommon::upfile_record_sep,
6170: $d is an array of 2 element arrays (internal name, displayed name)
6171:
6172: =cut
6173:
1.144 matthew 6174: ######################################################
6175: ######################################################
1.31 albertel 6176: sub csv_samples_select_table {
6177: my ($r,$records,$d) = @_;
6178: my $i=0;
1.144 matthew 6179: #
1.301 albertel 6180: my $samples = &get_samples($records,3);
1.144 matthew 6181: $r->print('<table border=2><tr><th>'.
6182: &mt('Field').'</th><th>'.&mt('Samples').'</th></tr>');
1.301 albertel 6183:
6184: foreach my $key (sort(keys(%{ $samples->[0] }))) {
1.144 matthew 6185: $r->print('<tr><td><select name="f'.$i.'"'.
1.32 matthew 6186: ' onchange="javascript:flip(this.form,'.$i.');">');
1.301 albertel 6187: foreach my $option (@$d) {
6188: my ($value,$display,$defaultcol)=@{ $option };
1.174 matthew 6189: $r->print('<option value="'.$value.'"'.
1.253 albertel 6190: ($i eq $defaultcol ? ' selected="selected" ':'').'>'.
1.174 matthew 6191: $display.'</option>');
1.31 albertel 6192: }
6193: $r->print('</select></td><td>');
1.301 albertel 6194: foreach my $line (0..2) {
6195: if (defined($samples->[$line]{$key})) {
6196: $r->print($samples->[$line]{$key}."<br />\n");
6197: }
6198: }
1.31 albertel 6199: $r->print('</td></tr>');
6200: $i++;
6201: }
6202: $i--;
6203: return($i);
1.115 matthew 6204: }
6205:
1.144 matthew 6206: ######################################################
6207: ######################################################
6208:
1.115 matthew 6209: =pod
6210:
6211: =item clean_excel_name($name)
6212:
6213: Returns a replacement for $name which does not contain any illegal characters.
6214:
6215: =cut
6216:
1.144 matthew 6217: ######################################################
6218: ######################################################
1.115 matthew 6219: sub clean_excel_name {
6220: my ($name) = @_;
6221: $name =~ s/[:\*\?\/\\]//g;
6222: if (length($name) > 31) {
6223: $name = substr($name,0,31);
6224: }
6225: return $name;
1.25 albertel 6226: }
1.84 albertel 6227:
1.85 albertel 6228: =pod
6229:
1.112 bowersj2 6230: =item * check_if_partid_hidden($id,$symb,$udom,$uname)
1.85 albertel 6231:
6232: Returns either 1 or undef
6233:
6234: 1 if the part is to be hidden, undef if it is to be shown
6235:
6236: Arguments are:
6237:
6238: $id the id of the part to be checked
6239: $symb, optional the symb of the resource to check
6240: $udom, optional the domain of the user to check for
6241: $uname, optional the username of the user to check for
6242:
6243: =cut
1.84 albertel 6244:
6245: sub check_if_partid_hidden {
6246: my ($id,$symb,$udom,$uname) = @_;
1.133 albertel 6247: my $hiddenparts=&Apache::lonnet::EXT('resource.0.hiddenparts',
1.84 albertel 6248: $symb,$udom,$uname);
1.141 albertel 6249: my $truth=1;
6250: #if the string starts with !, then the list is the list to show not hide
6251: if ($hiddenparts=~s/^\s*!//) { $truth=undef; }
1.84 albertel 6252: my @hiddenlist=split(/,/,$hiddenparts);
6253: foreach my $checkid (@hiddenlist) {
1.141 albertel 6254: if ($checkid =~ /^\s*\Q$id\E\s*$/) { return $truth; }
1.84 albertel 6255: }
1.141 albertel 6256: return !$truth;
1.84 albertel 6257: }
1.127 matthew 6258:
1.138 matthew 6259:
6260: ############################################################
6261: ############################################################
6262:
6263: =pod
6264:
1.157 matthew 6265: =back
6266:
1.138 matthew 6267: =head1 cgi-bin script and graphing routines
6268:
1.157 matthew 6269: =over 4
6270:
1.138 matthew 6271: =item get_cgi_id
6272:
6273: Inputs: none
6274:
6275: Returns an id which can be used to pass environment variables
6276: to various cgi-bin scripts. These environment variables will
6277: be removed from the users environment after a given time by
6278: the routine &Apache::lonnet::transfer_profile_to_env.
6279:
6280: =cut
6281:
6282: ############################################################
6283: ############################################################
1.152 albertel 6284: my $uniq=0;
1.136 matthew 6285: sub get_cgi_id {
1.154 albertel 6286: $uniq=($uniq+1)%100000;
1.280 albertel 6287: return (time.'_'.$$.'_'.$uniq);
1.136 matthew 6288: }
6289:
1.127 matthew 6290: ############################################################
6291: ############################################################
6292:
6293: =pod
6294:
1.134 matthew 6295: =item DrawBarGraph
1.127 matthew 6296:
1.138 matthew 6297: Facilitates the plotting of data in a (stacked) bar graph.
6298: Puts plot definition data into the users environment in order for
6299: graph.png to plot it. Returns an <img> tag for the plot.
6300: The bars on the plot are labeled '1','2',...,'n'.
6301:
6302: Inputs:
6303:
6304: =over 4
6305:
6306: =item $Title: string, the title of the plot
6307:
6308: =item $xlabel: string, text describing the X-axis of the plot
6309:
6310: =item $ylabel: string, text describing the Y-axis of the plot
6311:
6312: =item $Max: scalar, the maximum Y value to use in the plot
6313: If $Max is < any data point, the graph will not be rendered.
6314:
1.140 matthew 6315: =item $colors: array ref holding the colors to be used for the data sets when
1.138 matthew 6316: they are plotted. If undefined, default values will be used.
6317:
1.178 matthew 6318: =item $labels: array ref holding the labels to use on the x-axis for the bars.
6319:
1.138 matthew 6320: =item @Values: An array of array references. Each array reference holds data
6321: to be plotted in a stacked bar chart.
6322:
1.239 matthew 6323: =item If the final element of @Values is a hash reference the key/value
6324: pairs will be added to the graph definition.
6325:
1.138 matthew 6326: =back
6327:
6328: Returns:
6329:
6330: An <img> tag which references graph.png and the appropriate identifying
6331: information for the plot.
6332:
1.127 matthew 6333: =cut
6334:
6335: ############################################################
6336: ############################################################
1.134 matthew 6337: sub DrawBarGraph {
1.178 matthew 6338: my ($Title,$xlabel,$ylabel,$Max,$colors,$labels,@Values)=@_;
1.134 matthew 6339: #
6340: if (! defined($colors)) {
6341: $colors = ['#33ff00',
6342: '#0033cc', '#990000', '#aaaa66', '#663399', '#ff9933',
6343: '#66ccff', '#ff9999', '#cccc33', '#660000', '#33cc66',
6344: ];
6345: }
1.228 matthew 6346: my $extra_settings = {};
6347: if (ref($Values[-1]) eq 'HASH') {
6348: $extra_settings = pop(@Values);
6349: }
1.127 matthew 6350: #
1.136 matthew 6351: my $identifier = &get_cgi_id();
6352: my $id = 'cgi.'.$identifier;
1.129 matthew 6353: if (! @Values || ref($Values[0]) ne 'ARRAY') {
1.127 matthew 6354: return '';
6355: }
1.225 matthew 6356: #
6357: my @Labels;
6358: if (defined($labels)) {
6359: @Labels = @$labels;
6360: } else {
6361: for (my $i=0;$i<@{$Values[0]};$i++) {
6362: push (@Labels,$i+1);
6363: }
6364: }
6365: #
1.129 matthew 6366: my $NumBars = scalar(@{$Values[0]});
1.225 matthew 6367: if ($NumBars < scalar(@Labels)) { $NumBars = scalar(@Labels); }
1.129 matthew 6368: my %ValuesHash;
6369: my $NumSets=1;
6370: foreach my $array (@Values) {
6371: next if (! ref($array));
1.136 matthew 6372: $ValuesHash{$id.'.data.'.$NumSets++} =
1.132 matthew 6373: join(',',@$array);
1.129 matthew 6374: }
1.127 matthew 6375: #
1.136 matthew 6376: my ($height,$width,$xskip,$bar_width) = (200,120,1,15);
1.225 matthew 6377: if ($NumBars < 3) {
6378: $width = 120+$NumBars*32;
1.220 matthew 6379: $xskip = 1;
1.225 matthew 6380: $bar_width = 30;
6381: } elsif ($NumBars < 5) {
6382: $width = 120+$NumBars*20;
6383: $xskip = 1;
6384: $bar_width = 20;
1.220 matthew 6385: } elsif ($NumBars < 10) {
1.136 matthew 6386: $width = 120+$NumBars*15;
6387: $xskip = 1;
6388: $bar_width = 15;
6389: } elsif ($NumBars <= 25) {
6390: $width = 120+$NumBars*11;
6391: $xskip = 5;
6392: $bar_width = 8;
6393: } elsif ($NumBars <= 50) {
6394: $width = 120+$NumBars*8;
6395: $xskip = 5;
6396: $bar_width = 4;
6397: } else {
6398: $width = 120+$NumBars*8;
6399: $xskip = 5;
6400: $bar_width = 4;
6401: }
6402: #
1.137 matthew 6403: $Max = 1 if ($Max < 1);
6404: if ( int($Max) < $Max ) {
6405: $Max++;
6406: $Max = int($Max);
6407: }
1.127 matthew 6408: $Title = '' if (! defined($Title));
6409: $xlabel = '' if (! defined($xlabel));
6410: $ylabel = '' if (! defined($ylabel));
1.369 www 6411: $ValuesHash{$id.'.title'} = &escape($Title);
6412: $ValuesHash{$id.'.xlabel'} = &escape($xlabel);
6413: $ValuesHash{$id.'.ylabel'} = &escape($ylabel);
1.137 matthew 6414: $ValuesHash{$id.'.y_max_value'} = $Max;
1.136 matthew 6415: $ValuesHash{$id.'.NumBars'} = $NumBars;
6416: $ValuesHash{$id.'.NumSets'} = $NumSets;
6417: $ValuesHash{$id.'.PlotType'} = 'bar';
6418: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
6419: $ValuesHash{$id.'.height'} = $height;
6420: $ValuesHash{$id.'.width'} = $width;
6421: $ValuesHash{$id.'.xskip'} = $xskip;
6422: $ValuesHash{$id.'.bar_width'} = $bar_width;
6423: $ValuesHash{$id.'.labels'} = join(',',@Labels);
1.127 matthew 6424: #
1.228 matthew 6425: # Deal with other parameters
6426: while (my ($key,$value) = each(%$extra_settings)) {
6427: $ValuesHash{$id.'.'.$key} = $value;
6428: }
6429: #
1.137 matthew 6430: &Apache::lonnet::appenv(%ValuesHash);
6431: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
6432: }
6433:
6434: ############################################################
6435: ############################################################
6436:
6437: =pod
6438:
6439: =item DrawXYGraph
6440:
1.138 matthew 6441: Facilitates the plotting of data in an XY graph.
6442: Puts plot definition data into the users environment in order for
6443: graph.png to plot it. Returns an <img> tag for the plot.
6444:
6445: Inputs:
6446:
6447: =over 4
6448:
6449: =item $Title: string, the title of the plot
6450:
6451: =item $xlabel: string, text describing the X-axis of the plot
6452:
6453: =item $ylabel: string, text describing the Y-axis of the plot
6454:
6455: =item $Max: scalar, the maximum Y value to use in the plot
6456: If $Max is < any data point, the graph will not be rendered.
6457:
6458: =item $colors: Array ref containing the hex color codes for the data to be
6459: plotted in. If undefined, default values will be used.
6460:
6461: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
6462:
6463: =item $Ydata: Array ref containing Array refs.
1.185 www 6464: Each of the contained arrays will be plotted as a separate curve.
1.138 matthew 6465:
6466: =item %Values: hash indicating or overriding any default values which are
6467: passed to graph.png.
6468: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
6469:
6470: =back
6471:
6472: Returns:
6473:
6474: An <img> tag which references graph.png and the appropriate identifying
6475: information for the plot.
6476:
1.137 matthew 6477: =cut
6478:
6479: ############################################################
6480: ############################################################
6481: sub DrawXYGraph {
6482: my ($Title,$xlabel,$ylabel,$Max,$colors,$Xlabels,$Ydata,%Values)=@_;
6483: #
6484: # Create the identifier for the graph
6485: my $identifier = &get_cgi_id();
6486: my $id = 'cgi.'.$identifier;
6487: #
6488: $Title = '' if (! defined($Title));
6489: $xlabel = '' if (! defined($xlabel));
6490: $ylabel = '' if (! defined($ylabel));
6491: my %ValuesHash =
6492: (
1.369 www 6493: $id.'.title' => &escape($Title),
6494: $id.'.xlabel' => &escape($xlabel),
6495: $id.'.ylabel' => &escape($ylabel),
1.137 matthew 6496: $id.'.y_max_value'=> $Max,
6497: $id.'.labels' => join(',',@$Xlabels),
6498: $id.'.PlotType' => 'XY',
6499: );
6500: #
6501: if (defined($colors) && ref($colors) eq 'ARRAY') {
6502: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
6503: }
6504: #
6505: if (! ref($Ydata) || ref($Ydata) ne 'ARRAY') {
6506: return '';
6507: }
6508: my $NumSets=1;
1.138 matthew 6509: foreach my $array (@{$Ydata}){
1.137 matthew 6510: next if (! ref($array));
6511: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
6512: }
1.138 matthew 6513: $ValuesHash{$id.'.NumSets'} = $NumSets-1;
1.137 matthew 6514: #
6515: # Deal with other parameters
6516: while (my ($key,$value) = each(%Values)) {
6517: $ValuesHash{$id.'.'.$key} = $value;
1.127 matthew 6518: }
6519: #
1.136 matthew 6520: &Apache::lonnet::appenv(%ValuesHash);
6521: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
6522: }
6523:
6524: ############################################################
6525: ############################################################
6526:
6527: =pod
6528:
1.138 matthew 6529: =item DrawXYYGraph
6530:
6531: Facilitates the plotting of data in an XY graph with two Y axes.
6532: Puts plot definition data into the users environment in order for
6533: graph.png to plot it. Returns an <img> tag for the plot.
6534:
6535: Inputs:
6536:
6537: =over 4
6538:
6539: =item $Title: string, the title of the plot
6540:
6541: =item $xlabel: string, text describing the X-axis of the plot
6542:
6543: =item $ylabel: string, text describing the Y-axis of the plot
6544:
6545: =item $colors: Array ref containing the hex color codes for the data to be
6546: plotted in. If undefined, default values will be used.
6547:
6548: =item $Xlabels: Array ref containing the labels to be used for the X-axis.
6549:
6550: =item $Ydata1: The first data set
6551:
6552: =item $Min1: The minimum value of the left Y-axis
6553:
6554: =item $Max1: The maximum value of the left Y-axis
6555:
6556: =item $Ydata2: The second data set
6557:
6558: =item $Min2: The minimum value of the right Y-axis
6559:
6560: =item $Max2: The maximum value of the left Y-axis
6561:
6562: =item %Values: hash indicating or overriding any default values which are
6563: passed to graph.png.
6564: Possible values are: width, xskip, x_ticks, x_tick_offset, among others.
6565:
6566: =back
6567:
6568: Returns:
6569:
6570: An <img> tag which references graph.png and the appropriate identifying
6571: information for the plot.
1.136 matthew 6572:
6573: =cut
6574:
6575: ############################################################
6576: ############################################################
1.137 matthew 6577: sub DrawXYYGraph {
6578: my ($Title,$xlabel,$ylabel,$colors,$Xlabels,$Ydata1,$Min1,$Max1,
6579: $Ydata2,$Min2,$Max2,%Values)=@_;
1.136 matthew 6580: #
6581: # Create the identifier for the graph
6582: my $identifier = &get_cgi_id();
6583: my $id = 'cgi.'.$identifier;
6584: #
6585: $Title = '' if (! defined($Title));
6586: $xlabel = '' if (! defined($xlabel));
6587: $ylabel = '' if (! defined($ylabel));
6588: my %ValuesHash =
6589: (
1.369 www 6590: $id.'.title' => &escape($Title),
6591: $id.'.xlabel' => &escape($xlabel),
6592: $id.'.ylabel' => &escape($ylabel),
1.136 matthew 6593: $id.'.labels' => join(',',@$Xlabels),
6594: $id.'.PlotType' => 'XY',
6595: $id.'.NumSets' => 2,
1.137 matthew 6596: $id.'.two_axes' => 1,
6597: $id.'.y1_max_value' => $Max1,
6598: $id.'.y1_min_value' => $Min1,
6599: $id.'.y2_max_value' => $Max2,
6600: $id.'.y2_min_value' => $Min2,
1.136 matthew 6601: );
6602: #
1.137 matthew 6603: if (defined($colors) && ref($colors) eq 'ARRAY') {
6604: $ValuesHash{$id.'.Colors'} = join(',',@{$colors});
6605: }
6606: #
6607: if (! ref($Ydata1) || ref($Ydata1) ne 'ARRAY' ||
6608: ! ref($Ydata2) || ref($Ydata2) ne 'ARRAY'){
1.136 matthew 6609: return '';
6610: }
6611: my $NumSets=1;
1.137 matthew 6612: foreach my $array ($Ydata1,$Ydata2){
1.136 matthew 6613: next if (! ref($array));
6614: $ValuesHash{$id.'.data.'.$NumSets++} = join(',',@$array);
1.137 matthew 6615: }
6616: #
6617: # Deal with other parameters
6618: while (my ($key,$value) = each(%Values)) {
6619: $ValuesHash{$id.'.'.$key} = $value;
1.136 matthew 6620: }
6621: #
6622: &Apache::lonnet::appenv(%ValuesHash);
1.130 albertel 6623: return '<img src="/cgi-bin/graph.png?'.$identifier.'" border="1" />';
1.139 matthew 6624: }
6625:
6626: ############################################################
6627: ############################################################
6628:
6629: =pod
6630:
1.157 matthew 6631: =back
6632:
1.139 matthew 6633: =head1 Statistics helper routines?
6634:
6635: Bad place for them but what the hell.
6636:
1.157 matthew 6637: =over 4
6638:
1.139 matthew 6639: =item &chartlink
6640:
6641: Returns a link to the chart for a specific student.
6642:
6643: Inputs:
6644:
6645: =over 4
6646:
6647: =item $linktext: The text of the link
6648:
6649: =item $sname: The students username
6650:
6651: =item $sdomain: The students domain
6652:
6653: =back
6654:
1.157 matthew 6655: =back
6656:
1.139 matthew 6657: =cut
6658:
6659: ############################################################
6660: ############################################################
6661: sub chartlink {
6662: my ($linktext, $sname, $sdomain) = @_;
6663: my $link = '<a href="/adm/statistics?reportSelected=student_assessment'.
1.369 www 6664: '&SelectedStudent='.&escape($sname.':'.$sdomain).
1.219 albertel 6665: '&chartoutputmode='.HTML::Entities::encode('html, with all links').
1.139 matthew 6666: '">'.$linktext.'</a>';
1.153 matthew 6667: }
6668:
6669: #######################################################
6670: #######################################################
6671:
6672: =pod
6673:
6674: =head1 Course Environment Routines
1.157 matthew 6675:
6676: =over 4
1.153 matthew 6677:
6678: =item &restore_course_settings
6679:
6680: =item &store_course_settings
6681:
6682: Restores/Store indicated form parameters from the course environment.
6683: Will not overwrite existing values of the form parameters.
6684:
6685: Inputs:
6686: a scalar describing the data (e.g. 'chart', 'problem_analysis')
6687:
6688: a hash ref describing the data to be stored. For example:
6689:
6690: %Save_Parameters = ('Status' => 'scalar',
6691: 'chartoutputmode' => 'scalar',
6692: 'chartoutputdata' => 'scalar',
6693: 'Section' => 'array',
1.373 raeburn 6694: 'Group' => 'array',
1.153 matthew 6695: 'StudentData' => 'array',
6696: 'Maps' => 'array');
6697:
6698: Returns: both routines return nothing
6699:
6700: =cut
6701:
6702: #######################################################
6703: #######################################################
6704: sub store_course_settings {
1.496 albertel 6705: return &store_settings($env{'request.course.id'},@_);
6706: }
6707:
6708: sub store_settings {
1.153 matthew 6709: # save to the environment
6710: # appenv the same items, just to be safe
1.300 albertel 6711: my $udom = $env{'user.domain'};
6712: my $uname = $env{'user.name'};
1.496 albertel 6713: my ($context,$prefix,$Settings) = @_;
1.153 matthew 6714: my %SaveHash;
6715: my %AppHash;
6716: while (my ($setting,$type) = each(%$Settings)) {
1.496 albertel 6717: my $basename = join('.','internal',$context,$prefix,$setting);
1.300 albertel 6718: my $envname = 'environment.'.$basename;
1.258 albertel 6719: if (exists($env{'form.'.$setting})) {
1.153 matthew 6720: # Save this value away
6721: if ($type eq 'scalar' &&
1.258 albertel 6722: (! exists($env{$envname}) ||
6723: $env{$envname} ne $env{'form.'.$setting})) {
6724: $SaveHash{$basename} = $env{'form.'.$setting};
6725: $AppHash{$envname} = $env{'form.'.$setting};
1.153 matthew 6726: } elsif ($type eq 'array') {
6727: my $stored_form;
1.258 albertel 6728: if (ref($env{'form.'.$setting})) {
1.153 matthew 6729: $stored_form = join(',',
6730: map {
1.369 www 6731: &escape($_);
1.258 albertel 6732: } sort(@{$env{'form.'.$setting}}));
1.153 matthew 6733: } else {
6734: $stored_form =
1.369 www 6735: &escape($env{'form.'.$setting});
1.153 matthew 6736: }
6737: # Determine if the array contents are the same.
1.258 albertel 6738: if ($stored_form ne $env{$envname}) {
1.153 matthew 6739: $SaveHash{$basename} = $stored_form;
6740: $AppHash{$envname} = $stored_form;
6741: }
6742: }
6743: }
6744: }
6745: my $put_result = &Apache::lonnet::put('environment',\%SaveHash,
1.300 albertel 6746: $udom,$uname);
1.153 matthew 6747: if ($put_result !~ /^(ok|delayed)/) {
6748: &Apache::lonnet::logthis('unable to save form parameters, '.
6749: 'got error:'.$put_result);
6750: }
6751: # Make sure these settings stick around in this session, too
6752: &Apache::lonnet::appenv(%AppHash);
6753: return;
6754: }
6755:
6756: sub restore_course_settings {
1.499 albertel 6757: return &restore_settings($env{'request.course.id'},@_);
1.496 albertel 6758: }
6759:
6760: sub restore_settings {
6761: my ($context,$prefix,$Settings) = @_;
1.153 matthew 6762: while (my ($setting,$type) = each(%$Settings)) {
1.258 albertel 6763: next if (exists($env{'form.'.$setting}));
1.496 albertel 6764: my $envname = 'environment.internal.'.$context.'.'.$prefix.
1.153 matthew 6765: '.'.$setting;
1.258 albertel 6766: if (exists($env{$envname})) {
1.153 matthew 6767: if ($type eq 'scalar') {
1.258 albertel 6768: $env{'form.'.$setting} = $env{$envname};
1.153 matthew 6769: } elsif ($type eq 'array') {
1.258 albertel 6770: $env{'form.'.$setting} = [
1.153 matthew 6771: map {
1.369 www 6772: &unescape($_);
1.258 albertel 6773: } split(',',$env{$envname})
1.153 matthew 6774: ];
6775: }
6776: }
6777: }
1.127 matthew 6778: }
6779:
6780: ############################################################
6781: ############################################################
1.154 albertel 6782:
1.443 albertel 6783: sub commit_customrole {
6784: my ($udom,$uname,$url,$three,$four,$five,$start,$end) = @_;
6785: my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.'@'.$three.' in '.$url.
6786: ($start?', '.&mt('starting').' '.localtime($start):'').
6787: ($end?', ending '.localtime($end):'').': <b>'.
6788: &Apache::lonnet::assigncustomrole(
6789: $udom,$uname,$url,$three,$four,$five,$end,$start).
6790: '</b><br />';
6791: return $output;
6792: }
6793:
6794: sub commit_standardrole {
1.541 raeburn 6795: my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
6796: my ($output,$logmsg,$linefeed);
6797: if ($context eq 'auto') {
6798: $linefeed = "\n";
6799: } else {
6800: $linefeed = "<br />\n";
6801: }
1.443 albertel 6802: if ($three eq 'st') {
1.541 raeburn 6803: my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
6804: $one,$two,$sec,$context);
6805: if (($result =~ /^error/) || ($result eq 'not_in_class') ||
6806: ($result eq 'unknown_course')) {
1.443 albertel 6807: $output = "Error: $result\n";
6808: } else {
1.541 raeburn 6809: $output = $logmsg.$linefeed.&mt('Assigning').' '.$three.' in '.$url.
1.443 albertel 6810: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 6811: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
6812: if ($context eq 'auto') {
6813: $output .= $result.$linefeed.&mt('Add to classlist').': ok';
6814: } else {
6815: $output .= '<b>'.$result.'</b>'.$linefeed.
6816: &mt('Add to classlist').': <b>ok</b>';
6817: }
6818: $output .= $linefeed;
1.443 albertel 6819: }
6820: } else {
6821: $output = &mt('Assigning').' '.$three.' in '.$url.
6822: ($start?', '.&mt('starting').' '.localtime($start):'').
1.541 raeburn 6823: ($end?', '.&mt('ending').' '.localtime($end):'').': ';
6824: my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start);
6825: if ($context eq 'auto') {
6826: $output .= $result.$linefeed;
6827: } else {
6828: $output .= '<b>'.$result.'</b>'.$linefeed;
6829: }
1.443 albertel 6830: }
6831: return $output;
6832: }
6833:
6834: sub commit_studentrole {
1.541 raeburn 6835: my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context) = @_;
6836: my ($result,$linefeed);
6837: if ($context eq 'auto') {
6838: $linefeed = "\n";
6839: } else {
6840: $linefeed = '<br />'."\n";
6841: }
1.443 albertel 6842: if (defined($one) && defined($two)) {
6843: my $cid=$one.'_'.$two;
6844: my $oldsec=&Apache::lonnet::getsection($udom,$uname,$cid);
6845: my $secchange = 0;
6846: my $expire_role_result;
6847: my $modify_section_result;
6848: unless ($oldsec eq '-1') {
6849: unless ($sec eq $oldsec) {
6850: $secchange = 1;
6851: my $uurl='/'.$cid;
6852: $uurl=~s/\_/\//g;
6853: if ($oldsec) {
6854: $uurl.='/'.$oldsec;
6855: }
6856: $expire_role_result = &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',time);
6857: $result = $expire_role_result;
6858: }
6859: }
6860: if (($expire_role_result eq 'ok') || ($secchange == 0)) {
6861: $modify_section_result = &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,undef,undef,undef,$sec,$end,$start,'','',$cid);
6862: if ($modify_section_result =~ /^ok/) {
6863: if ($secchange == 1) {
6864: $$logmsg .= "Section for $uname switched from old section: $oldsec to new section: $sec".$linefeed;
6865: } elsif ($oldsec eq '-1') {
6866: $$logmsg .= "New student role for $uname in section $sec in course $cid".$linefeed;
6867: } else {
6868: $$logmsg .= "Student $uname assigned to unchanged section $sec in course $cid".$linefeed;
6869: }
6870: } else {
6871: $$logmsg .= "Error when attempting section change for $uname from old section $oldsec to new section: $sec in course $cid -error: $modify_section_result".$linefeed;
6872: }
6873: $result = $modify_section_result;
6874: } elsif ($secchange == 1) {
6875: $$logmsg .= "Error when attempting to expire role for $uname in old section $oldsec in course $cid -error: $expire_role_result".$linefeed;
6876: }
6877: } else {
6878: $$logmsg .= "Incomplete course id defined. Addition of user $uname from domain $udom to course $one\_$two, section $sec not completed.$linefeed";
6879: $result = "error: incomplete course id\n";
6880: }
6881: return $result;
6882: }
6883:
6884: ############################################################
6885: ############################################################
6886:
1.444 albertel 6887: sub construct_course {
1.541 raeburn 6888: my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context) = @_;
1.444 albertel 6889: my $outcome;
1.541 raeburn 6890: my $linefeed = '<br />'."\n";
6891: if ($context eq 'auto') {
6892: $linefeed = "\n";
6893: }
1.444 albertel 6894: #
6895: # Open course
6896: #
6897: my $crstype = lc($args->{'crstype'});
6898: my %cenv=();
6899: $$courseid=&Apache::lonnet::createcourse($args->{'course_domain'},
6900: $args->{'cdescr'},
6901: $args->{'curl'},
6902: $args->{'course_home'},
6903: $args->{'nonstandard'},
6904: $args->{'crscode'},
6905: $args->{'ccuname'}.':'.
6906: $args->{'ccdomain'},
6907: $args->{'crstype'});
6908:
6909: # Note: The testing routines depend on this being output; see
6910: # Utils::Course. This needs to at least be output as a comment
6911: # if anyone ever decides to not show this, and Utils::Course::new
6912: # will need to be suitably modified.
1.541 raeburn 6913: $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed;
6914:
1.444 albertel 6915: #
6916: # Check if created correctly
6917: #
1.479 albertel 6918: ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
1.444 albertel 6919: my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
1.541 raeburn 6920: $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
1.444 albertel 6921: #
6922: # Are we cloning?
6923: #
6924: my $cloneid='';
6925: if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
1.541 raeburn 6926: my $can_clone = 0;
1.444 albertel 6927: $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
1.479 albertel 6928: my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
1.444 albertel 6929: my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
1.541 raeburn 6930: my $clonemsg;
1.444 albertel 6931: if ($clonehome eq 'no_host') {
1.541 raeburn 6932: $clonemsg = &mt('Attempting to clone non-existing [_1]',$crstype);
6933: if ($context eq 'auto') {
6934: $outcome .= $clonemsg;
6935: } else {
6936: $outcome .= '<font color="red">'.$clonemsg.'</font>';
6937: }
6938: $outcome .= $linefeed;
1.444 albertel 6939: } else {
1.541 raeburn 6940: my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
6941: if ($env{'request.role.domain'} eq $args->{'form.clonedomain'}) {
6942: $can_clone = 1;
6943: } else {
6944: my %clonehash = &Apache::lonnet::get('environment',['cloners'],
6945: $args->{'clonedomain'},$args->{'clonecourse'});
6946: my @cloners = split(/,/,$clonehash{'cloners'});
6947: my %roleshash =
6948: &Apache::lonnet::get_my_roles($args->{'ccuname'},
6949: $args->{'ccdomain'},'userroles',['active'],['cc'],
6950: [$args->{'clonedomain'}]);
6951: if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':cc'}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) {
6952: $can_clone = 1;
6953: } else {
6954: $clonemsg = &mt('The new course was not cloned from an existing course because the course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
6955: if ($context eq 'auto') {
6956: $outcome .= $clonemsg;
6957: } else {
6958: $outcome .= '<font color="red">'.$clonemsg.'</font>';
6959: }
6960: $outcome .= $linefeed;
6961: }
6962: }
6963: }
6964: if ($can_clone) {
6965: $clonemsg = &mt('Cloning [_1] from [_2]',$crstype,$clonehome);
6966: if ($context eq 'auto') {
6967: $outcome = $clonemsg;
6968: } else {
6969: $outcome .= '<font color="green">'.$clonemsg.'</font>';
6970: }
6971: $outcome .= $linefeed;
1.444 albertel 6972: my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
6973: # Copy all files
6974: &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid);
6975: # Restore URL
6976: $cenv{'url'}=$oldcenv{'url'};
6977: # Restore title
6978: $cenv{'description'}=$oldcenv{'description'};
6979: # restore grading mode
6980: if (defined($oldcenv{'grading'})) {
6981: $cenv{'grading'}=$oldcenv{'grading'};
6982: }
6983: # Mark as cloned
6984: $cenv{'clonedfrom'}=$cloneid;
6985: delete($cenv{'default_enrollment_start_date'});
6986: delete($cenv{'default_enrollment_end_date'});
6987: }
6988: }
6989: #
6990: # Set environment (will override cloned, if existing)
6991: #
6992: my @sections = ();
6993: my @xlists = ();
6994: if ($args->{'crstype'}) {
6995: $cenv{'type'}=$args->{'crstype'};
6996: }
6997: if ($args->{'crsid'}) {
6998: $cenv{'courseid'}=$args->{'crsid'};
6999: }
7000: if ($args->{'crscode'}) {
7001: $cenv{'internal.coursecode'}=$args->{'crscode'};
7002: }
7003: if ($args->{'crsquota'} ne '') {
7004: $cenv{'internal.coursequota'}=$args->{'crsquota'};
7005: } else {
7006: $cenv{'internal.coursequota'}=$args->{'crsquota'} = 20;
7007: }
7008: if ($args->{'ccuname'}) {
7009: $cenv{'internal.courseowner'} = $args->{'ccuname'}.
7010: ':'.$args->{'ccdomain'};
7011: } else {
7012: $cenv{'internal.courseowner'} = $args->{'curruser'};
7013: }
7014:
7015: my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
7016: if ($args->{'crssections'}) {
7017: $cenv{'internal.sectionnums'} = '';
7018: if ($args->{'crssections'} =~ m/,/) {
7019: @sections = split/,/,$args->{'crssections'};
7020: } else {
7021: $sections[0] = $args->{'crssections'};
7022: }
7023: if (@sections > 0) {
7024: foreach my $item (@sections) {
7025: my ($sec,$gp) = split/:/,$item;
7026: my $class = $args->{'crscode'}.$sec;
7027: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
7028: $cenv{'internal.sectionnums'} .= $item.',';
7029: unless ($addcheck eq 'ok') {
7030: push @badclasses, $class;
7031: }
7032: }
7033: $cenv{'internal.sectionnums'} =~ s/,$//;
7034: }
7035: }
7036: # do not hide course coordinator from staff listing,
7037: # even if privileged
7038: $cenv{'nothideprivileged'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
7039: # add crosslistings
7040: if ($args->{'crsxlist'}) {
7041: $cenv{'internal.crosslistings'}='';
7042: if ($args->{'crsxlist'} =~ m/,/) {
7043: @xlists = split/,/,$args->{'crsxlist'};
7044: } else {
7045: $xlists[0] = $args->{'crsxlist'};
7046: }
7047: if (@xlists > 0) {
7048: foreach my $item (@xlists) {
7049: my ($xl,$gp) = split/:/,$item;
7050: my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
7051: $cenv{'internal.crosslistings'} .= $item.',';
7052: unless ($addcheck eq 'ok') {
7053: push @badclasses, $xl;
7054: }
7055: }
7056: $cenv{'internal.crosslistings'} =~ s/,$//;
7057: }
7058: }
7059: if ($args->{'autoadds'}) {
7060: $cenv{'internal.autoadds'}=$args->{'autoadds'};
7061: }
7062: if ($args->{'autodrops'}) {
7063: $cenv{'internal.autodrops'}=$args->{'autodrops'};
7064: }
7065: # check for notification of enrollment changes
7066: my @notified = ();
7067: if ($args->{'notify_owner'}) {
7068: if ($args->{'ccuname'} ne '') {
7069: push(@notified,$args->{'ccuname'}.':'.$args->{'ccdomain'});
7070: }
7071: }
7072: if ($args->{'notify_dc'}) {
7073: if ($uname ne '') {
7074: push(@notified,$uname.'@'.$udom);
7075: }
7076: }
7077: if (@notified > 0) {
7078: my $notifylist;
7079: if (@notified > 1) {
7080: $notifylist = join(',',@notified);
7081: } else {
7082: $notifylist = $notified[0];
7083: }
7084: $cenv{'internal.notifylist'} = $notifylist;
7085: }
7086: if (@badclasses > 0) {
7087: my %lt=&Apache::lonlocal::texthash(
7088: 'tclb' => 'The courses listed below were included as sections or crosslistings affiliated with your new LON-CAPA course. However, if automated course roster updates are enabled for this class, these particular sections/crosslistings will not contribute towards enrollment, because the user identified as the course owner for this LON-CAPA course',
7089: 'dnhr' => 'does not have rights to access enrollment in these classes',
7090: 'adby' => 'as determined by the policies of your institution on access to official classlists'
7091: );
1.541 raeburn 7092: my $badclass_msg = $cenv{'internal.courseowner'}.') - '.$lt{'dnhr'}.
7093: ' ('.$lt{'adby'}.')';
7094: if ($context eq 'auto') {
7095: $outcome .= $badclass_msg.$linefeed;
7096: $outcome .= '<font color="red">'.$badclass_msg.$linefeed.'<ul>'."\n";
7097: foreach my $item (@badclasses) {
7098: if ($context eq 'auto') {
7099: $outcome .= " - $item\n";
7100: } else {
7101: $outcome .= "<li>$item</li>\n";
7102: }
7103: }
7104: if ($context eq 'auto') {
7105: $outcome .= $linefeed;
7106: } else {
7107: $outcome .= "</ul><br /><br /></font>\n";
7108: }
7109: }
1.444 albertel 7110: }
7111: if ($args->{'no_end_date'}) {
7112: $args->{'endaccess'} = 0;
7113: }
7114: $cenv{'internal.autostart'}=$args->{'enrollstart'};
7115: $cenv{'internal.autoend'}=$args->{'enrollend'};
7116: $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
7117: $cenv{'default_enrollment_end_date'}=$args->{'endaccess'};
7118: if ($args->{'showphotos'}) {
7119: $cenv{'internal.showphotos'}=$args->{'showphotos'};
7120: }
7121: $cenv{'internal.authtype'} = $args->{'authtype'};
7122: $cenv{'internal.autharg'} = $args->{'autharg'};
7123: if ( ($cenv{'internal.authtype'} =~ /^krb/) && ($cenv{'internal.autoadds'} == 1)) {
7124: if (! defined($cenv{'internal.autharg'}) || $cenv{'internal.autharg'} eq '') {
1.541 raeburn 7125: my $krb_msg = &mt('As you did not include the default Kerberos domain to be used for authentication in this class, the institutional data used by the automated enrollment process must include the Kerberos domain for each new student');
7126: if ($context eq 'auto') {
7127: $outcome .= $krb_msg;
7128: } else {
7129: $outcome .= '<font color="red" size="+1">'.$krb_msg.'</font>';
7130: }
7131: $outcome .= $linefeed;
1.444 albertel 7132: }
7133: }
7134: if (($args->{'ccdomain'}) && ($args->{'ccuname'})) {
7135: if ($args->{'setpolicy'}) {
7136: $cenv{'policy.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
7137: }
7138: if ($args->{'setcontent'}) {
7139: $cenv{'question.email'}=$args->{'ccuname'}.':'.$args->{'ccdomain'};
7140: }
7141: }
7142: if ($args->{'reshome'}) {
7143: $cenv{'reshome'}=$args->{'reshome'}.'/';
7144: $cenv{'reshome'}=~s/\/+$/\//;
7145: }
7146: #
7147: # course has keyed access
7148: #
7149: if ($args->{'setkeys'}) {
7150: $cenv{'keyaccess'}='yes';
7151: }
7152: # if specified, key authority is not course, but user
7153: # only active if keyaccess is yes
7154: if ($args->{'keyauth'}) {
1.487 albertel 7155: my ($user,$domain) = split(':',$args->{'keyauth'});
7156: $user = &LONCAPA::clean_username($user);
7157: $domain = &LONCAPA::clean_username($domain);
1.488 foxr 7158: if ($user ne '' && $domain ne '') {
1.487 albertel 7159: $cenv{'keyauth'}=$user.':'.$domain;
1.444 albertel 7160: }
7161: }
7162:
7163: if ($args->{'disresdis'}) {
7164: $cenv{'pch.roles.denied'}='st';
7165: }
7166: if ($args->{'disablechat'}) {
7167: $cenv{'plc.roles.denied'}='st';
7168: }
7169:
7170: # Record we've not yet viewed the Course Initialization Helper for this
7171: # course
7172: $cenv{'course.helper.not.run'} = 1;
7173: #
7174: # Use new Randomseed
7175: #
7176: $cenv{'rndseed'}=&Apache::lonnet::latest_rnd_algorithm_id();;
7177: $cenv{'receiptalg'}=&Apache::lonnet::latest_receipt_algorithm_id();;
7178: #
7179: # The encryption code and receipt prefix for this course
7180: #
7181: $cenv{'internal.encseed'}=$Apache::lonnet::perlvar{'lonReceipt'}.$$.time.int(rand(9999));
7182: $cenv{'internal.encpref'}=100+int(9*rand(99));
7183: #
7184: # By default, use standard grading
7185: if (!defined($cenv{'grading'})) { $cenv{'grading'} = 'standard'; }
7186:
1.541 raeburn 7187: $outcome .= $linefeed.&mt('Setting environment').': '.
7188: &Apache::lonnet::put('environment',\%cenv,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 7189: #
7190: # Open all assignments
7191: #
7192: if ($args->{'openall'}) {
7193: my $storeunder=$$crsudom.'_'.$$crsunum.'.0.opendate';
7194: my %storecontent = ($storeunder => time,
7195: $storeunder.'.type' => 'date_start');
7196:
7197: $outcome .= &mt('Opening all assignments').': '.&Apache::lonnet::cput
1.541 raeburn 7198: ('resourcedata',\%storecontent,$$crsudom,$$crsunum).$linefeed;
1.444 albertel 7199: }
7200: #
7201: # Set first page
7202: #
7203: unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
7204: || ($cloneid)) {
1.445 albertel 7205: use LONCAPA::map;
1.444 albertel 7206: $outcome .= &mt('Setting first resource').': ';
1.445 albertel 7207:
7208: my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
7209: my ($errtext,$fatal)=&LONCAPA::map::mapread($map);
7210:
1.444 albertel 7211: $outcome .= ($fatal?$errtext:'read ok').' - ';
7212: my $title; my $url;
7213: if ($args->{'firstres'} eq 'syl') {
7214: $title='Syllabus';
7215: $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus';
7216: } else {
7217: $title='Navigate Contents';
7218: $url='/adm/navmaps';
7219: }
1.445 albertel 7220:
7221: $LONCAPA::map::resources[1]=$title.':'.$url.':false:start:res';
7222: (my $outtext,$errtext) = &LONCAPA::map::storemap($map,1);
7223:
7224: if ($errtext) { $fatal=2; }
1.541 raeburn 7225: $outcome .= ($fatal?$errtext:'write ok').$linefeed;
1.444 albertel 7226: }
7227: return $outcome;
7228: }
7229:
7230: ############################################################
7231: ############################################################
7232:
1.378 raeburn 7233: sub course_type {
7234: my ($cid) = @_;
7235: if (!defined($cid)) {
7236: $cid = $env{'request.course.id'};
7237: }
1.404 albertel 7238: if (defined($env{'course.'.$cid.'.type'})) {
7239: return $env{'course.'.$cid.'.type'};
1.378 raeburn 7240: } else {
7241: return 'Course';
1.377 raeburn 7242: }
7243: }
1.156 albertel 7244:
1.406 raeburn 7245: sub group_term {
7246: my $crstype = &course_type();
7247: my %names = (
7248: 'Course' => 'group',
7249: 'Group' => 'team',
7250: );
7251: return $names{$crstype};
7252: }
7253:
1.156 albertel 7254: sub icon {
7255: my ($file)=@_;
1.505 albertel 7256: my $curfext = lc((split(/\./,$file))[-1]);
1.168 albertel 7257: my $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/unknown.gif';
1.156 albertel 7258: my $embstyle = &Apache::loncommon::fileembstyle($curfext);
1.168 albertel 7259: if (!(!defined($embstyle) || $embstyle eq 'unk' || $embstyle eq 'hdn')) {
7260: if (-e $Apache::lonnet::perlvar{'lonDocRoot'}.'/'.
7261: $Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
7262: $curfext.".gif") {
7263: $iconname=$Apache::lonnet::perlvar{'lonIconsURL'}.'/'.
7264: $curfext.".gif";
7265: }
7266: }
1.249 albertel 7267: return &lonhttpdurl($iconname);
1.154 albertel 7268: }
1.84 albertel 7269:
1.215 albertel 7270: sub lonhttpdurl {
7271: my ($url)=@_;
7272: my $lonhttpd_port=$Apache::lonnet::perlvar{'lonhttpdPort'};
7273: if (!defined($lonhttpd_port)) { $lonhttpd_port='8080'; }
7274: return 'http://'.$ENV{'SERVER_NAME'}.':'.$lonhttpd_port.$url;
7275: }
7276:
1.213 albertel 7277: sub connection_aborted {
7278: my ($r)=@_;
7279: $r->print(" ");$r->rflush();
7280: my $c = $r->connection;
7281: return $c->aborted();
7282: }
7283:
1.221 foxr 7284: # Escapes strings that may have embedded 's that will be put into
1.222 foxr 7285: # strings as 'strings'.
7286: sub escape_single {
1.221 foxr 7287: my ($input) = @_;
1.223 albertel 7288: $input =~ s/\\/\\\\/g; # Escape the \'s..(must be first)>
1.221 foxr 7289: $input =~ s/\'/\\\'/g; # Esacpe the 's....
7290: return $input;
7291: }
1.223 albertel 7292:
1.222 foxr 7293: # Same as escape_single, but escape's "'s This
7294: # can be used for "strings"
7295: sub escape_double {
7296: my ($input) = @_;
7297: $input =~ s/\\/\\\\/g; # Escape the /'s..(must be first)>
7298: $input =~ s/\"/\\\"/g; # Esacpe the "s....
7299: return $input;
7300: }
1.223 albertel 7301:
1.222 foxr 7302: # Escapes the last element of a full URL.
7303: sub escape_url {
7304: my ($url) = @_;
1.238 raeburn 7305: my @urlslices = split(/\//, $url,-1);
1.369 www 7306: my $lastitem = &escape(pop(@urlslices));
1.223 albertel 7307: return join('/',@urlslices).'/'.$lastitem;
1.222 foxr 7308: }
1.462 albertel 7309:
7310: # -------------------------------------------------------- Initliaze user login
7311: sub init_user_environment {
1.463 albertel 7312: my ($r, $username, $domain, $authhost, $form, $args) = @_;
1.462 albertel 7313: my $lonids=$Apache::lonnet::perlvar{'lonIDsDir'};
7314:
7315: my $public=($username eq 'public' && $domain eq 'public');
7316:
7317: # See if old ID present, if so, remove
7318:
7319: my ($filename,$cookie,$userroles);
7320: my $now=time;
7321:
7322: if ($public) {
7323: my $max_public=100;
7324: my $oldest;
7325: my $oldest_time=0;
7326: for(my $next=1;$next<=$max_public;$next++) {
7327: if (-e $lonids."/publicuser_$next.id") {
7328: my $mtime=(stat($lonids."/publicuser_$next.id"))[9];
7329: if ($mtime<$oldest_time || !$oldest_time) {
7330: $oldest_time=$mtime;
7331: $oldest=$next;
7332: }
7333: } else {
7334: $cookie="publicuser_$next";
7335: last;
7336: }
7337: }
7338: if (!$cookie) { $cookie="publicuser_$oldest"; }
7339: } else {
1.463 albertel 7340: # if this isn't a robot, kill any existing non-robot sessions
7341: if (!$args->{'robot'}) {
7342: opendir(DIR,$lonids);
7343: while ($filename=readdir(DIR)) {
7344: if ($filename=~/^$username\_\d+\_$domain\_$authhost\.id$/) {
7345: unlink($lonids.'/'.$filename);
7346: }
1.462 albertel 7347: }
1.463 albertel 7348: closedir(DIR);
1.462 albertel 7349: }
7350: # Give them a new cookie
1.463 albertel 7351: my $id = ($args->{'robot'} ? 'robot'.$args->{'robot'}
7352: : $now);
7353: $cookie="$username\_$id\_$domain\_$authhost";
1.462 albertel 7354:
7355: # Initialize roles
7356:
7357: $userroles=&Apache::lonnet::rolesinit($domain,$username,$authhost);
7358: }
7359: # ------------------------------------ Check browser type and MathML capability
7360:
7361: my ($httpbrowser,$clientbrowser,$clientversion,$clientmathml,
7362: $clientunicode,$clientos) = &decode_user_agent($r);
7363:
7364: # -------------------------------------- Any accessibility options to remember?
7365: if (($form->{'interface'}) && ($form->{'remember'} eq 'true')) {
7366: foreach my $option ('imagesuppress','appletsuppress',
7367: 'embedsuppress','fontenhance','blackwhite') {
7368: if ($form->{$option} eq 'true') {
7369: &Apache::lonnet::put('environment',{$option => 'on'},
7370: $domain,$username);
7371: } else {
7372: &Apache::lonnet::del('environment',[$option],
7373: $domain,$username);
7374: }
7375: }
7376: }
7377: # ------------------------------------------------------------- Get environment
7378:
7379: my %userenv = &Apache::lonnet::dump('environment',$domain,$username);
7380: my ($tmp) = keys(%userenv);
7381: if ($tmp !~ /^(con_lost|error|no_such_host)/i) {
7382: # default remote control to off
7383: if ($userenv{'remote'} ne 'on') { $userenv{'remote'} = 'off'; }
7384: } else {
7385: undef(%userenv);
7386: }
7387: if (($userenv{'interface'}) && (!$form->{'interface'})) {
7388: $form->{'interface'}=$userenv{'interface'};
7389: }
7390: $env{'environment.remote'}=$userenv{'remote'};
7391: if ($userenv{'texengine'} eq 'ttm') { $clientmathml=1; }
7392:
7393: # --------------- Do not trust query string to be put directly into environment
7394: foreach my $option ('imagesuppress','appletsuppress',
7395: 'embedsuppress','fontenhance','blackwhite',
7396: 'interface','localpath','localres') {
7397: $form->{$option}=~s/[\n\r\=]//gs;
7398: }
7399: # --------------------------------------------------------- Write first profile
7400:
7401: {
7402: my %initial_env =
7403: ("user.name" => $username,
7404: "user.domain" => $domain,
7405: "user.home" => $authhost,
7406: "browser.type" => $clientbrowser,
7407: "browser.version" => $clientversion,
7408: "browser.mathml" => $clientmathml,
7409: "browser.unicode" => $clientunicode,
7410: "browser.os" => $clientos,
7411: "server.domain" => $Apache::lonnet::perlvar{'lonDefDomain'},
7412: "request.course.fn" => '',
7413: "request.course.uri" => '',
7414: "request.course.sec" => '',
7415: "request.role" => 'cm',
7416: "request.role.adv" => $env{'user.adv'},
7417: "request.host" => $ENV{'REMOTE_ADDR'},);
7418:
7419: if ($form->{'localpath'}) {
7420: $initial_env{"browser.localpath"} = $form->{'localpath'};
7421: $initial_env{"browser.localres"} = $form->{'localres'};
7422: }
7423:
7424: if ($public) {
7425: $initial_env{"environment.remote"} = "off";
7426: }
7427: if ($form->{'interface'}) {
7428: $form->{'interface'}=~s/\W//gs;
7429: $initial_env{"browser.interface"} = $form->{'interface'};
7430: $env{'browser.interface'}=$form->{'interface'};
7431: foreach my $option ('imagesuppress','appletsuppress',
7432: 'embedsuppress','fontenhance','blackwhite') {
7433: if (($form->{$option} eq 'true') ||
7434: ($userenv{$option} eq 'on')) {
7435: $initial_env{"browser.$option"} = "on";
7436: }
7437: }
7438: }
7439:
7440: $env{'user.environment'} = "$lonids/$cookie.id";
7441:
7442: if (tie(my %disk_env,'GDBM_File',"$lonids/$cookie.id",
7443: &GDBM_WRCREAT(),0640)) {
7444: &_add_to_env(\%disk_env,\%initial_env);
7445: &_add_to_env(\%disk_env,\%userenv,'environment.');
7446: &_add_to_env(\%disk_env,$userroles);
1.463 albertel 7447: if (ref($args->{'extra_env'})) {
7448: &_add_to_env(\%disk_env,$args->{'extra_env'});
7449: }
1.462 albertel 7450: untie(%disk_env);
7451: } else {
7452: &Apache::lonnet::logthis("<font color=\"blue\">WARNING: ".
7453: 'Could not create environment storage in lonauth: '.$!.'</font>');
7454: return 'error: '.$!;
7455: }
7456: }
7457: $env{'request.role'}='cm';
7458: $env{'request.role.adv'}=$env{'user.adv'};
7459: $env{'browser.type'}=$clientbrowser;
7460:
7461: return $cookie;
7462:
7463: }
7464:
7465: sub _add_to_env {
7466: my ($idf,$env_data,$prefix) = @_;
7467: while (my ($key,$value) = each(%$env_data)) {
7468: $idf->{$prefix.$key} = $value;
7469: $env{$prefix.$key} = $value;
7470: }
7471: }
7472:
7473:
1.41 ng 7474: =pod
7475:
7476: =back
7477:
1.112 bowersj2 7478: =cut
1.41 ng 7479:
1.112 bowersj2 7480: 1;
7481: __END__;
1.41 ng 7482:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>