Annotation of loncom/interface/lonpdfupload.pm, revision 1.15

1.1       onken       1: # The LearningOnline Network with CAPA
1.12      bisitz      2: # PDF Form Upload Handler
1.1       onken       3: #
1.15    ! raeburn     4: # $Id: lonpdfupload.pm,v 1.14 2009/10/17 03:13:35 raeburn Exp $
1.1       onken       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: package Apache::lonpdfupload;
                     29: 
                     30: use lib '/home/httpd/lib/perl';
                     31: use Apache::Constants qw(:common :http);
1.15    ! raeburn    32: use Apache::lonnet;
1.1       onken      33: use Apache::lonhtmlcommon();
                     34: use Apache::loncommon();
                     35: use Apache::lonlocal;
1.2       onken      36: use CAM::PDF;
1.1       onken      37: 
                     38: use strict;
                     39: 
                     40: sub handler() {
1.2       onken      41:     my $r = shift;
1.15    ! raeburn    42:     &Apache::loncommon::content_type($r,'text/html');
        !            43:     $r->send_http_header;
        !            44:     return OK if $r->header_only;
1.13      bisitz     45: 
                     46:     # Breadcrumbs
1.15    ! raeburn    47:     my $brcrum = [{'href' => '/adm/pdfupload',
1.13      bisitz     48:                    'text' => 'Upload PDF Form'}];
                     49: 
                     50:     $r->print(&Apache::loncommon::start_page('Upload PDF Form',
                     51:                                              undef,
                     52:                                              {'bread_crumbs' => $brcrum,})
                     53:     );
1.2       onken      54: 
                     55:     # if a file was upload
                     56:     if($env{'form.Uploaded'} && $env{'form.file'}) {
                     57:         $r->print(&processPDF);
                     58:     } else { 
                     59:         # print upload form
                     60:         $r->print(&get_javascripts);
                     61:         $r->print(&get_uploadform);
                     62:     }
                     63: 
                     64:     #link to course-content
1.6       bisitz     65:     $r->print('<hr />'
                     66:              .'<p>'."\n"
1.5       bisitz     67:              .'<a href="/adm/navmaps">'."\n"
1.14      raeburn    68:              .&mt('Course Contents')."\n"
1.5       bisitz     69:              .'</a>'."\n"
                     70:              .'</p>'."\n"
                     71:     );
1.1       onken      72: 
1.2       onken      73:     #&dumpenv($r); #debug -> prints the environment
1.7       onken      74:     $r->print(&Apache::loncommon::end_page());
1.1       onken      75:     return OK;
1.2       onken      76: }
1.1       onken      77: 
                     78: sub get_javascripts() {
1.2       onken      79:     
1.6       bisitz     80:     my $message = &mt('Please choose a PDF-File.');
1.1       onken      81: 
1.2       onken      82:     # simple test if the upload ends with ".pdf"
                     83:     # it's only for giving a message to the user
                     84:     my $result .= <<END
                     85:   <script type="text/javascript">
1.1       onken      86:     function checkFilename(form) {
                     87:         var fileExt = form.file.value;
                     88:         fileExt = fileExt.match(/[.]pdf\$/g);
                     89:         if(fileExt) {
                     90:             return true;
                     91:         }
1.2       onken      92:         alert("$message");
1.1       onken      93:         return false;
                     94:     }
1.2       onken      95:   </script>
1.1       onken      96: END
                     97: ;
                     98:     return $result; 
                     99: }
                    100: 
