Annotation of loncom/interface/loncommon.pm, revision 1.35
1.10 albertel 1: # The LearningOnline Network with CAPA
1.1 albertel 2: # a pile of common routines
1.10 albertel 3: #
1.35 ! matthew 4: # $Id: loncommon.pm,v 1.34 2002/04/23 21:00:01 matthew 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.12 harris41 28: # YEAR=2001
29: # 2/13-12/7 Guy Albertelli
1.17 harris41 30: # 12/11,12/12,12/17 Scott Harrison
1.18 www 31: # 12/21 Gerd Kortemeyer
1.20 www 32: # 12/21 Scott Harrison
1.22 www 33: # 12/25,12/28 Gerd Kortemeyer
1.23 www 34: # YEAR=2002
35: # 1/4 Gerd Kortemeyer
1.1 albertel 36:
37: # Makes a table out of the previous attempts
1.2 albertel 38: # Inputs result_from_symbread, user, domain, course_id
1.16 harris41 39: # Reads in non-network-related .tab files
1.1 albertel 40:
1.35 ! matthew 41: # POD header:
! 42:
! 43: =head1 NAME
! 44:
! 45: Apache::loncommon - pile of common routines
! 46:
! 47: =head1 SYNOPSIS
! 48:
! 49: Referenced by other mod_perl Apache modules.
! 50:
! 51: Invocation:
! 52: &Apache::loncommon::SUBROUTINENAME(ARGUMENTS);
! 53:
! 54: =head1 INTRODUCTION
! 55:
! 56: Common collection of used subroutines. This collection helps remove
! 57: redundancy from other modules and increase efficiency of memory usage.
! 58:
! 59: Current things done:
! 60:
! 61: Makes a table out of the previous homework attempts
! 62: Inputs result_from_symbread, user, domain, course_id
! 63: Reads in non-network-related .tab files
! 64:
! 65: This is part of the LearningOnline Network with CAPA project
! 66: described at http://www.lon-capa.org.
! 67:
! 68: =head2 Subroutines
! 69:
! 70: =over 4
! 71:
! 72: =cut
! 73:
! 74: # End of POD header
1.1 albertel 75: package Apache::loncommon;
76:
77: use strict;
1.22 www 78: use Apache::lonnet();
1.8 albertel 79: use POSIX qw(strftime);
1.1 albertel 80: use Apache::Constants qw(:common);
81: use Apache::lonmsg();
1.12 harris41 82:
1.22 www 83: my $readit;
84:
1.20 www 85: # ----------------------------------------------- Filetypes/Languages/Copyright
1.12 harris41 86: my %language;
87: my %cprtag;
88: my %fe; my %fd;
1.15 harris41 89: my %fc;
1.12 harris41 90:
1.20 www 91: # -------------------------------------------------------------- Thesaurus data
1.21 www 92: my @therelated;
93: my @theword;
94: my @thecount;
95: my %theindex;
96: my $thetotalcount;
1.20 www 97: my $thefuzzy=2;
98: my $thethreshold=0.1/$thefuzzy;
99: my $theavecount;
100:
1.12 harris41 101: # ----------------------------------------------------------------------- BEGIN
1.35 ! matthew 102: =item BEGIN()
! 103:
! 104: Initialize values from language.tab, copyright.tab, filetypes.tab,
! 105: and filecategories.tab.
! 106:
! 107: =cut
! 108: # ----------------------------------------------------------------------- BEGIN
! 109:
1.18 www 110: BEGIN {
1.22 www 111:
112: unless ($readit) {
1.12 harris41 113: # ------------------------------------------------------------------- languages
114: {
115: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
116: '/language.tab');
1.16 harris41 117: if ($fh) {
118: while (<$fh>) {
119: next if /^\#/;
120: chomp;
121: my ($key,$val)=(split(/\s+/,$_,2));
122: $language{$key}=$val;
123: }
1.12 harris41 124: }
125: }
126: # ------------------------------------------------------------------ copyrights
127: {
1.16 harris41 128: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonIncludes'}.
129: '/copyright.tab');
130: if ($fh) {
131: while (<$fh>) {
132: next if /^\#/;
133: chomp;
134: my ($key,$val)=(split(/\s+/,$_,2));
135: $cprtag{$key}=$val;
136: }
1.12 harris41 137: }
138: }
1.15 harris41 139: # ------------------------------------------------------------- file categories
140: {
141: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
1.16 harris41 142: '/filecategories.tab');
143: if ($fh) {
144: while (<$fh>) {
145: next if /^\#/;
146: chomp;
147: my ($key,$val)=(split(/\s+/,$_,2));
148: push @{$fc{$key}},$val;
149: }
1.15 harris41 150: }
151: }
1.12 harris41 152: # ------------------------------------------------------------------ file types
153: {
1.16 harris41 154: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
155: '/filetypes.tab');
156: if ($fh) {
157: while (<$fh>) {
158: next if (/^\#/);
159: chomp;
160: my ($ending,$emb,$descr)=split(/\s+/,$_,3);
161: if ($descr ne '') {
162: $fe{$ending}=lc($emb);
163: $fd{$ending}=$descr;
164: }
1.12 harris41 165: }
166: }
167: }
1.20 www 168: # -------------------------------------------------------------- Thesaurus data
169: {
170: my $fh=Apache::File->new($Apache::lonnet::perlvar{'lonTabDir'}.
171: '/thesaurus.dat');
172: if ($fh) {
173: while (<$fh>) {
174: my ($tword,$tindex,$tcount,$trelated)=split(/\@/,$_);
175: $theindex{$tword}=$tindex;
176: $theword[$tindex]=$tword;
177: $thecount[$tindex]=$tcount;
178: $thetotalcount+=$tcount;
179: $therelated[$tindex]=$trelated;
180: }
181: }
182: $theavecount=$thetotalcount/$#thecount;
183: }
1.22 www 184: &Apache::lonnet::logthis(
185: "<font color=yellow>INFO: Read file types and thesaurus</font>");
186: $readit=1;
187: }
1.32 matthew 188:
189: }
190: # ============================================================= END BEGIN BLOCK
1.33 matthew 191: ###############################################################
192: ## Home server <option> list generating code ##
193: ###############################################################
1.35 ! matthew 194: #-------------------------------------------
! 195:
! 196: =item get_domains()
! 197:
! 198: Returns an array containing each of the domains listed in the hosts.tab
! 199: file.
! 200:
! 201: =cut
! 202:
! 203: #-------------------------------------------
1.34 matthew 204: sub get_domains {
205: # The code below was stolen from "The Perl Cookbook", p 102, 1st ed.
206: my @domains;
207: my %seen;
208: foreach (sort values(%Apache::lonnet::hostdom)) {
209: push (@domains,$_) unless $seen{$_}++;
210: }
211: return @domains;
212: }
213:
1.35 ! matthew 214: #-------------------------------------------
! 215:
! 216: =item select_dom_form($defdom,$name)
! 217:
! 218: Returns a string containing a <select name='$name' size='1'> form to
! 219: allow a user to select the domain to preform an operation in.
! 220: See loncreateuser.pm for an example invocation and use.
! 221:
! 222: =cut
! 223:
! 224: #-------------------------------------------
1.34 matthew 225: sub select_dom_form {
226: my ($defdom,$name) = @_;
227: my @domains = get_domains();
228: my $selectdomain = "<select name=\"$name\" size=\"1\">\n";
229: foreach (@domains) {
230: $selectdomain.="<option value=\"$_\" ".
231: ($_ eq $defdom ? 'selected' : '').
232: ">$_</option>\n";
233: }
234: $selectdomain.="</select>";
235: return $selectdomain;
236: }
237:
1.35 ! matthew 238: #-------------------------------------------
! 239:
! 240: =item get_home_servers($domain)
! 241:
! 242: Returns a hash which contains keys like '103l3' and values like
! 243: 'kirk.lite.msu.edu'. All of the keys will be for machines in the
! 244: given $domain.
! 245:
! 246: =cut
! 247:
! 248: #-------------------------------------------
1.33 matthew 249: sub get_home_servers {
250: my $domain = shift;
251: my %home_servers;
252: foreach (keys(%Apache::lonnet::libserv)) {
253: if ($Apache::lonnet::hostdom{$_} eq $domain) {
254: $home_servers{$_} = $Apache::lonnet::hostname{$_};
255: }
256: }
257: return %home_servers;
258: }
259:
1.35 ! matthew 260: #-------------------------------------------
! 261:
! 262: =item home_server_option_list($domain)
! 263:
! 264: returns a string which contains an <option> list to be used in a
! 265: <select> form input. See loncreateuser.pm for an example.
! 266:
! 267: =cut
! 268:
! 269: #-------------------------------------------
1.33 matthew 270: sub home_server_option_list {
271: my $domain = shift;
272: my %servers = &get_home_servers($domain);
273: my $result = '';
274: foreach (sort keys(%servers)) {
275: $result.=
276: '<option value="'.$_.'">'.$_.' '.$servers{$_}."</option>\n";
277: }
278: return $result;
279: }
280: ###############################################################
281: ## End of home server <option> list generating code ##
282: ###############################################################
1.32 matthew 283:
284: ###############################################################
285: ## Authentication changing form generation subroutines ##
286: ###############################################################
287: ##
288: ## All of the authform_xxxxxxx subroutines take their inputs in a
289: ## hash, and have reasonable default values.
290: ##
291: ## formname = the name given in the <form> tag.
1.35 ! matthew 292: #-------------------------------------------
! 293:
! 294: =item authform_xxxxxx
! 295:
! 296: The authform_xxxxxx subroutines provide javascript and html forms which
! 297: handle some of the conveniences required for authentication forms.
! 298: This is not an optimal method, but it works.
! 299:
! 300: See loncreateuser.pm for invocation and use examples.
! 301:
! 302: =over 4
! 303:
! 304: =item authform_header
! 305:
! 306: =item authform_authorwarning
! 307:
! 308: =item authform_nochange
! 309:
! 310: =item authform_kerberos
! 311:
! 312: =item authform_internal
! 313:
! 314: =item authform_filesystem
! 315:
! 316: =back
! 317:
! 318: =cut
! 319:
! 320: #-------------------------------------------
1.32 matthew 321: sub authform_header{
322: my %in = (
323: formname => 'cu',
324: kerb_def_dom => 'MSU.EDU',
325: @_,
326: );
327: $in{'formname'} = 'document.' . $in{'formname'};
328: my $result='';
329: $result.=<<"END";
330: var current = new Object();
331: current.radiovalue = 'nochange';
332: current.argfield = null;
333:
334: function changed_radio(choice,currentform) {
335: var choicearg = choice + 'arg';
336: // If a radio button in changed, we need to change the argfield
337: if (current.radiovalue != choice) {
338: current.radiovalue = choice;
339: if (current.argfield != null) {
340: currentform.elements[current.argfield].value = '';
341: }
342: if (choice == 'nochange') {
343: current.argfield = null;
344: } else {
345: current.argfield = choicearg;
346: switch(choice) {
347: case 'krb':
348: currentform.elements[current.argfield].value =
349: "$in{'kerb_def_dom'}";
350: break;
351: default:
352: break;
353: }
354: }
355: }
356: return;
357: }
1.22 www 358:
1.32 matthew 359: function changed_text(choice,currentform) {
360: var choicearg = choice + 'arg';
361: if (currentform.elements[choicearg].value !='') {
362: switch (choice) {
363: case 'krb': currentform.elements[choicearg].value =
364: currentform.elements[choicearg].value.toUpperCase();
365: break;
366: default:
367: }
368: // clear old field
369: if ((current.argfield != choicearg) && (current.argfield != null)) {
370: currentform.elements[current.argfield].value = '';
371: }
372: current.argfield = choicearg;
373: }
374: set_auth_radio_buttons(choice,currentform);
375: return;
1.20 www 376: }
1.32 matthew 377:
378: function set_auth_radio_buttons(newvalue,currentform) {
379: var i=0;
380: while (i < currentform.login.length) {
381: if (currentform.login[i].value == newvalue) { break; }
382: i++;
383: }
384: if (i == currentform.login.length) {
385: return;
386: }
387: current.radiovalue = newvalue;
388: currentform.login[i].checked = true;
389: return;
390: }
391: END
392: return $result;
393: }
394:
395: sub authform_authorwarning{
396: my $result='';
397: $result=<<"END";
398: <i>As a general rule, only authors or co-authors should be filesystem
399: authenticated (which allows access to the server filesystem).</i>
400: END
401: return $result;
402: }
403:
404: sub authform_nochange{
405: my %in = (
406: formname => 'document.cu',
407: kerb_def_dom => 'MSU.EDU',
408: @_,
409: );
410: my $result='';
411: $result.=<<"END";
412: <input type="radio" name="login" value="nochange" checked="checked"
413: onclick="javascript:changed_radio('nochange',$in{'formname'});">
414: Do not change login data
415: END
416: return $result;
417: }
418:
419: sub authform_kerberos{
420: my %in = (
421: formname => 'document.cu',
422: kerb_def_dom => 'MSU.EDU',
423: @_,
424: );
425: my $result='';
426: $result.=<<"END";
427: <input type="radio" name="login" value="krb"
428: onclick="javascript:changed_radio('krb',$in{'formname'});"
429: onchange="javascript:changed_radio('krb',$in{'formname'});">
430: Kerberos authenticated with domain
431: <input type="text" size="10" name="krbarg" value=""
432: onchange="javascript:changed_text('krb',$in{'formname'});">
433: END
434: return $result;
435: }
436:
437: sub authform_internal{
438: my %args = (
439: formname => 'document.cu',
440: kerb_def_dom => 'MSU.EDU',
441: @_,
442: );
443: my $result='';
444: $result.=<<"END";
445: <input type="radio" name="login" value="int"
446: onchange="javascript:changed_radio('int',$args{'formname'});"
447: onclick="javascript:changed_radio('int',$args{'formname'});">
448: Internally authenticated (with initial password
449: <input type="text" size="10" name="intarg" value=""
450: onchange="javascript:changed_text('int',$args{'formname'});">
451: END
452: return $result;
453: }
454:
455: sub authform_local{
456: my %in = (
457: formname => 'document.cu',
458: kerb_def_dom => 'MSU.EDU',
459: @_,
460: );
461: my $result='';
462: $result.=<<"END";
463: <input type="radio" name="login" value="loc"
464: onchange="javascript:changed_radio('loc',$in{'formname'});"
465: onclick="javascript:changed_radio('loc',$in{'formname'});">
466: Local Authentication with argument
467: <input type="text" size="10" name="locarg" value=""
468: onchange="javascript:changed_text('loc',$in{'formname'});">
469: END
470: return $result;
471: }
472:
473: sub authform_filesystem{
474: my %in = (
475: formname => 'document.cu',
476: kerb_def_dom => 'MSU.EDU',
477: @_,
478: );
479: my $result='';
480: $result.=<<"END";
481: <input type="radio" name="login" value="fsys"
482: onchange="javascript:changed_radio('fsys',$in{'formname'});"
483: onclick="javascript:changed_radio('fsys',$in{'formname'});">
484: Filesystem authenticated (with initial password
485: <input type="text" size="10" name="fsysarg" value=""
486: onchange="javascript:changed_text('fsys',$in{'formname'});">
487: END
488: return $result;
489: }
490:
491: ###############################################################
492: ## End Authentication changing form generation functions ##
493: ###############################################################
494:
1.20 www 495:
496:
497: # ---------------------------------------------------------- Is this a keyword?
498:
499: sub keyword {
500: my $newword=shift;
501: $newword=~s/\W//g;
502: $newword=~tr/A-Z/a-z/;
503: my $tindex=$theindex{$newword};
504: if ($tindex) {
505: if ($thecount[$tindex]>$theavecount) {
506: return 1;
507: }
508: }
509: return 0;
510: }
511: # -------------------------------------------------------- Return related words
512:
513: sub related {
514: my $newword=shift;
515: $newword=~s/\W//g;
516: $newword=~tr/A-Z/a-z/;
517: my $tindex=$theindex{$newword};
518: if ($tindex) {
519: my %found=();
520: foreach (split(/\,/,$therelated[$tindex])) {
521: # - Related word found
522: my ($ridx,$rcount)=split(/\:/,$_);
523: # - Direct relation index
524: my $directrel=$rcount/$thecount[$tindex];
525: if ($directrel>$thethreshold) {
526: foreach (split(/\,/,$therelated[$ridx])) {
527: my ($rridx,$rrcount)=split(/\:/,$_);
528: if ($rridx==$tindex) {
529: # - Determine reverse relation index
530: my $revrel=$rrcount/$thecount[$ridx];
531: # - Calculate full index
532: $found{$ridx}=$directrel*$revrel;
533: if ($found{$ridx}>$thethreshold) {
534: foreach (split(/\,/,$therelated[$ridx])) {
535: my ($rrridx,$rrrcount)=split(/\:/,$_);
536: unless ($found{$rrridx}) {
537: my $revrevrel=$rrrcount/$thecount[$ridx];
538: if (
539: $directrel*$revrel*$revrevrel>$thethreshold
540: ) {
541: $found{$rrridx}=
542: $directrel*$revrel*$revrevrel;
543: }
544: }
545: }
546: }
547: }
548: }
549: }
550: }
551: }
552: return ();
1.14 harris41 553: }
554:
555: # ---------------------------------------------------------------- Language IDs
556: sub languageids {
1.16 harris41 557: return sort(keys(%language));
1.14 harris41 558: }
559:
560: # -------------------------------------------------------- Language Description
561: sub languagedescription {
1.16 harris41 562: return $language{shift(@_)};
1.14 harris41 563: }
564:
565: # --------------------------------------------------------------- Copyright IDs
566: sub copyrightids {
1.16 harris41 567: return sort(keys(%cprtag));
1.14 harris41 568: }
569:
570: # ------------------------------------------------------- Copyright Description
571: sub copyrightdescription {
1.16 harris41 572: return $cprtag{shift(@_)};
1.14 harris41 573: }
574:
575: # ------------------------------------------------------------- File Categories
576: sub filecategories {
1.16 harris41 577: return sort(keys(%fc));
1.15 harris41 578: }
1.14 harris41 579:
1.17 harris41 580: # -------------------------------------- File Types within a specified category
1.15 harris41 581: sub filecategorytypes {
1.16 harris41 582: return @{$fc{lc(shift(@_))}};
1.14 harris41 583: }
584:
585: # ------------------------------------------------------------------ File Types
586: sub fileextensions {
1.16 harris41 587: return sort(keys(%fe));
1.14 harris41 588: }
589:
590: # ------------------------------------------------------------- Embedding Style
591: sub fileembstyle {
1.16 harris41 592: return $fe{lc(shift(@_))};
1.14 harris41 593: }
594:
595: # ------------------------------------------------------------ Description Text
596: sub filedescription {
1.16 harris41 597: return $fd{lc(shift(@_))};
598: }
599:
600: # ------------------------------------------------------------ Description Text
601: sub filedescriptionex {
602: my $ex=shift;
603: return '.'.$ex.' '.$fd{lc($ex)};
1.12 harris41 604: }
1.1 albertel 605:
606: sub get_previous_attempt {
1.2 albertel 607: my ($symb,$username,$domain,$course)=@_;
1.1 albertel 608: my $prevattempts='';
609: if ($symb) {
1.3 albertel 610: my (%returnhash)=
611: &Apache::lonnet::restore($symb,$course,$domain,$username);
1.1 albertel 612: if ($returnhash{'version'}) {
613: my %lasthash=();
614: my $version;
615: for ($version=1;$version<=$returnhash{'version'};$version++) {
1.19 harris41 616: foreach (sort(split(/\:/,$returnhash{$version.':keys'}))) {
1.1 albertel 617: $lasthash{$_}=$returnhash{$version.':'.$_};
1.19 harris41 618: }
1.1 albertel 619: }
620: $prevattempts='<table border=2></tr><th>History</th>';
1.16 harris41 621: foreach (sort(keys %lasthash)) {
1.31 albertel 622: my ($ign,@parts) = split(/\./,$_);
623: if (@parts) {
624: my $data=$parts[-1];
625: pop(@parts);
626: $prevattempts.='<th>Part '.join('.',@parts).'<br />'.$data.'</th>';
627: } else {
628: $prevattempts.='<th>'.$ign.'</th>';
629: }
1.16 harris41 630: }
1.1 albertel 631: for ($version=1;$version<=$returnhash{'version'};$version++) {
632: $prevattempts.='</tr><tr><th>Attempt '.$version.'</th>';
1.16 harris41 633: foreach (sort(keys %lasthash)) {
1.5 albertel 634: my $value;
635: if ($_ =~ /timestamp/) {
636: $value=scalar(localtime($returnhash{$version.':'.$_}));
637: } else {
638: $value=$returnhash{$version.':'.$_};
639: }
640: $prevattempts.='<td>'.$value.'</td>';
1.16 harris41 641: }
1.1 albertel 642: }
643: $prevattempts.='</tr><tr><th>Current</th>';
1.16 harris41 644: foreach (sort(keys %lasthash)) {
1.5 albertel 645: my $value;
646: if ($_ =~ /timestamp/) {
647: $value=scalar(localtime($lasthash{$_}));
648: } else {
649: $value=$lasthash{$_};
650: }
651: $prevattempts.='<td>'.$value.'</td>';
1.16 harris41 652: }
1.1 albertel 653: $prevattempts.='</tr></table>';
654: } else {
655: $prevattempts='Nothing submitted - no attempts.';
656: }
657: } else {
658: $prevattempts='No data.';
659: }
1.10 albertel 660: }
661:
662: sub get_student_view {
663: my ($symb,$username,$domain,$courseid) = @_;
664: my ($map,$id,$feedurl) = split(/___/,$symb);
665: my (%old,%moreenv);
666: my @elements=('symb','courseid','domain','username');
667: foreach my $element (@elements) {
668: $old{$element}=$ENV{'form.grade_'.$element};
669: $moreenv{'form.grade_'.$element}=eval '$'.$element #'
670: }
1.11 albertel 671: &Apache::lonnet::appenv(%moreenv);
672: my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
673: &Apache::lonnet::delenv('form.grade_');
674: foreach my $element (@elements) {
675: $ENV{'form.grade_'.$element}=$old{$element};
676: }
677: $userview=~s/\<body[^\>]*\>//gi;
678: $userview=~s/\<\/body\>//gi;
679: $userview=~s/\<html\>//gi;
680: $userview=~s/\<\/html\>//gi;
681: $userview=~s/\<head\>//gi;
682: $userview=~s/\<\/head\>//gi;
683: $userview=~s/action\s*\=/would_be_action\=/gi;
684: return $userview;
685: }
686:
687: sub get_student_answers {
688: my ($symb,$username,$domain,$courseid) = @_;
689: my ($map,$id,$feedurl) = split(/___/,$symb);
690: my (%old,%moreenv);
691: my @elements=('symb','courseid','domain','username');
692: foreach my $element (@elements) {
693: $old{$element}=$ENV{'form.grade_'.$element};
694: $moreenv{'form.grade_'.$element}=eval '$'.$element #'
695: }
696: $moreenv{'form.grade_target'}='answer';
1.10 albertel 697: &Apache::lonnet::appenv(%moreenv);
698: my $userview=&Apache::lonnet::ssi('/res/'.$feedurl);
699: &Apache::lonnet::delenv('form.grade_');
700: foreach my $element (@elements) {
701: $ENV{'form.grade_'.$element}=$old{$element};
702: }
703: $userview=~s/\<body[^\>]*\>//gi;
704: $userview=~s/\<\/body\>//gi;
705: $userview=~s/\<html\>//gi;
706: $userview=~s/\<\/html\>//gi;
707: $userview=~s/\<head\>//gi;
708: $userview=~s/\<\/head\>//gi;
709: $userview=~s/action\s*\=/would_be_action\=/gi;
710: return $userview;
1.1 albertel 711: }
712:
1.6 albertel 713: sub get_unprocessed_cgi {
1.25 albertel 714: my ($query,$possible_names)= @_;
1.26 matthew 715: # $Apache::lonxml::debug=1;
1.16 harris41 716: foreach (split(/&/,$query)) {
1.6 albertel 717: my ($name, $value) = split(/=/,$_);
1.25 albertel 718: $name = &Apache::lonnet::unescape($name);
719: if (!defined($possible_names) || (grep {$_ eq $name} @$possible_names)) {
720: $value =~ tr/+/ /;
721: $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
722: &Apache::lonxml::debug("Seting :$name: to :$value:");
1.30 albertel 723: unless (defined($ENV{'form.'.$name})) { &add_to_env('form.'.$name,$value) };
1.25 albertel 724: }
1.16 harris41 725: }
1.6 albertel 726: }
727:
1.7 albertel 728: sub cacheheader {
1.23 www 729: unless ($ENV{'request.method'} eq 'GET') { return ''; }
1.8 albertel 730: my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
1.7 albertel 731: my $output .='<meta HTTP-EQUIV="Expires" CONTENT="'.$date.'" />
732: <meta HTTP-EQUIV="Cache-control" CONTENT="no-cache" />
733: <meta HTTP-EQUIV="Pragma" CONTENT="no-cache" />';
734: return $output;
735: }
736:
1.9 albertel 737: sub no_cache {
738: my ($r) = @_;
1.23 www 739: unless ($ENV{'request.method'} eq 'GET') { return ''; }
1.24 albertel 740: #my $date=strftime("%a, %d %b %Y %H:%M:%S GMT",gmtime);
1.9 albertel 741: $r->no_cache(1);
742: $r->header_out("Pragma" => "no-cache");
1.24 albertel 743: #$r->header_out("Expires" => $date);
1.9 albertel 744: }
1.25 albertel 745:
746: sub add_to_env {
747: my ($name,$value)=@_;
1.28 albertel 748: if (defined($ENV{$name})) {
1.27 albertel 749: if (ref($ENV{$name})) {
1.25 albertel 750: #already have multiple values
751: push(@{ $ENV{$name} },$value);
752: } else {
753: #first time seeing multiple values, convert hash entry to an arrayref
754: my $first=$ENV{$name};
755: undef($ENV{$name});
756: push(@{ $ENV{$name} },$first,$value);
757: }
758: } else {
759: $ENV{$name}=$value;
760: }
1.31 albertel 761: }
762:
763: #---CSV Upload/Handling functions
764:
765: # ========================================================= Store uploaded file
766: # needs $ENV{'form.upfile'}
767: # return $datatoken to be put into hidden field
768:
769: sub upfile_store {
770: my $r=shift;
771: $ENV{'form.upfile'}=~s/\r/\n/gs;
772: $ENV{'form.upfile'}=~s/\f/\n/gs;
773: $ENV{'form.upfile'}=~s/\n+/\n/gs;
774: $ENV{'form.upfile'}=~s/\n+$//gs;
775:
776: my $datatoken=$ENV{'user.name'}.'_'.$ENV{'user.domain'}.
777: '_enroll_'.$ENV{'request.course.id'}.'_'.time.'_'.$$;
778: {
779: my $fh=Apache::File->new('>'.$r->dir_config('lonDaemons').
780: '/tmp/'.$datatoken.'.tmp');
781: print $fh $ENV{'form.upfile'};
782: }
783: return $datatoken;
784: }
785:
786: # ================================================= Load uploaded file from tmp
787: # needs $ENV{'form.datatoken'}
788: # sets $ENV{'form.upfile'} to the contents of the file
789:
790: sub load_tmp_file {
791: my $r=shift;
792: my @studentdata=();
793: {
794: my $fh;
795: if ($fh=Apache::File->new($r->dir_config('lonDaemons').
796: '/tmp/'.$ENV{'form.datatoken'}.'.tmp')) {
797: @studentdata=<$fh>;
798: }
799: }
800: $ENV{'form.upfile'}=join('',@studentdata);
801: }
802:
803: # ========================================= Separate uploaded file into records
804: # returns array of records
805: # needs $ENV{'form.upfile'}
806: # needs $ENV{'form.upfiletype'}
807:
808: sub upfile_record_sep {
809: if ($ENV{'form.upfiletype'} eq 'xml') {
810: } else {
811: return split(/\n/,$ENV{'form.upfile'});
812: }
813: }
814:
815: # =============================================== Separate a record into fields
816: # needs $ENV{'form.upfiletype'}
817: # takes $record as arg
818: sub record_sep {
819: my $record=shift;
820: my %components=();
821: if ($ENV{'form.upfiletype'} eq 'xml') {
822: } elsif ($ENV{'form.upfiletype'} eq 'space') {
823: my $i=0;
824: foreach (split(/\s+/,$record)) {
825: my $field=$_;
826: $field=~s/^(\"|\')//;
827: $field=~s/(\"|\')$//;
828: $components{$i}=$field;
829: $i++;
830: }
831: } elsif ($ENV{'form.upfiletype'} eq 'tab') {
832: my $i=0;
833: foreach (split(/\t+/,$record)) {
834: my $field=$_;
835: $field=~s/^(\"|\')//;
836: $field=~s/(\"|\')$//;
837: $components{$i}=$field;
838: $i++;
839: }
840: } else {
841: my @allfields=split(/\,/,$record);
842: my $i=0;
843: my $j;
844: for ($j=0;$j<=$#allfields;$j++) {
845: my $field=$allfields[$j];
846: if ($field=~/^\s*(\"|\')/) {
847: my $delimiter=$1;
848: while (($field!~/$delimiter$/) && ($j<$#allfields)) {
849: $j++;
850: $field.=','.$allfields[$j];
851: }
852: $field=~s/^\s*$delimiter//;
853: $field=~s/$delimiter\s*$//;
854: }
855: $components{$i}=$field;
856: $i++;
857: }
858: }
859: return %components;
860: }
861:
862: # =============================== HTML code to select file and specify its type
863: sub upfile_select_html {
864: return (<<'ENDUPFORM');
865: <input type="file" name="upfile" size="50">
866: <br />Type: <select name="upfiletype">
867: <option value="csv">CSV (comma separated values, spreadsheet)</option>
868: <option value="space">Space separated</option>
869: <option value="tab">Tabulator separated</option>
870: <option value="xml">HTML/XML</option>
871: </select>
872: ENDUPFORM
873: }
874:
875: # ===================Prints a table of sample values from each column uploaded
876: # $r is an Apache Request ref
877: # $records is an arrayref from &Apache::loncommon::upfile_record_sep
878: sub csv_print_samples {
879: my ($r,$records) = @_;
880: my (%sone,%stwo,%sthree);
881: %sone=&record_sep($$records[0]);
882: if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
883: if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
884:
885: $r->print('Samples<br /><table border="2"><tr>');
886: foreach (sort({$a <=> $b} keys(%sone))) { $r->print('<th>Column '.($_+1).'</th>'); }
887: $r->print('</tr>');
888: foreach my $hash (\%sone,\%stwo,\%sthree) {
889: $r->print('<tr>');
890: foreach (sort({$a <=> $b} keys(%sone))) {
891: $r->print('<td>');
892: if (defined($$hash{$_})) { $r->print($$hash{$_}); }
893: $r->print('</td>');
894: }
895: $r->print('</tr>');
896: }
897: $r->print('</tr></table><br />'."\n");
898: }
899:
900: # ======Prints a table to create associations between values and table columns
901: # $r is an Apache Request ref
902: # $records is an arrayref from &Apache::loncommon::upfile_record_sep
903: # $d is an array of 2 element arrays (internal name, displayed name)
904: sub csv_print_select_table {
905: my ($r,$records,$d) = @_;
906: my $i=0;my %sone;
907: %sone=&record_sep($$records[0]);
908: $r->print('Associate columns with student attributes.'."\n".
909: '<table border="2"><tr><th>Attribute</th><th>Column</th></tr>'."\n");
910: foreach (@$d) {
911: my ($value,$display)=@{ $_ };
912: $r->print('<tr><td>'.$display.'</td>');
913:
914: $r->print('<td><select name=f'.$i.
1.32 matthew 915: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 916: $r->print('<option value="none"></option>');
917: foreach (sort({$a <=> $b} keys(%sone))) {
918: $r->print('<option value="'.$_.'">Column '.($_+1).'</option>');
919: }
920: $r->print('</select></td></tr>'."\n");
921: $i++;
922: }
923: $i--;
924: return $i;
925: }
926:
927: # ===================Prints a table of sample values from the upload and
928: # can make associate samples to internal names
929: # $r is an Apache Request ref
930: # $records is an arrayref from &Apache::loncommon::upfile_record_sep
931: # $d is an array of 2 element arrays (internal name, displayed name)
932: sub csv_samples_select_table {
933: my ($r,$records,$d) = @_;
934: my %sone; my %stwo; my %sthree;
935: my $i=0;
936:
937: $r->print('<table border=2><tr><th>Field</th><th>Samples</th></tr>');
938: %sone=&record_sep($$records[0]);
939: if (defined($$records[1])) {%stwo=&record_sep($$records[1]);}
940: if (defined($$records[2])) {%sthree=&record_sep($$records[2]);}
941:
942: foreach (sort keys %sone) {
943: $r->print('<tr><td><select name=f'.$i.
1.32 matthew 944: ' onchange="javascript:flip(this.form,'.$i.');">');
1.31 albertel 945: foreach (@$d) {
946: my ($value,$display)=@{ $_ };
947: $r->print('<option value='.$value.'>'.$display.'</option>');
948: }
949: $r->print('</select></td><td>');
950: if (defined($sone{$_})) { $r->print($sone{$_}."</br>\n"); }
951: if (defined($stwo{$_})) { $r->print($stwo{$_}."</br>\n"); }
952: if (defined($sthree{$_})) { $r->print($sthree{$_}."</br>\n"); }
953: $r->print('</td></tr>');
954: $i++;
955: }
956: $i--;
957: return($i);
1.25 albertel 958: }
1.1 albertel 959: 1;
960: __END__;
1.17 harris41 961:
1.35 ! matthew 962: =item languageids()
1.17 harris41 963:
1.35 ! matthew 964: returns list of all language ids
1.17 harris41 965:
1.35 ! matthew 966: =item languagedescription()
1.17 harris41 967:
1.35 ! matthew 968: returns description of a specified language id
1.17 harris41 969:
1.35 ! matthew 970: =item copyrightids()
1.17 harris41 971:
1.35 ! matthew 972: returns list of all copyrights
1.17 harris41 973:
1.35 ! matthew 974: =item copyrightdescription()
1.17 harris41 975:
1.35 ! matthew 976: returns description of a specified copyright id
1.17 harris41 977:
1.35 ! matthew 978: =item filecategories()
1.17 harris41 979:
1.35 ! matthew 980: returns list of all file categories
1.17 harris41 981:
1.35 ! matthew 982: =item filecategorytypes()
1.17 harris41 983:
1.35 ! matthew 984: returns list of file types belonging to a given file
1.17 harris41 985: category
986:
1.35 ! matthew 987: =item fileembstyle()
1.17 harris41 988:
1.35 ! matthew 989: returns embedding style for a specified file type
1.17 harris41 990:
1.35 ! matthew 991: =item filedescription()
1.17 harris41 992:
1.35 ! matthew 993: returns description for a specified file type
1.17 harris41 994:
1.35 ! matthew 995: =item filedescriptionex()
1.17 harris41 996:
1.35 ! matthew 997: returns description for a specified file type with
1.17 harris41 998: extra formatting
999:
1.35 ! matthew 1000: =item get_previous_attempt()
1.17 harris41 1001:
1.35 ! matthew 1002: return string with previous attempt on problem
1.17 harris41 1003:
1.35 ! matthew 1004: =item get_student_view()
1.17 harris41 1005:
1.35 ! matthew 1006: show a snapshot of what student was looking at
1.17 harris41 1007:
1.35 ! matthew 1008: =item get_student_answers()
1.17 harris41 1009:
1.35 ! matthew 1010: show a snapshot of how student was answering problem
1.17 harris41 1011:
1.35 ! matthew 1012: =item get_unprocessed_cgi()
1.17 harris41 1013:
1.35 ! matthew 1014: get unparsed CGI parameters
1.17 harris41 1015:
1.35 ! matthew 1016: =item cacheheader()
1.17 harris41 1017:
1.35 ! matthew 1018: returns cache-controlling header code
1.17 harris41 1019:
1.35 ! matthew 1020: =item nocache()
1.17 harris41 1021:
1.35 ! matthew 1022: specifies header code to not have cache
1.25 albertel 1023:
1.35 ! matthew 1024: =item add_to_env($name,$value)
1.25 albertel 1025:
1.35 ! matthew 1026: adds $name to the %ENV hash with value
1.25 albertel 1027: $value, if $name already exists, the entry is converted to an array
1028: reference and $value is added to the array.
1.17 harris41 1029:
1030: =back
1031:
1032: =cut
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>