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