1.2       onken     101: 
1.1       onken     102: sub get_uploadform() {
1.4       onken     103:     
                    104:     my %lt = &Apache::lonlocal::texthash(
1.6       bisitz    105:                  'title'  => 'Upload a PDF Form with filled Form Fields', 
                    106:                  'chFile' => 'File',
                    107:                  'submit' => 'Upload',
1.4       onken     108:              );
                    109: 
1.5       bisitz    110:     my $result = 
                    111:         '<br />'
                    112:        .'<form method="post" enctype="multipart/form-data" onsubmit="return checkFilename(this);">'
                    113:        .'<input type="hidden" name="type" value="upload" />'
                    114:        .&Apache::lonhtmlcommon::start_pick_box()
                    115:        .&Apache::lonhtmlcommon::row_headline()
                    116:        .'<h2>'.$lt{'title'}.'</h2>'
                    117:        .&Apache::lonhtmlcommon::row_closure()
                    118:        .&Apache::lonhtmlcommon::row_title($lt{'chFile'})
                    119:        .'<input type="file" name="file" id="filename" />'
                    120:        .&Apache::lonhtmlcommon::row_closure(1)
                    121:        .&Apache::lonhtmlcommon::end_pick_box()
1.13      bisitz    122:        .'<p>'
1.5       bisitz    123:        .'<input type="submit" name="Uploaded" value="'.$lt{'submit'}.'" />'
1.13      bisitz    124:        .'</p>'
1.5       bisitz    125:        .'</form>'
1.6       bisitz    126:        .'<br />';
1.5       bisitz    127: 
1.1       onken     128:   return $result;
                    129: }
                    130: 
                    131: sub processPDF {
1.2       onken     132:     my $result = ();  # message for Browser
                    133:     my @pdfdata = (); # answers from PDF-Forms
1.1       onken     134:     
1.2       onken     135:     @pdfdata = &get_pdf_data(); # get answers from PDF-Form
1.1       onken     136:     
                    137:     if (scalar @pdfdata) {    
1.2       onken     138:         &grade_pdf(@pdfdata);
1.1       onken     139:     } else {
1.6       bisitz    140:         $result .= '<p class="LC_error">'
                    141:                   .&mt("Can't find any valid PDF formfields.")
                    142:                   .'</p>';
1.1       onken     143:     }
                    144: }
                    145: 
                    146: sub get_pdf_data() {
                    147:     my @data = ();
1.2       onken     148:     my $pdf = CAM::PDF->new($env{'form.file'});
                    149: 
                    150:     my @formFields = $pdf->getFormFieldList(); #get names of formfields
1.1       onken     151:     
1.2       onken     152:     foreach my $field (@formFields) {
                    153: 	my $dict = $pdf->getFormFieldDict($pdf->getFormField($field)); # get formfield dictonary
1.1       onken     154: 
1.2       onken     155:         #
1.15    ! raeburn   156:         # this is necessary because CAM::PDF has a problem with formfieldnames which include a
1.2       onken     157:         # dot in fieldnames. So a fieldname like "i.am.aFormfield" will offer three fieldnames "i", "i.am" 
                    158:         # and "i.am.aFormfield". The fragmentary names keep no values and will be ignored.
                    159:         if($dict->{'V'}) {
                    160:             push(@data, $field."?". $dict->{'V'}{'value'}); #binding fieldname with value
                    161:         }
                    162:     } 
1.1       onken     163:     return @data;
                    164: }
                    165: 
                    166: sub grade_pdf {
                    167:     my $result = ();
                    168:     my @pdfdata = @_;
                    169:    
                    170:     my $meta = ();
                    171:     my %grades = ();
                    172:     my %problems = ();
                    173:         
                    174:     my $debug = ();
                    175: 
                    176:     $debug  .= "Found: ". scalar @pdfdata." Entries \n";
1.4       onken     177: 
1.1       onken     178:     foreach my $entry (sort(@pdfdata)) {
                    179:         if ($entry =~ /^meta.*/) {
1.2       onken     180:             $debug .= 'found: metadata -> '.$entry . "<br />";
                    181:             my ($label, $value) = ($entry =~ /^([^?]*)\?(.*)/);
1.1       onken     182:             my ($domain, $user) = split('&', $value);
1.4       onken     183:             $user =~ s/(.*)\n/$1/; #TODO is that equals to chomp?
1.1       onken     184:             
                    185:             if($user ne $env{'user.name'} or  $domain ne $env{'user.domain'}) {
1.12      bisitz    186:                 return '<p class="LC_error">'
                    187:                       .&mt('Wrong username ([_1]) found in PDF file. Expected username: [_2]'
                    188:                           ,$user.':'.$domain
                    189:                           ,$env{'user.domain'}.':'.$env{'user.name'})
                    190:                       .'</p>';
1.1       onken     191:             }
                    192: 
                    193:         } elsif($entry =~ /^upload.*/)  {
                    194:             $debug .= 'found: a problem -> '.$entry;
1.2       onken     195:             my ($label, $value) = ($entry =~ /^([^?]*)\?(.*)/);
1.1       onken     196:             my ($symb, $part, $type, $HWVAL) = split('&', $label);
                    197:             my ($map,$id,$resource)=&Apache::lonnet::decode_symb($symb);  
                    198:             $value =~ s/(.*)\n/$1/; 
                    199: 
1.6       bisitz    200:             #filter incorrect radiobuttons (Bug in CABAReT Stage)
1.1       onken     201:             if($type eq 'radiobuttonresponse' && $value eq 'Off' ) {
                    202:                 next;
                    203:             }
                    204:  
                    205:             my $submit = $part;
                    206:             $submit =~ s/part_(.*)/submit_$1/;
                    207:             if($problems{$symb.$part}) {
                    208:                  $problems{$symb.$part}{$HWVAL} = $value;
                    209:             } else {
                    210:                  $problems{$symb.$part} =  { 'resource' => $resource,
1.11      onken     211:                                         'symb' => $symb,
1.1       onken     212:                                         'submitted' => $part,
                    213:                                         $submit => 'Answer',
                    214:                                         $HWVAL => $value};
                    215:             }
                    216:         } else {
                    217:             $debug .= 'found: -> '.$entry;
                    218:             next;
                    219:         }
                    220:     }
1.4       onken     221:     #$result .= $debug;
1.1       onken     222: 
1.12      bisitz    223:     $result .= '<h2>'.&mt('Results of PDF Form problems').'</h2>';
                    224:     $result .= &Apache::loncommon::start_data_table()
                    225:               .&Apache::loncommon::start_data_table_header_row()
                    226:               .'<th>'.&mt('Problem Name').'</th>'
                    227:               .'<th>'.&mt('Grading').'</th>'
                    228:               .&Apache::loncommon::start_data_table_header_row()
                    229:               .&Apache::loncommon::end_data_table_header_row();
                    230: 
1.1       onken     231:     foreach my $key (sort (keys %problems)) {
                    232:         my %problem = %{$problems{$key}};
                    233:         my ($problemname, $grade) = &grade_problem(%problem);
1.4       onken     234: 
                    235:         $result .= &Apache::loncommon::start_data_table_row();
                    236:         $result .= "<td>$problemname</td><td class='";
1.8       onken     237:         if($grade eq "EXACT_ANS" || $grade eq "APPROX_ANS") {
1.4       onken     238:             $result .= "LC_answer_correct";
1.1       onken     239:         } else { 
1.4       onken     240:             $result .= "LC_answer_charged_try";
1.1       onken     241:         }
1.8       onken     242:         $grade = &parse_grade_answer($grade);
1.4       onken     243:         $result .= "'>$grade</span></td>";
                    244:         $result .= &Apache::loncommon::end_data_table_row();
                    245:     }
                    246:     $result .= &Apache::loncommon::end_data_table();
1.1       onken     247: 
                    248: 
                    249:     return $result;        
                    250: }
                    251: 
                    252: sub grade_problem {
                    253:     my %problem = @_;
1.7       onken     254:     my ($title, $part) = ();
1.1       onken     255: 
1.7       onken     256:     &Apache::loncommon::ssi_with_retries('/res/'.$problem{'resource'}, 5, %problem);
1.1       onken     257: 
1.7       onken     258:     $title = &Apache::lonnet::gettitle($problem{'symb'});    
                    259:     $part = $problem{submitted};
1.1       onken     260:     $part =~ s/part_(.*)/$1/;
1.7       onken     261:     unless($part eq '0') {
                    262:         #add information about part number
                    263:         $title .= " - Part $part";
                    264:     }
1.1       onken     265:  
                    266:     my %problemhash = &Apache::lonnet::restore($problem{'symb'});
                    267:     my $grade = $problemhash{"resource.$part.award"};
                    268: 
1.7       onken     269:     return ($title, $grade);    
1.1       onken     270: }
                    271: 
