![]() ![]() | ![]() |
Documentation fix so I can find it on grep.
1: # The LearningOnline Network with CAPA 2: # a pile of common routines 3: # 4: # $Id: loncommon.pm,v 1.65 2002/09/09 11:50:07 matthew Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 28: # YEAR=2001 29: # 2/13-12/7 Guy Albertelli 30: # 12/11,12/12,12/17 Scott Harrison 31: # 12/21 Gerd Kortemeyer 32: # 12/21 Scott Harrison 33: # 12/25,12/28 Gerd Kortemeyer 34: # YEAR=2002 35: # 1/4 Gerd Kortemeyer 36: # 6/24,7/2 H. K. Ng 37: 38: # Makes a table out of the previous attempts 39: # Inputs result_from_symbread, user, domain, course_id 40: # Reads in non-network-related .tab files 41: 42: # POD header: 43: 44: =pod 45: 46: =head1 NAME 47: 48: Apache::loncommon - pile of common routines 49: 50: =head1 SYNOPSIS 51: 52: Referenced by other mod_perl Apache modules. 53: 54: Invocation: 55: &Apache::loncommon::SUBROUTINENAME(ARGUMENTS); 56: 57: =head1 INTRODUCTION 58: 59: Common collection of used subroutines. This collection helps remove 60: redundancy from other modules and increase efficiency of memory usage. 61: 62: Current things done: 63: 64: Makes a table out of the previous homework attempts 65: Inputs result_from_symbread, user, domain, course_id 66: Reads in non-network-related .tab files 67: 68: This is part of the LearningOnline Network with CAPA project 69: described at http://www.lon-capa.org. 70: 71: =head2 General Subroutines 72: 73: =over 4 74: 75: =cut 76: 77: # End of POD header 78: package Apache::loncommon; 79: 80: use strict; 81: use Apache::lonnet(); 82: use GDBM_File; 83: use POSIX qw(strftime mktime); 84: use Apache::Constants qw(:common); 85: use Apache::lonmsg(); 86: my $readit; 87: 88: =pod 89: 90: =item Global Variables 91: 92: =over 4 93: 94: =cut 95: # ----------------------------------------------- Filetypes/Languages/Copyright 96: my %language; 97: my %cprtag; 98: my %fe; my %fd; 99: my %category_extensions; 100: 101: # ---------------------------------------------- Designs 102: 103: my %designhash; 104: 105: # ---------------------------------------------- Thesaurus variables 106: 107: =pod 108: 109: =item %Keywords 110: 111: A hash used by &keyword to determine if a word is considered a keyword. 112: 113: =item $thesaurus_db_file 114: 115: Scalar containing the full path to the thesaurus database. 116: 117: =cut 118: 119: my %Keywords; 120: my $thesaurus_db_file; 121: 122: 123: =pod 124: 125: =back 126: 127: =cut 128: 129: # ----------------------------------------------------------------------- BEGIN 130: 131: =pod 132: 133: =item BEGIN() 134: 135: Initialize values from language.tab, copyright.tab, filetypes.tab, 136: thesaurus.tab, and filecategories.tab. 137: 138: =cut 139: 140: # ----------------------------------------------------------------------- BEGIN 141: 142: BEGIN { 143: # Variable initialization 144: $thesaurus_db_file = $Apache::lonnet::perlvar{'lonTabDir'}."/thesaurus.db"; 145: # 146: unless ($readit) { 147: # ------------------------------------------------------------------- languages 148: { 149: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. 150: '/language.tab'); 151: if ($fh) { 152: while (<$fh>) { 153: next if /^\#/; 154: chomp; 155: my ($key,$val)=(split(/\s+/,$_,2)); 156: $language{$key}=$val; 157: } 158: } 159: } 160: # ------------------------------------------------------------------ copyrights 161: { 162: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonIncludes'}. 163: '/copyright.tab'); 164: if ($fh) { 165: while (<$fh>) { 166: next if /^\#/; 167: chomp; 168: my ($key,$val)=(split(/\s+/,$_,2)); 169: $cprtag{$key}=$val; 170: } 171: } 172: } 173: 174: # -------------------------------------------------------------- domain designs 175: 176: my $filename; 177: my $designdir=$Apache::lonnet::perlvar{'lonTabDir'}.'/lonDomColors'; 178: opendir(DIR,$designdir); 179: while ($filename=readdir(DIR)) { 180: my ($domain)=($filename=~/^(\w+)\./); 181: { 182: my $fh=Apache::File->new($designdir.'/'.$filename); 183: if ($fh) { 184: while (<$fh>) { 185: next if /^\#/; 186: chomp; 187: my ($key,$val)=(split(/\=/,$_)); 188: if ($val) { $designhash{$domain.'.'.$key}=$val; } 189: } 190: } 191: } 192: 193: } 194: closedir(DIR); 195: 196: 197: # ------------------------------------------------------------- file categories 198: { 199: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. 200: '/filecategories.tab'); 201: if ($fh) { 202: while (<$fh>) { 203: next if /^\#/; 204: chomp; 205: my ($extension,$category)=(split(/\s+/,$_,2)); 206: push @{$category_extensions{lc($category)}},$extension; 207: } 208: } 209: } 210: # ------------------------------------------------------------------ file types 211: { 212: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}. 213: '/filetypes.tab'); 214: if ($fh) { 215: while (<$fh>) { 216: next if (/^\#/); 217: chomp; 218: my ($ending,$emb,$descr)=split(/\s+/,$_,3); 219: if ($descr ne '') { 220: $fe{$ending}=lc($emb); 221: $fd{$ending}=$descr; 222: } 223: } 224: } 225: } 226: &Apache::lonnet::logthis( 227: "<font color=yellow>INFO: Read file types</font>"); 228: $readit=1; 229: } # end of unless($readit) 230: 231: } 232: # ============================================================= END BEGIN BLOCK 233: ############################################################### 234: ## HTML and Javascript Helper Functions ## 235: ############################################################### 236: 237: =pod 238: 239: =item browser_and_searcher_javascript 240: 241: Returns scalar containing javascript to open a browser window 242: or a searcher window. Also creates 243: 244: =over 4 245: 246: =item openbrowser(formname,elementname,only,omit) [javascript] 247: 248: inputs: formname, elementname, only, omit 249: 250: formname and elementname indicate the name of the html form and name of 251: the element that the results of the browsing selection are to be placed in. 252: 253: Specifying 'only' will restrict the browser to displaying only files 254: with the given extension. Can be a comma seperated list. 255: 256: Specifying 'omit' will restrict the browser to NOT displaying files 257: with the given extension. Can be a comma seperated list. 258: 259: =item opensearcher(formname, elementname) [javascript] 260: 261: Inputs: formname, elementname 262: 263: formname and elementname specify the name of the html form and the name 264: of the element the selection from the search results will be placed in. 265: 266: =back 267: 268: =cut 269: 270: ############################################################### 271: sub browser_and_searcher_javascript { 272: return <<END; 273: var editbrowser = null; 274: function openbrowser(formname,elementname,only,omit) { 275: var url = '/res/?'; 276: if (editbrowser == null) { 277: url += 'launch=1&'; 278: } 279: url += 'catalogmode=interactive&'; 280: url += 'mode=edit&'; 281: url += 'form=' + formname + '&'; 282: if (only != null) { 283: url += 'only=' + only + '&'; 284: } 285: if (omit != null) { 286: url += 'omit=' + omit + '&'; 287: } 288: url += 'element=' + elementname + ''; 289: var title = 'Browser'; 290: var options = 'scrollbars=1,resizable=1,menubar=0'; 291: options += ',width=700,height=600'; 292: editbrowser = open(url,title,options,'1'); 293: editbrowser.focus(); 294: } 295: var editsearcher; 296: function opensearcher(formname,elementname) { 297: var url = '/adm/searchcat?'; 298: if (editsearcher == null) { 299: url += 'launch=1&'; 300: } 301: url += 'catalogmode=interactive&'; 302: url += 'mode=edit&'; 303: url += 'form=' + formname + '&'; 304: url += 'element=' + elementname + ''; 305: var title = 'Search'; 306: var options = 'scrollbars=1,resizable=1,menubar=0'; 307: options += ',width=700,height=600'; 308: editsearcher = open(url,title,options,'1'); 309: editsearcher.focus(); 310: } 311: END 312: } 313: 314: 315: 316: ############################################################### 317: 318: =pod 319: 320: =item linked_select_forms(...) 321: 322: linked_select_forms returns a string containing a <script></script> block 323: and html for two <select> menus. The select menus will be linked in that 324: changing the value of the first menu will result in new values being placed 325: in the second menu. The values in the select menu will appear in alphabetical 326: order. 327: 328: linked_select_forms takes the following ordered inputs: 329: 330: =over 4 331: 332: =item $formname, the name of the <form> tag 333: 334: =item $middletext, the text which appears between the <select> tags 335: 336: =item $firstdefault, the default value for the first menu 337: 338: =item $firstselectname, the name of the first <select> tag 339: 340: =item $secondselectname, the name of the second <select> tag 341: 342: =item $hashref, a reference to a hash containing the data for the menus. 343: 344: =back 345: 346: Below is an example of such a hash. Only the 'text', 'default', and 347: 'select2' keys must appear as stated. keys(%menu) are the possible 348: values for the first select menu. The text that coincides with the 349: first menu value is given in $menu{$choice1}->{'text'}. The values 350: and text for the second menu are given in the hash pointed to by 351: $menu{$choice1}->{'select2'}. 352: 353: my %menu = ( A1 => { text =>"Choice A1" , 354: default => "B3", 355: select2 => { 356: B1 => "Choice B1", 357: B2 => "Choice B2", 358: B3 => "Choice B3", 359: B4 => "Choice B4" 360: } 361: }, 362: A2 => { text =>"Choice A2" , 363: default => "C2", 364: select2 => { 365: C1 => "Choice C1", 366: C2 => "Choice C2", 367: C3 => "Choice C3" 368: } 369: }, 370: A3 => { text =>"Choice A3" , 371: default => "D6", 372: select2 => { 373: D1 => "Choice D1", 374: D2 => "Choice D2", 375: D3 => "Choice D3", 376: D4 => "Choice D4", 377: D5 => "Choice D5", 378: D6 => "Choice D6", 379: D7 => "Choice D7" 380: } 381: } 382: ); 383: 384: =cut 385: 386: # ------------------------------------------------ 387: 388: sub linked_select_forms { 389: my ($formname, 390: $middletext, 391: $firstdefault, 392: $firstselectname, 393: $secondselectname, 394: $hashref 395: ) = @_; 396: my $second = "document.$formname.$secondselectname"; 397: my $first = "document.$formname.$firstselectname"; 398: # output the javascript to do the changing 399: my $result = ''; 400: $result.="<script>\n"; 401: $result.="var select2data = new Object();\n"; 402: $" = '","'; 403: my $debug = ''; 404: foreach my $s1 (sort(keys(%$hashref))) { 405: $result.="select2data.d_$s1 = new Object();\n"; 406: $result.="select2data.d_$s1.def = new String('". 407: $hashref->{$s1}->{'default'}."');\n"; 408: $result.="select2data.d_$s1.values = new Array("; 409: my @s2values = sort(keys( %{ $hashref->{$s1}->{'select2'} } )); 410: $result.="\"@s2values\");\n"; 411: $result.="select2data.d_$s1.texts = new Array("; 412: my @s2texts; 413: foreach my $value (@s2values) { 414: push @s2texts, $hashref->{$s1}->{'select2'}->{$value}; 415: } 416: $result.="\"@s2texts\");\n"; 417: } 418: $"=' '; 419: $result.= <<"END"; 420: 421: function select1_changed() { 422: // Determine new choice 423: var newvalue = "d_" + $first.value; 424: // update select2 425: var values = select2data[newvalue].values; 426: var texts = select2data[newvalue].texts; 427: var select2def = select2data[newvalue].def; 428: var i; 429: // out with the old 430: for (i = 0; i < $second.options.length; i++) { 431: $second.options[i] = null; 432: } 433: // in with the nuclear 434: for (i=0;i<values.length; i++) { 435: $second.options[i] = new Option(values[i]); 436: $second.options[i].text = texts[i]; 437: if (values[i] == select2def) { 438: $second.options[i].selected = true; 439: } 440: } 441: } 442: </script> 443: END 444: # output the initial values for the selection lists 445: $result .= "<select size=\"1\" name=\"$firstselectname\" onchange=\"select1_changed()\">\n"; 446: foreach my $value (sort(keys(%$hashref))) { 447: $result.=" <option value=\"$value\" "; 448: $result.=" selected=\"true\" " if ($value eq $firstdefault); 449: $result.=">$hashref->{$value}->{'text'}</option>\n"; 450: } 451: $result .= "</select>\n"; 452: my %select2 = %{$hashref->{$firstdefault}->{'select2'}}; 453: $result .= $middletext; 454: $result .= "<select size=\"1\" name=\"$secondselectname\">\n"; 455: my $seconddefault = $hashref->{$firstdefault}->{'default'}; 456: foreach my $value (sort(keys(%select2))) { 457: $result.=" <option value=\"$value\" "; 458: $result.=" selected=\"true\" " if ($value eq $seconddefault); 459: $result.=">$select2{$value}</option>\n"; 460: } 461: $result .= "</select>\n"; 462: # return $debug; 463: return $result; 464: } # end of sub linked_select_forms { 465: 466: ############################################################### 467: 468: =pod 469: 470: =item help_open_topic($topic, $text, $stayOnPage, $width, $height) 471: 472: Returns a string corresponding to an HTML link to the given help $topic, where $topic corresponds to the name of a .tex file in /home/httpd/html/adm/help/tex, with underscores replaced by spaces. 473: 474: $text will optionally be linked to the same topic, allowing you to link text in addition to the graphic. If you do not want to link text, but wish to specify one of the later parameters, pass an empty string. 475: 476: $stayOnPage is a value that will be interpreted as a boolean. If true, the link will not open a new window. If false, the link will open a new window using Javascript. (Default is false.) 477: 478: $width and $height are optional numerical parameters that will override the width and height of the popped up window, which may be useful for certain help topics with big pictures included. 479: 480: =cut 481: 482: sub help_open_topic { 483: my ($topic, $text, $stayOnPage, $width, $height) = @_; 484: $text = "" if (not defined $text); 485: $stayOnPage = 0 if (not defined $stayOnPage); 486: $width = 350 if (not defined $width); 487: $height = 400 if (not defined $height); 488: my $filename = $topic; 489: $filename =~ s/ /_/g; 490: 491: my $template = ""; 492: my $link; 493: 494: if (!$stayOnPage) 495: { 496: $link = "javascript:void(open('/adm/help/${filename}.hlp', 'Help_for_$topic', 'menubar=0,toolbar=1,scrollbars=1,width=$width,height=$height'))"; 497: } 498: else 499: { 500: $link = "/adm/help/${filename}.hlp"; 501: } 502: 503: # Add the text 504: if ($text ne "") 505: { 506: $template .= "<a href=\"$link\">$text</a> "; 507: } 508: 509: # Add the graphic 510: $template .= <<"ENDTEMPLATE"; 511: <a href="$link"><image src="/adm/help/gif/smallHelp.gif" border="0" alt="(Help: $topic)" /></a> 512: ENDTEMPLATE 513: 514: return $template; 515: 516: } 517: 518: =pod 519: 520: =item csv_translate($text) 521: 522: Translate $text to allow it to be output as a 'comma seperated values' 523: format. 524: 525: =cut 526: 527: sub csv_translate { 528: my $text = shift; 529: $text =~ s/\"/\"\"/g; 530: $text =~ s/\n//g; 531: return $text; 532: } 533: 534: ############################################################### 535: ## Home server <option> list generating code ## 536: ############################################################### 537: #------------------------------------------- 538: 539: =pod 540: 541: =item get_domains() 542: 543: Returns an array containing each of the domains listed in the hosts.tab 544: file. 545: 546: =cut 547: 548: #------------------------------------------- 549: sub get_domains { 550: # The code below was stolen from "The Perl Cookbook", p 102, 1st ed. 551: my @domains; 552: my %seen; 553: foreach (sort values(%Apache::lonnet::hostdom)) { 554: push (@domains,$_) unless $seen{$_}++; 555: } 556: return @domains; 557: } 558: 559: #------------------------------------------- 560: 561: =pod 562: 563: =item select_dom_form($defdom,$name) 564: 565: Returns a string containing a <select name='$name' size='1'> form to 566: allow a user to select the domain to preform an operation in. 567: See loncreateuser.pm for an example invocation and use. 568: 569: =cut 570: 571: #------------------------------------------- 572: sub select_dom_form { 573: my ($defdom,$name) = @_; 574: my @domains = get_domains(); 575: my $selectdomain = "<select name=\"$name\" size=\"1\">\n"; 576: foreach (@domains) { 577: $selectdomain.="<option value=\"$_\" ". 578: ($_ eq $defdom ? 'selected' : ''). 579: ">$_</option>\n"; 580: } 581: $selectdomain.="</select>"; 582: return $selectdomain; 583: } 584: 585: #------------------------------------------- 586: 587: =pod 588: 589: =item get_library_servers($domain) 590: 591: Returns a hash which contains keys like '103l3' and values like 592: 'kirk.lite.msu.edu'. All of the keys will be for machines in the 593: given $domain. 594: 595: =cut 596: 597: #------------------------------------------- 598: sub get_library_servers { 599: my $domain = shift; 600: my %library_servers; 601: foreach (keys(%Apache::lonnet::libserv)) { 602: if ($Apache::lonnet::hostdom{$_} eq $domain) { 603: $library_servers{$_} = $Apache::lonnet::hostname{$_}; 604: } 605: } 606: return %library_servers; 607: } 608: 609: #------------------------------------------- 610: 611: =pod 612: 613: =item home_server_option_list($domain) 614: 615: returns a string which contains an <option> list to be used in a 616: <select> form input. See loncreateuser.pm for an example. 617: 618: =cut 619: 620: #------------------------------------------- 621: sub home_server_option_list { 622: my $domain = shift; 623: my %servers = &get_library_servers($domain); 624: my $result = ''; 625: foreach (sort keys(%servers)) { 626: $result.= 627: '<option value="'.$_.'">'.$_.' '.$servers{$_}."</option>\n"; 628: } 629: return $result; 630: } 631: ############################################################### 632: ## End of home server <option> list generating code ## 633: ############################################################### 634: 635: ############################################################### 636: ## Authentication changing form generation subroutines ## 637: ############################################################### 638: ## 639: ## All of the authform_xxxxxxx subroutines take their inputs in a 640: ## hash, and have reasonable default values. 641: ## 642: ## formname = the name given in the <form> tag. 643: #------------------------------------------- 644: 645: =pod 646: 647: =item authform_xxxxxx 648: 649: The authform_xxxxxx subroutines provide javascript and html forms which 650: handle some of the conveniences required for authentication forms. 651: This is not an optimal method, but it works. 652: 653: See loncreateuser.pm for invocation and use examples. 654: 655: =over 4 656: 657: =item authform_header 658: 659: =item authform_authorwarning 660: 661: =item authform_nochange 662: 663: =item authform_kerberos 664: 665: =item authform_internal 666: 667: =item authform_filesystem 668: 669: =back 670: 671: =cut 672: 673: #------------------------------------------- 674: sub authform_header{ 675: my %in = ( 676: formname => 'cu', 677: kerb_def_dom => 'MSU.EDU', 678: @_, 679: ); 680: $in{'formname'} = 'document.' . $in{'formname'}; 681: my $result=''; 682: $result.=<<"END"; 683: var current = new Object(); 684: current.radiovalue = 'nochange'; 685: current.argfield = null; 686: 687: function changed_radio(choice,currentform) { 688: var choicearg = choice + 'arg'; 689: // If a radio button in changed, we need to change the argfield 690: if (current.radiovalue != choice) { 691: current.radiovalue = choice; 692: if (current.argfield != null) { 693: currentform.elements[current.argfield].value = ''; 694: } 695: if (choice == 'nochange') { 696: current.argfield = null; 697: } else { 698: current.argfield = choicearg; 699: switch(choice) { 700: case 'krb': 701: currentform.elements[current.argfield].value = 702: "$in{'kerb_def_dom'}"; 703: break; 704: default: 705: break; 706: } 707: } 708: } 709: return; 710: } 711: 712: function changed_text(choice,currentform) { 713: var choicearg = choice + 'arg'; 714: if (currentform.elements[choicearg].value !='') { 715: switch (choice) { 716: case 'krb': currentform.elements[choicearg].value = 717: currentform.elements[choicearg].value.toUpperCase(); 718: break; 719: default: 720: } 721: // clear old field 722: if ((current.argfield != choicearg) && (current.argfield != null)) { 723: currentform.elements[current.argfield].value = ''; 724: } 725: current.argfield = choicearg; 726: } 727: set_auth_radio_buttons(choice,currentform); 728: return; 729: } 730: 731: function set_auth_radio_buttons(newvalue,currentform) { 732: var i=0; 733: while (i < currentform.login.length) { 734: if (currentform.login[i].value == newvalue) { break; } 735: i++; 736: } 737: if (i == currentform.login.length) { 738: return; 739: } 740: current.radiovalue = newvalue; 741: currentform.login[i].checked = true; 742: return; 743: } 744: END 745: return $result; 746: } 747: 748: sub authform_authorwarning{ 749: my $result=''; 750: $result=<<"END"; 751: <i>As a general rule, only authors or co-authors should be filesystem 752: authenticated (which allows access to the server filesystem).</i> 753: END 754: return $result; 755: } 756: 757: sub authform_nochange{ 758: my %in = ( 759: formname => 'document.cu', 760: kerb_def_dom => 'MSU.EDU', 761: @_, 762: ); 763: my $result=''; 764: $result.=<<"END"; 765: <input type="radio" name="login" value="nochange" checked="checked" 766: onclick="javascript:changed_radio('nochange',$in{'formname'});" /> 767: Do not change login data 768: END 769: return $result; 770: } 771: 772: sub authform_kerberos{ 773: my %in = ( 774: formname => 'document.cu', 775: kerb_def_dom => 'MSU.EDU', 776: @_, 777: ); 778: my $result=''; 779: $result.=<<"END"; 780: <input type="radio" name="login" value="krb" 781: onclick="javascript:changed_radio('krb',$in{'formname'});" 782: onchange="javascript:changed_radio('krb',$in{'formname'});" /> 783: Kerberos authenticated with domain 784: <input type="text" size="10" name="krbarg" value="" 785: onchange="javascript:changed_text('krb',$in{'formname'});" /> 786: <input type="radio" name="krbver" value="4" checked="on" />Version 4 787: <input type="radio" name="krbver" value="5" />Version 5 788: END 789: return $result; 790: } 791: 792: sub authform_internal{ 793: my %args = ( 794: formname => 'document.cu', 795: kerb_def_dom => 'MSU.EDU', 796: @_, 797: ); 798: my $result=''; 799: $result.=<<"END"; 800: <input type="radio" name="login" value="int" 801: onchange="javascript:changed_radio('int',$args{'formname'});" 802: onclick="javascript:changed_radio('int',$args{'formname'});" /> 803: Internally authenticated (with initial password 804: <input type="text" size="10" name="intarg" value="" 805: onchange="javascript:changed_text('int',$args{'formname'});" /> 806: END 807: return $result; 808: } 809: 810: sub authform_local{ 811: my %in = ( 812: formname => 'document.cu', 813: kerb_def_dom => 'MSU.EDU', 814: @_, 815: ); 816: my $result=''; 817: $result.=<<"END"; 818: <input type="radio" name="login" value="loc" 819: onchange="javascript:changed_radio('loc',$in{'formname'});" 820: onclick="javascript:changed_radio('loc',$in{'formname'});" /> 821: Local Authentication with argument 822: <input type="text" size="10" name="locarg" value="" 823: onchange="javascript:changed_text('loc',$in{'formname'});" /> 824: END 825: return $result; 826: } 827: 828: sub authform_filesystem{ 829: my %in = ( 830: formname => 'document.cu', 831: kerb_def_dom => 'MSU.EDU', 832: @_, 833: ); 834: my $result=''; 835: $result.=<<"END"; 836: <input type="radio" name="login" value="fsys" 837: onchange="javascript:changed_radio('fsys',$in{'formname'});" 838: onclick="javascript:changed_radio('fsys',$in{'formname'});" /> 839: Filesystem authenticated (with initial password 840: <input type="text" size="10" name="fsysarg" value="" 841: onchange="javascript:changed_text('fsys',$in{'formname'});"> 842: END 843: return $result; 844: } 845: 846: ############################################################### 847: ## End Authentication changing form generation functions ## 848: ############################################################### 849: 850: ############################################################### 851: ## Thesaurus Functions ## 852: ############################################################### 853: 854: =pod 855: 856: =item initialize_keywords 857: 858: Initializes the package variable %Keywords if it is empty. Uses the 859: package variable $thesaurus_db_file. 860: 861: =cut 862: 863: ################################################### 864: 865: sub initialize_keywords { 866: return 1 if (scalar keys(%Keywords)); 867: # If we are here, %Keywords is empty, so fill it up 868: # Make sure the file we need exists... 869: if (! -e $thesaurus_db_file) { 870: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file". 871: " failed because it does not exist"); 872: return 0; 873: } 874: # Set up the hash as a database 875: my %thesaurus_db; 876: if (! tie(%thesaurus_db,'GDBM_File', 877: $thesaurus_db_file,&GDBM_READER(),0640)){ 878: &Apache::lonnet::logthis("Could not tie \%thesaurus_db to ". 879: $thesaurus_db_file); 880: return 0; 881: } 882: # Get the average number of appearances of a word. 883: my $avecount = $thesaurus_db{'average.count'}; 884: # Put keywords (those that appear > average) into %Keywords 885: while (my ($word,$data)=each (%thesaurus_db)) { 886: my ($count,undef) = split /:/,$data; 887: $Keywords{$word}++ if ($count > $avecount); 888: } 889: untie %thesaurus_db; 890: # Remove special values from %Keywords. 891: foreach ('total.count','average.count') { 892: delete($Keywords{$_}) if (exists($Keywords{$_})); 893: } 894: return 1; 895: } 896: 897: ################################################### 898: 899: =pod 900: 901: =item keyword($word) 902: 903: Returns true if $word is a keyword. A keyword is a word that appears more 904: than the average number of times in the thesaurus database. Calls 905: &initialize_keywords 906: 907: =cut 908: 909: ################################################### 910: 911: sub keyword { 912: return if (!&initialize_keywords()); 913: my $word=lc(shift()); 914: $word=~s/\W//g; 915: return exists($Keywords{$word}); 916: } 917: 918: ############################################################### 919: 920: =pod 921: 922: =item get_related_words 923: 924: Look up a word in the thesaurus. Takes a scalar arguement and returns 925: an array of words. If the keyword is not in the thesaurus, an empty array 926: will be returned. The order of the words returned is determined by the 927: database which holds them. 928: 929: Uses global $thesaurus_db_file. 930: 931: =cut 932: 933: ############################################################### 934: sub get_related_words { 935: my $keyword = shift; 936: my %thesaurus_db; 937: if (! -e $thesaurus_db_file) { 938: &Apache::lonnet::logthis("Attempt to access $thesaurus_db_file ". 939: "failed because the file does not exist"); 940: return (); 941: } 942: if (! tie(%thesaurus_db,'GDBM_File', 943: $thesaurus_db_file,&GDBM_READER(),0640)){ 944: return (); 945: } 946: my @Words=(); 947: if (exists($thesaurus_db{$keyword})) { 948: $_ = $thesaurus_db{$keyword}; 949: (undef,@Words) = split/:/; # The first element is the number of times 950: # the word appears. We do not need it now. 951: for (my $i=0;$i<=$#Words;$i++) { 952: ($Words[$i],undef)= split/\,/,$Words[$i]; 953: } 954: } 955: untie %thesaurus_db; 956: return @Words; 957: } 958: 959: ############################################################### 960: ## End Thesaurus Functions ## 961: ############################################################### 962: 963: # -------------------------------------------------------------- Plaintext name 964: 965: sub plainname { 966: my ($uname,$udom)=@_; 967: my %names=&Apache::lonnet::get('environment', 968: ['firstname','middlename','lastname','generation'], 969: $udom,$uname); 970: my $name=$names{'firstname'}.' '.$names{'middlename'}.' '. 971: $names{'lastname'}.' '.$names{'generation'}; 972: $name=~s/\s+$//; 973: $name=~s/\s+/ /g; 974: return $name; 975: } 976: 977: # ------------------------------------------------------------------ Screenname 978: 979: sub screenname { 980: my ($uname,$udom)=@_; 981: my %names= 982: &Apache::lonnet::get('environment',['screenname'],$udom,$uname); 983: return $names{'screenname'}; 984: } 985: 986: # ------------------------------------------------------------- Message Wrapper 987: 988: sub messagewrapper { 989: my ($link,$un,$do)=@_; 990: return 991: "<a href='/adm/email?compose=individual&recname=$un&recdom=$do'>$link</a>"; 992: } 993: # ------------------------------------------------------------- Aboutme Wrapper 994: 995: sub aboutmewrapper { 996: my ($link,$un,$do)=@_; 997: return "<a href='/adm/$do/$un/aboutme'>$link</a>"; 998: } 999: 1000: # ------------------------------------------------------------ Syllabus Wrapper 1001: 1002: 1003: sub syllabuswrapper { 1004: my ($link,$un,$do)=@_; 1005: return "<a href='/public/$do/$un/syllabus'>$link</a>"; 1006: } 1007: 1008: # ---------------------------------------------------------------- Language IDs 1009: sub languageids { 1010: return sort(keys(%language)); 1011: } 1012: 1013: # -------------------------------------------------------- Language Description 1014: sub languagedescription { 1015: return $language{shift(@_)}; 1016: } 1017: 1018: # --------------------------------------------------------------- Copyright IDs 1019: sub copyrightids { 1020: return sort(keys(%cprtag)); 1021: } 1022: 1023: # ------------------------------------------------------- Copyright Description 1024: sub copyrightdescription { 1025: return $cprtag{shift(@_)}; 1026: } 1027: 1028: # ------------------------------------------------------------- File Categories 1029: sub filecategories { 1030: return sort(keys(%category_extensions)); 1031: } 1032: 1033: # -------------------------------------- File Types within a specified category 1034: sub filecategorytypes { 1035: return @{$category_extensions{lc($_[0])}}; 1036: } 1037: 1038: # ------------------------------------------------------------------ File Types 1039: sub fileextensions { 1040: return sort(keys(%fe)); 1041: } 1042: 1043: # ------------------------------------------------------------- Embedding Style 1044: sub fileembstyle { 1045: return $fe{lc(shift(@_))}; 1046: } 1047: 1048: # ------------------------------------------------------------ Description Text 1049: sub filedescription { 1050: return $fd{lc(shift(@_))}; 1051: } 1052: 1053: # ------------------------------------------------------------ Description Text 1054: sub filedescriptionex { 1055: my $ex=shift; 1056: return '.'.$ex.' '.$fd{lc($ex)}; 1057: } 1058: 1059: # ---- Retrieve attempts by students 1060: # input 1061: # $symb - problem including path 1062: # $username,$domain - that of the student 1063: # $course - course name 1064: # $getattempt - leave blank if want all attempts, else put something. 1065: # $regexp - regular expression. If string matches regexp send to 1066: # $gradesub - routine that process the string if it matches regexp 1067: # 1068: # output 1069: # formatted as a table all the attempts, if any. 1070: # 1071: sub get_previous_attempt { 1072: my ($symb,$username,$domain,$course,$getattempt,$regexp,$gradesub)=@_; 1073: my $prevattempts=''; 1074: no strict 'refs'; 1075: if ($symb) { 1076: my (%returnhash)= 1077: &Apache::lonnet::restore($symb,$course,$domain,$username); 1078: if ($returnhash{'version'}) { 1079: my %lasthash=(); 1080: my $version; 1081: for ($version=1;$version<=$returnhash{'version'};$version++) { 1082: foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) { 1083: $lasthash{$_}=$returnhash{$version.':'.$_}; 1084: } 1085: } 1086: $prevattempts='<table border="0" width="100%"><tr><td bgcolor="#777777">'; 1087: $prevattempts.='<table border="0" width="100%"><tr bgcolor="#e6ffff"><td>History</td>'; 1088: foreach (sort(keys %lasthash)) { 1089: my ($ign,@parts) = split(/\./,$_); 1090: if ($#parts > 0) { 1091: my $data=$parts[-1]; 1092: pop(@parts); 1093: $prevattempts.='<td>Part '.join('.',@parts).'<br />'.$data.' </td>'; 1094: } else { 1095: if ($#parts == 0) { 1096: $prevattempts.='<th>'.$parts[0].'</th>'; 1097: } else { 1098: $prevattempts.='<th>'.$ign.'</th>'; 1099: } 1100: } 1101: } 1102: if ($getattempt eq '') { 1103: for ($version=1;$version<=$returnhash{'version'};$version++) { 1104: $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Transaction '.$version.'</td>'; 1105: foreach (sort(keys %lasthash)) { 1106: my $value; 1107: if ($_ =~ /timestamp/) { 1108: $value=scalar(localtime($returnhash{$version.':'.$_})); 1109: } else { 1110: $value=$returnhash{$version.':'.$_}; 1111: } 1112: $prevattempts.='<td>'.$value.' </td>'; 1113: } 1114: } 1115: } 1116: $prevattempts.='</tr><tr bgcolor="#ffffe6"><td>Current</td>'; 1117: foreach (sort(keys %lasthash)) { 1118: my $value; 1119: if ($_ =~ /timestamp/) { 1120: $value=scalar(localtime($lasthash{$_})); 1121: } else { 1122: $value=$lasthash{$_}; 1123: } 1124: if ($_ =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} 1125: $prevattempts.='<td>'.$value.' </td>'; 1126: } 1127: $prevattempts.='</tr></table></td></tr></table>'; 1128: } else { 1129: $prevattempts='Nothing submitted - no attempts.'; 1130: } 1131: } else { 1132: $prevattempts='No data.'; 1133: } 1134: } 1135: 1136: sub get_student_view { 1137: my ($symb,$username,$domain,$courseid,$target) = @_; 1138: my ($map,$id,$feedurl) = split(/___/,$symb); 1139: my (%old,%moreenv); 1140: my @elements=('symb','courseid','domain','username'); 1141: foreach my $element (@elements) { 1142: $old{$element}=$ENV{'form.grade_'.$element}; 1143: $moreenv{'form.grade_'.$element}=eval '$'.$element #' 1144: } 1145: if ($target eq 'tex') {$moreenv{'form.grade_target'} = 'tex';} 1146: &Apache::lonnet::appenv(%moreenv); 1147: my $userview=&Apache::lonnet::ssi('/res/'.$feedurl); 1148: &Apache::lonnet::delenv('form.grade_'); 1149: foreach my $element (@elements) { 1150: $ENV{'form.grade_'.$element}=$old{$element}; 1151: } 1152: $userview=~s/\<body[^\>]*\>//gi; 1153: $userview=~s/\<\/body\>//gi; 1154: $userview=~s/\<html\>//gi; 1155: $userview=~s/\<\/html\>//gi; 1156: $userview=~s/\<head\>//gi; 1157: $userview=~s/\<\/head\>//gi; 1158: $userview=~s/action\s*\=/would_be_action\=/gi; 1159: return $userview; 1160: } 1161: 1162: sub get_student_answers { 1163: my ($symb,$username,$domain,$courseid) = @_; 1164: my ($map,$id,$feedurl) = split(/___/,$symb); 1165: my (%old,%moreenv); 1166: my @elements=('symb','courseid','domain','username'); 1167: foreach my $element (@elements) { 1168: $old{$element}=$ENV{'form.grade_'.$element}; 1169: $moreenv{'form.grade_'.$element}=eval '$'.$element #' 1170: } 1171: $moreenv{'form.grade_target'}='answer'; 1172: &Apache::lonnet::appenv(%moreenv); 1173: my $userview=&Apache::lonnet::ssi('/res/'.$feedurl); 1174: &Apache::lonnet::delenv('form.grade_'); 1175: foreach my $element (@elements) { 1176: $ENV{'form.grade_'.$element}=$old{$element}; 1177: } 1178: return $userview; 1179: } 1180: 1181: ############################################### 1182: 1183: 1184: sub timehash { 1185: my @ltime=localtime(shift); 1186: return ( 'seconds' => $ltime[0], 1187: 'minutes' => $ltime[1], 1188: 'hours' => $ltime[2], 1189: 'day' => $ltime[3], 1190: 'month' => $ltime[4]+1, 1191: 'year' => $ltime[5]+1900, 1192: 'weekday' => $ltime[6], 1193: 'dayyear' => $ltime[7]+1, 1194: 'dlsav' => $ltime[8] ); 1195: } 1196: 1197: sub maketime { 1198: my %th=@_; 1199: return POSIX::mktime( 1200: ($th{'seconds'},$th{'minutes'},$th{'hours'}, 1201: $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,$th{'dlsav'})); 1202: } 1203: 1204: 1205: sub findallcourses { 1206: my %courses=(); 1207: my $now=time; 1208: foreach (keys %ENV) { 1209: if ($_=~/^user\.role\.\w+\.\/(\w+)\/(\w+)/) { 1210: my ($starttime,$endtime)=$ENV{$_}; 1211: my $active=1; 1212: if ($starttime) { 1213: if ($now<$starttime) { $active=0; } 1214: } 1215: if ($endtime) { 1216: if ($now>$endtime) { $active=0; } 1217: } 1218: if ($active) { $courses{$1.'_'.$2}=1; } 1219: } 1220: } 1221: return keys %courses; 1222: } 1223: 1224: ############################################### 1225: ############################################### 1226: 1227: =pod 1228: 1229: =item &determinedomain() 1230: 1231: Inputs: $domain (usually will be undef) 1232: 1233: Returns: Determines which domain should be used for designs 1234: 1235: =cut 1236: 1237: ############################################### 1238: sub determinedomain { 1239: my $domain=shift; 1240: if (! $domain) { 1241: # Determine domain if we have not been given one 1242: $domain = $Apache::lonnet::perlvar{'lonDefDomain'}; 1243: if ($ENV{'user.domain'}) { $domain=$ENV{'user.domain'}; } 1244: if ($ENV{'request.role.domain'}) { 1245: $domain=$ENV{'request.role.domain'}; 1246: } 1247: } 1248: return $domain; 1249: } 1250: ############################################### 1251: =pod 1252: 1253: =item &domainlogo() 1254: 1255: Inputs: $domain (usually will be undef) 1256: 1257: Returns: A link to a domain logo, if the domain logo exists. 1258: If the domain logo does not exist, a description of the domain. 1259: 1260: =cut 1261: ############################################### 1262: sub domainlogo { 1263: my $domain = &determinedomain(shift); 1264: # See if there is a logo 1265: if (-e '/home/httpd/html/adm/lonDomLogos/'.$domain.'.gif') { 1266: return '<img src="/adm/lonDomLogos/'.$domain.'.gif" />'; 1267: } elsif(exists($Apache::lonnet::domaindescription{$domain})) { 1268: return $Apache::lonnet::domaindescription{$domain}; 1269: } else { 1270: return ''; 1271: } 1272: } 1273: ############################################## 1274: 1275: =pod 1276: 1277: =item &designparm() 1278: 1279: Inputs: $which parameter; $domain (usually will be undef) 1280: 1281: Returns: value of designparamter $which 1282: 1283: =cut 1284: ############################################## 1285: sub designparm { 1286: my ($which,$domain)=@_; 1287: $domain=&determinedomain($domain); 1288: if ($designhash{$domain.'.'.$which}) { 1289: return $designhash{$domain.'.'.$which}; 1290: } else { 1291: return $designhash{'default.'.$which}; 1292: } 1293: } 1294: 1295: ############################################### 1296: ############################################### 1297: 1298: =pod 1299: 1300: =item &bodytag() 1301: 1302: Returns a uniform header for LON-CAPA web pages. 1303: 1304: Inputs: 1305: 1306: $title, A title to be displayed on the page. 1307: $function, the current role (can be undef). 1308: $addentries, extra parameters for the <body> tag. 1309: $bodyonly, if defined, only return the <body> tag. 1310: $domain, if defined, force a given domain. 1311: 1312: Returns: A uniform header for LON-CAPA web pages. 1313: If $bodyonly is nonzero, a string containing a <body> tag will be returned. 1314: If $bodyonly is undef or zero, an html string containing a <body> tag and 1315: other decorations will be returned. 1316: 1317: =cut 1318: 1319: ############################################### 1320: 1321: 1322: ############################################### 1323: sub bodytag { 1324: my ($title,$function,$addentries,$bodyonly,$domain)=@_; 1325: unless ($function) { 1326: $function='student'; 1327: if ($ENV{'request.role'}=~/^(cc|in|ta|ep)/) { 1328: $function='coordinator'; 1329: } 1330: if ($ENV{'request.role'}=~/^(su|dc|ad|li)/) { 1331: $function='admin'; 1332: } 1333: if (($ENV{'request.role'}=~/^(au|ca)/) || 1334: ($ENV{'REQUEST_URI'}=~/^(\/priv|\~)/)) { 1335: $function='author'; 1336: } 1337: } 1338: my $img=&designparm($function.'.img',$domain); 1339: my $pgbg=&designparm($function.'.pgbg',$domain); 1340: my $tabbg=&designparm($function.'.tabbg',$domain); 1341: my $font=&designparm($function.'.font',$domain); 1342: my $link=&designparm($function.'.link',$domain); 1343: my $alink=&designparm($function.'.alink',$domain); 1344: my $vlink=&designparm($function.'.vlink',$domain); 1345: my $sidebg=&designparm($function.'.sidebg',$domain); 1346: 1347: # role and realm 1348: my ($role,$realm) 1349: =&Apache::lonnet::plaintext((split(/\./,$ENV{'request.role'}))[0]); 1350: # realm 1351: if ($ENV{'request.course.id'}) { 1352: $realm= 1353: $ENV{'course.'.$ENV{'request.course.id'}.'.description'}; 1354: } 1355: unless ($realm) { $realm=' '; } 1356: # Set messages 1357: my $messages=&domainlogo($domain); 1358: # Output 1359: my $bodytag = <<END; 1360: <body bgcolor="$pgbg" text="$font" alink="$alink" vlink="$vlink" link="$link" 1361: $addentries> 1362: END 1363: if ($bodyonly) { 1364: return $bodytag; 1365: } else { 1366: return(<<ENDBODY); 1367: $bodytag 1368: <table width="100%" cellspacing="0" border="0" cellpadding="0"> 1369: <tr><td bgcolor="$font"> 1370: <img src="$img" /></td> 1371: <td bgcolor="$font"><font color='$sidebg'>$messages</font></td> 1372: </tr> 1373: <tr> 1374: <td rowspan="3" bgcolor="$tabbg"> 1375: <font size="5"><b>$title</b></font> 1376: <td bgcolor="$tabbg" align="right"> 1377: <font size="2"> 1378: $ENV{'environment.firstname'} 1379: $ENV{'environment.middlename'} 1380: $ENV{'environment.lastname'} 1381: $ENV{'environment.generation'} 1382: </font> 1383: </td> 1384: </tr> 1385: <tr><td bgcolor="$tabbg" align="right"> 1386: <font size="2">$role</font> 1387: </td></tr> 1388: <tr> 1389: <td bgcolor="$tabbg" align="right"><font size="2">$realm</font> </td></tr> 1390: </table><br> 1391: ENDBODY 1392: } 1393: } 1394: ############################################### 1395: 1396: sub get_unprocessed_cgi { 1397: my ($query,$possible_names)= @_; 1398: # $Apache::lonxml::debug=1; 1399: foreach (split(/&/,$query)) { 1400: my ($name, $value) = split(/=/,$_); 1401: $name = &Apache::lonnet::unescape($name); 1402: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) { 1403: $value =~ tr/+/ /; 1404: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg; 1405: &Apache::lonxml::debug("Seting :$name: to :$value:"); 1406: unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) }; 1407: } 1408: } 1409: } 1410: 1411: sub cacheheader { 1412: unless ($ENV{'request.method'} eq 'GET') { return ''; } 1413: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime); 1414: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" /> 1415: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" /> 1416: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />'; 1417: return $output; 1418: } 1419: 1420: sub no_cache { 1421: my ($r) = @_; 1422: unless ($ENV{'request.method'} eq 'GET') { return ''; } 1423: #my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime); 1424: $r->no_cache(1); 1425: $r->header_out("Pragma" => "no-cache"); 1426: #$r->header_out("Expires" => $date); 1427: } 1428: 1429: sub add_to_env { 1430: my ($name,$value)=@_; 1431: if (defined($ENV{$name})) { 1432: if (ref($ENV{$name})) { 1433: #already have multiple values 1434: push(@{ $ENV{$name} },$value); 1435: } else { 1436: #first time seeing multiple values, convert hash entry to an arrayref 1437: my $first=$ENV{$name}; 1438: undef($ENV{$name}); 1439: push(@{ $ENV{$name} },$first,$value); 1440: } 1441: } else { 1442: $ENV{$name}=$value; 1443: } 1444: } 1445: 1446: =pod 1447: 1448: =back 1449: 1450: =head2 CSV Upload/Handling functions 1451: 1452: =over 4 1453: 1454: =item upfile_store($r) 1455: 1456: Store uploaded file, $r should be the HTTP Request object, 1457: needs $ENV{'form.upfile'} 1458: returns $datatoken to be put into hidden field 1459: 1460: =cut 1461: 1462: sub upfile_store { 1463: my $r=shift; 1464: $ENV{'form.upfile'}=~s/\r/\n/gs; 1465: $ENV{'form.upfile'}=~s/\f/\n/gs; 1466: $ENV{'form.upfile'}=~s/\n+/\n/gs; 1467: $ENV{'form.upfile'}=~s/\n+$//gs; 1468: 1469: my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}. 1470: '_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$; 1471: { 1472: my $fh=Apache::File->new('>'.$r->dir_config('lonDaemons'). 1473: '/tmp/'.$datatoken.'.tmp'); 1474: print $fh $ENV{'form.upfile'}; 1475: } 1476: return $datatoken; 1477: } 1478: 1479: =pod 1480: 1481: =item load_tmp_file($r) 1482: 1483: Load uploaded file from tmp, $r should be the HTTP Request object, 1484: needs $ENV{'form.datatoken'}, 1485: sets $ENV{'form.upfile'} to the contents of the file 1486: 1487: =cut 1488: 1489: sub load_tmp_file { 1490: my $r=shift; 1491: my @studentdata=(); 1492: { 1493: my $fh; 1494: if ($fh=Apache::File->new($r->dir_config('lonDaemons'). 1495: '/tmp/'.$ENV{'form.datatoken'}.'.tmp')) { 1496: @studentdata=<$fh>; 1497: } 1498: } 1499: $ENV{'form.upfile'}=join('',@studentdata); 1500: } 1501: 1502: =pod 1503: 1504: =item upfile_record_sep() 1505: 1506: Separate uploaded file into records 1507: returns array of records, 1508: needs $ENV{'form.upfile'} and $ENV{'form.upfiletype'} 1509: 1510: =cut 1511: 1512: sub upfile_record_sep { 1513: if ($ENV{'form.upfiletype'} eq 'xml') { 1514: } else { 1515: return split(/\n/,$ENV{'form.upfile'}); 1516: } 1517: } 1518: 1519: =pod 1520: 1521: =item record_sep($record) 1522: 1523: Separate a record into fields $record should be an item from the upfile_record_sep(), needs $ENV{'form.upfiletype'} 1524: 1525: =cut 1526: 1527: sub record_sep { 1528: my $record=shift; 1529: my %components=(); 1530: if ($ENV{'form.upfiletype'} eq 'xml') { 1531: } elsif ($ENV{'form.upfiletype'} eq 'space') { 1532: my $i=0; 1533: foreach (split(/\s+/,$record)) { 1534: my $field=$_; 1535: $field=~s/^(\"|\')//; 1536: $field=~s/(\"|\')$//; 1537: $components{$i}=$field; 1538: $i++; 1539: } 1540: } elsif ($ENV{'form.upfiletype'} eq 'tab') { 1541: my $i=0; 1542: foreach (split(/\t+/,$record)) { 1543: my $field=$_; 1544: $field=~s/^(\"|\')//; 1545: $field=~s/(\"|\')$//; 1546: $components{$i}=$field; 1547: $i++; 1548: } 1549: } else { 1550: my @allfields=split(/\,/,$record); 1551: my $i=0; 1552: my $j; 1553: for ($j=0;$j<=$#allfields;$j++) { 1554: my $field=$allfields[$j]; 1555: if ($field=~/^\s*(\"|\')/) { 1556: my $delimiter=$1; 1557: while (($field!~/$delimiter$/) && ($j<$#allfields)) { 1558: $j++; 1559: $field.=','.$allfields[$j]; 1560: } 1561: $field=~s/^\s*$delimiter//; 1562: $field=~s/$delimiter\s*$//; 1563: } 1564: $components{$i}=$field; 1565: $i++; 1566: } 1567: } 1568: return %components; 1569: } 1570: 1571: =pod 1572: 1573: =item upfile_select_html() 1574: 1575: return HTML code to select file and specify its type 1576: 1577: =cut 1578: 1579: sub upfile_select_html { 1580: return (<<'ENDUPFORM'); 1581: <input type="file" name="upfile" size="50" /> 1582: <br />Type: <select name="upfiletype"> 1583: <option value="csv">CSV (comma separated values, spreadsheet)</option> 1584: <option value="space">Space separated</option> 1585: <option value="tab">Tabulator separated</option> 1586: <option value="xml">HTML/XML</option> 1587: </select> 1588: ENDUPFORM 1589: } 1590: 1591: =pod 1592: 1593: =item csv_print_samples($r,$records) 1594: 1595: Prints a table of sample values from each column uploaded $r is an 1596: Apache Request ref, $records is an arrayref from 1597: &Apache::loncommon::upfile_record_sep 1598: 1599: =cut 1600: 1601: sub csv_print_samples { 1602: my ($r,$records) = @_; 1603: my (%sone,%stwo,%sthree); 1604: %sone=&record_sep($$records[0]); 1605: if (defined($$records[1])) {%stwo=&record_sep($$records[1]);} 1606: if (defined($$records[2])) {%sthree=&record_sep($$records[2]);} 1607: 1608: $r->print('Samples<br /><table border="2"><tr>'); 1609: foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<th>Column '.($_+1).'</th>'); } 1610: $r->print('</tr>'); 1611: foreach my $hash (\%sone,\%stwo,\%sthree) { 1612: $r->print('<tr>'); 1613: foreach (sort({$a <=> $b} keys(%sone))) { 1614: $r->print('<td>'); 1615: if (defined($$hash{$_})) { $r->print($$hash{$_}); } 1616: $r->print('</td>'); 1617: } 1618: $r->print('</tr>'); 1619: } 1620: $r->print('</tr></table><br />'."\n"); 1621: } 1622: 1623: =pod 1624: 1625: =item csv_print_select_table($r,$records,$d) 1626: 1627: Prints a table to create associations between values and table columns. 1628: $r is an Apache Request ref, 1629: $records is an arrayref from &Apache::loncommon::upfile_record_sep, 1630: $d is an array of 2 element arrays (internal name, displayed name) 1631: 1632: =cut 1633: 1634: sub csv_print_select_table { 1635: my ($r,$records,$d) = @_; 1636: my $i=0;my %sone; 1637: %sone=&record_sep($$records[0]); 1638: $r->print('Associate columns with student attributes.'."\n". 1639: '<table border="2"><tr><th>Attribute</th><th>Column</th></tr>'."\n"); 1640: foreach (@$d) { 1641: my ($value,$display)=@{ $_ }; 1642: $r->print('<tr><td>'.$display.'</td>'); 1643: 1644: $r->print('<td><select name=f'.$i. 1645: ' onchange="javascript:flip(this.form,'.$i.');">'); 1646: $r->print('<option value="none"></option>'); 1647: foreach (sort({$a <=> $b} keys(%sone))) { 1648: $r->print('<option value="'.$_.'">Column '.($_+1).'</option>'); 1649: } 1650: $r->print('</select></td></tr>'."\n"); 1651: $i++; 1652: } 1653: $i--; 1654: return $i; 1655: } 1656: 1657: =pod 1658: 1659: =item csv_samples_select_table($r,$records,$d) 1660: 1661: Prints a table of sample values from the upload and can make associate samples to internal names. 1662: 1663: $r is an Apache Request ref, 1664: $records is an arrayref from &Apache::loncommon::upfile_record_sep, 1665: $d is an array of 2 element arrays (internal name, displayed name) 1666: 1667: =cut 1668: 1669: sub csv_samples_select_table { 1670: my ($r,$records,$d) = @_; 1671: my %sone; my %stwo; my %sthree; 1672: my $i=0; 1673: 1674: $r->print('<table border=2><tr><th>Field</th><th>Samples</th></tr>'); 1675: %sone=&record_sep($$records[0]); 1676: if (defined($$records[1])) {%stwo=&record_sep($$records[1]);} 1677: if (defined($$records[2])) {%sthree=&record_sep($$records[2]);} 1678: 1679: foreach (sort keys %sone) { 1680: $r->print('<tr><td><select name=f'.$i. 1681: ' onchange="javascript:flip(this.form,'.$i.');">'); 1682: foreach (@$d) { 1683: my ($value,$display)=@{ $_ }; 1684: $r->print('<option value='.$value.'>'.$display.'</option>'); 1685: } 1686: $r->print('</select></td><td>'); 1687: if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); } 1688: if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); } 1689: if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); } 1690: $r->print('</td></tr>'); 1691: $i++; 1692: } 1693: $i--; 1694: return($i); 1695: } 1696: 1; 1697: __END__; 1698: 1699: =pod 1700: 1701: =back 1702: 1703: =head2 Access .tab File Data 1704: 1705: =over 4 1706: 1707: =item languageids() 1708: 1709: returns list of all language ids 1710: 1711: =item languagedescription() 1712: 1713: returns description of a specified language id 1714: 1715: =item copyrightids() 1716: 1717: returns list of all copyrights 1718: 1719: =item copyrightdescription() 1720: 1721: returns description of a specified copyright id 1722: 1723: =item filecategories() 1724: 1725: returns list of all file categories 1726: 1727: =item filecategorytypes() 1728: 1729: returns list of file types belonging to a given file 1730: category 1731: 1732: =item fileembstyle() 1733: 1734: returns embedding style for a specified file type 1735: 1736: =item filedescription() 1737: 1738: returns description for a specified file type 1739: 1740: =item filedescriptionex() 1741: 1742: returns description for a specified file type with 1743: extra formatting 1744: 1745: =back 1746: 1747: =head2 Alternate Problem Views 1748: 1749: =over 4 1750: 1751: =item get_previous_attempt() 1752: 1753: return string with previous attempt on problem 1754: 1755: =item get_student_view() 1756: 1757: show a snapshot of what student was looking at 1758: 1759: =item get_student_answers() 1760: 1761: show a snapshot of how student was answering problem 1762: 1763: =back 1764: 1765: =head2 HTTP Helper 1766: 1767: =over 4 1768: 1769: =item get_unprocessed_cgi($query,$possible_names) 1770: 1771: Modify the %ENV hash to contain unprocessed CGI form parameters held in 1772: $query. The parameters listed in $possible_names (an array reference), 1773: will be set in $ENV{'form.name'} if they do not already exist. 1774: 1775: Typically called with $ENV{'QUERY_STRING'} as the first parameter. 1776: $possible_names is an ref to an array of form element names. As an example: 1777: get_unprocessed_cgi($ENV{'QUERY_STRING'},['uname','udom']); 1778: will result in $ENV{'form.uname'} and $ENV{'form.udom'} being set. 1779: 1780: =item cacheheader() 1781: 1782: returns cache-controlling header code 1783: 1784: =item no_cache($r) 1785: 1786: specifies header code to not have cache 1787: 1788: =item add_to_env($name,$value) 1789: 1790: adds $name to the %ENV hash with value 1791: $value, if $name already exists, the entry is converted to an array 1792: reference and $value is added to the array. 1793: 1794: =back 1795: 1796: =cut