1.8       onken     272: sub parse_grade_answer {
                    273:     my ($shortcut) = @_;
                    274:      my %answerhash = ('EXACT_ANS' => &mt('You are correct.'),
1.10      onken     275:                        'APPROX_ANS' => &mt('You are correct.'),
1.8       onken     276:                        'INCORRECT' => &mt('You are incorrect'),
                    277:      );
                    278: 
                    279:     foreach my $key (keys %answerhash) {
                    280:         if($shortcut eq $key) {
                    281:             return $answerhash{$shortcut};
                    282:         }  
                    283:     }
                    284:     return &mt('See course contents for further information.');
                    285: 
                    286: }
                    287: 
                    288: 
1.1       onken     289: sub dumpenv  {
                    290:     my $r = shift;
                    291: 
                    292:     $r->print ("<br />-------------------<br />");
                    293:     foreach my $key (sort (keys %env)) {
                    294:         $r->print ("<br />$key -> $env{$key}");
                    295:     }
                    296:     $r->print ("<br />-------------------<br />");
                    297:     $r->print ("<br />-------------------<br />");
                    298:     foreach my $key (sort (keys %ENV)) {
                    299:         $r->print ("<br />$key -> $ENV{$key}");
                    300:     }
                    301:     $r->print ("<br />-------------------<br />");
                    302:     
                    303: }	
                    304: 
                    305: 1;
                    306: __END__
                    307: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>