File:  [LON-CAPA] / loncom / interface / spreadsheet / lonspreadsheet.pm
Revision 1.1: download - view: text, annotated - select for diffs
Fri May 16 20:55:11 2003 UTC (21 years, 1 month ago) by matthew
Branches: MAIN
CVS tags: HEAD
Nearly complete reworking of spreadsheet.

lonspreadsheet.pm holds a few utility functions and the handler, which
creates a spreadsheet and tells it to display itself.

Spreadsheet.pm is the base definition of the spreadsheet object.
classcalc.pm, studentcalc.pm, and assesscalc.pm are implementations of the
spreadsheets.

There are missing pieces - excel and csv output, limiting by section
permissions, the ability to add extra 'header' rows to the student and
course level sheets, and students are still allowed to view the assessment
level sheets (will disable this soon).

Computing and editing of the spreadsheet have been tested and have been
given a preliminary seal of approval.

    1: #
    2: # $Id: lonspreadsheet.pm,v 1.1 2003/05/16 20:55:11 matthew Exp $
    3: #
    4: # Copyright Michigan State University Board of Trustees
    5: #
    6: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    7: #
    8: # LON-CAPA is free software; you can redistribute it and/or modify
    9: # it under the terms of the GNU General Public License as published by
   10: # the Free Software Foundation; either version 2 of the License, or
   11: # (at your option) any later version.
   12: #
   13: # LON-CAPA is distributed in the hope that it will be useful,
   14: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   15: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16: # GNU General Public License for more details.
   17: #
   18: # You should have received a copy of the GNU General Public License
   19: # along with LON-CAPA; if not, write to the Free Software
   20: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   21: #
   22: # /home/httpd/html/adm/gpl.txt
   23: #
   24: # http://www.lon-capa.org/
   25: #
   26: # The LearningOnline Network with CAPA
   27: # Spreadsheet/Grades Display Handler
   28: #
   29: # POD required stuff:
   30: 
   31: =head1 NAME
   32: 
   33: lonspreadsheet
   34: 
   35: =head1 SYNOPSIS
   36: 
   37: Spreadsheet interface to internal LON-CAPA data
   38: 
   39: =head1 DESCRIPTION
   40: 
   41: Lonspreadsheet provides course coordinators the ability to manage their
   42: students grades online.  The students are able to view their own grades, but
   43: not the grades of their peers.  The spreadsheet is highly customizable,
   44: offering the ability to use Perl code to manipulate data, as well as many
   45: built-in functions.
   46: 
   47: =head2 Functions available to user of lonspreadsheet
   48: 
   49: =over 4
   50: 
   51: =cut
   52: 
   53: 
   54: package Apache::lonspreadsheet;
   55:             
   56: use strict;
   57: use Apache::classcalc();
   58: use Apache::studentcalc();
   59: use Apache::assesscalc();
   60: use Apache::Constants qw(:common :http);
   61: use Apache::lonnet;
   62: use Apache::lonhtmlcommon;
   63: use HTML::Entities();
   64: 
   65: ##
   66: ## HTML utility subroutines really should go in lonhtmlcommon
   67: ##
   68: 
   69: sub textfield {
   70:     my ($title,$name,$value)=@_;
   71:     return "\n<p><b>$title:</b><br>".
   72:         '<input type=text name="'.$name.'" size=80 value="'.$value.'">';
   73: }
   74: 
   75: sub hiddenfield {
   76:     my ($name,$value)=@_;
   77:     return '<input type=hidden name="'.$name.'" value="'.$value.'" />'."\n";
   78: }
   79: 
   80: sub selectbox {
   81:     my ($title,$name,$value,%options)=@_;
   82:     my $selout="\n<p><b>$title:</b><br>".'<select name="'.$name.'">';
   83:     foreach (sort keys(%options)) {
   84:         $selout.='<option value="'.$_.'"';
   85:         if ($_ eq $value) { $selout.=' selected'; }
   86:         $selout.='>'.$options{$_}.'</option>';
   87:     }
   88:     return $selout.'</select>';
   89: }
   90: 
   91: sub handler {
   92:     my $r=shift;
   93:     #
   94:     # Overload checking
   95:     #
   96:     # Check this server
   97:     my $loaderror=&Apache::lonnet::overloaderror($r);
   98:     if ($loaderror) { return $loaderror; }
   99:     # Check the course homeserver
  100:     $loaderror= &Apache::lonnet::overloaderror($r,
  101:                       $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
  102:     if ($loaderror) { return $loaderror; } 
  103:     #
  104:     # HTML Header
  105:     #
  106:     if ($r->header_only) {
  107:         $r->content_type('text/html');
  108:         $r->send_http_header;
  109:         return OK;
  110:     }
  111:     #
  112:     # Roles Checking
  113:     #
  114:     # Needs to be in a course
  115:     if (! $ENV{'request.course.fn'}) { 
  116:         # Not in a course, or not allowed to modify parms
  117:         $ENV{'user.error.msg'}=
  118:             $r->uri.":opa:0:0:Cannot modify spreadsheet";
  119:         return HTTP_NOT_ACCEPTABLE; 
  120:     }
  121:     #
  122:     # Get query string for limited number of parameters
  123:     #
  124:     &Apache::loncommon::get_unprocessed_cgi
  125:         ($ENV{'QUERY_STRING'},['sname','sdomain','usymb','filename']);
  126:     #
  127:     # Deal with restricted student permissions 
  128:     #
  129:     if ($ENV{'request.role'} =~ /^st\./) {
  130:         delete $ENV{'form.cell'}       if (exists($ENV{'form.cell'}));
  131:         delete $ENV{'form.newformula'} if (exists($ENV{'form.newformula'}));
  132:     }
  133:     #
  134:     # Determine basic information about the spreadsheet
  135:     my ($sheettype) = ($r->uri=~/\/(\w+)$/);
  136:     #
  137:     my $symb   = undef;
  138:     $symb = $ENV{'form.usymb'} if (exists($ENV{'form.usymb'}));
  139:     my $name   = $ENV{'user.name'};
  140:     my $domain = $ENV{'user.domain'};
  141:     if (exists($ENV{'form.sname'})) {
  142:         $name   = $ENV{'form.sname'};
  143:         $domain = $ENV{'form.sdomain'};
  144:     }
  145:     #
  146:     # Open page, try to prevent browser cache.
  147:     #
  148:     $r->content_type('text/html');
  149:     $r->header_out('Cache-control','no-cache');
  150:     $r->header_out('Pragma','no-cache');
  151:     $r->send_http_header;
  152:     #
  153:     # Check user permissions - only those able to view others grades
  154:     # will be allowed to continue if they are not requesting their own.
  155:     if (($sheettype eq 'classcalc') || 
  156:         ($name   ne $ENV{'user.name'} ) ||
  157:         ($domain ne $ENV{'user.domain'})) {
  158:         if (! &Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
  159:             $r->print('<h1>Access Permission Denied</h1>'.
  160:                       '</form></body></html>');
  161:             return OK;
  162:         }
  163:     }
  164:     #
  165:     # Header....
  166:     #
  167:     $r->print('<html><head><title>LON-CAPA Spreadsheet</title>');
  168:     my $nothing = &Apache::lonhtmlcommon::javascript_nothing();
  169:     ##
  170:     ## Spit out the javascript required for editing
  171:     ##
  172:     if (&Apache::lonnet::allowed('mgr',$ENV{'request.course.id'})) {
  173:         $r->print(<<ENDSCRIPT);
  174: <script language="JavaScript">
  175: 
  176:     var editwin;
  177: 
  178:     function celledit(cellname,cellformula) {
  179:         var edit_text = '';
  180:         // cellformula may contain less-than and greater-than symbols, so
  181:         // we need to escape them?  
  182:         edit_text +='<html><head><title>Cell Edit Window</title></head><body>';
  183:         edit_text += '<form name="editwinform">';
  184:         edit_text += '<center><h3>Cell '+cellname+'</h3>';
  185:         edit_text += '<textarea name="newformula" cols="40" rows="6"';
  186:         edit_text += ' wrap="off" >'+cellformula+'</textarea>';
  187:         edit_text += '</br>';
  188:         edit_text += '<input type="button" name="accept" value="Accept"';
  189:         edit_text += ' onClick=\\\'javascript:';
  190:         edit_text += 'opener.document.sheet.cell.value=';
  191:         edit_text +=     '"'+cellname+'";';
  192:         edit_text += 'opener.document.sheet.newformula.value=';
  193:         edit_text +=     'document.editwinform.newformula.value;';
  194:         edit_text += 'opener.document.sheet.submit();';
  195:         edit_text += 'self.close()\\\' />';
  196:         edit_text += '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
  197:         edit_text += '<input type="button" name="abort" ';
  198:         edit_text +=     'value="Discard Changes"';
  199:         edit_text += ' onClick="javascript:self.close()" />';
  200:         edit_text += '</center></body></html>';
  201: 
  202:         if (editwin != null && !(editwin.closed) ) {
  203:             editwin.close();
  204:         }
  205: 
  206:         editwin = window.open($nothing,'CellEditWin','height=200,width=350,scrollbars=no,resizeable=yes,alwaysRaised=yes,dependent=yes',true);
  207:         editwin.document.write(edit_text);
  208:     }
  209: </script>
  210: ENDSCRIPT
  211:     }
  212:     $r->print('</head>'.&Apache::loncommon::bodytag('Grades Spreadsheet').
  213:               '<form action="'.$r->uri.'" name="sheet" method="post">');
  214:     $r->print(&hiddenfield('sname'  ,$ENV{'form.sname'}).
  215:               &hiddenfield('sdomain',$ENV{'form.sdomain'}).
  216:               &hiddenfield('usymb'  ,$ENV{'form.usymb'}));
  217:     $r->rflush();
  218:     ##
  219:     ## Check permissions
  220:     my $editing_is_allowed = &Apache::lonnet::allowed('mgr',
  221:                                                 $ENV{'request.course.id'});
  222:     ##
  223:     ## Determine the filename to use
  224:     my $filename = undef;
  225:     if ($editing_is_allowed) {
  226:         $filename = $ENV{'form.filename'} if (exists($ENV{'form.filename'}));
  227:         #
  228:         if (exists($ENV{'form.load'}) && exists($ENV{'form.loadfilename'})) {
  229:             $filename = $ENV{'form.loadfilename'};
  230:         }
  231:     }
  232:     ##
  233:     ## Make the spreadsheet
  234:     &Apache::Spreadsheet::initialize_spreadsheet_package();
  235:     my $spreadsheet = undef;
  236:     if ($sheettype eq 'classcalc') {
  237:         $spreadsheet = Apache::classcalc->new($name,$domain,$filename,undef);
  238:     } elsif ($sheettype eq 'studentcalc') {
  239:         $spreadsheet = Apache::studentcalc->new($name,$domain,$filename,undef);
  240:     } elsif ($sheettype eq 'assesscalc' && defined($symb)) {
  241:         $spreadsheet = Apache::assesscalc->new($name,$domain,$filename,$symb);
  242:     } else {
  243:         &Apache::lonnet::logthis('Unable to determine spreadsheet type');
  244:         return;
  245:     }
  246:     ##
  247:     ## Editing/loading/saving
  248:     if ($editing_is_allowed) {
  249:         ##
  250:         ## Deal with saving the spreadsheet
  251:         if (exists($ENV{'form.save'}) && 
  252:             exists($ENV{'form.savefilename'})) {
  253:             $spreadsheet->filename($ENV{'form.savefilename'});
  254:             my $save_status = $spreadsheet->save();
  255:             if ($save_status ne 'ok') {
  256:                 $r->print("An error occurred while saving the spreadsheet".
  257:                           "There error is:".$save_status);
  258:             } else {
  259:                 $r->print("Spreadsheet saved as ".$ENV{'form.savefilename'});
  260:             }
  261:         } elsif (exists($ENV{'form.newformula'}) && 
  262:                  exists($ENV{'form.cell'})       && 
  263:                  $ENV{'form.cell'} ne '' ) {
  264:             ##
  265:             ## Make any requested modifications to the spreadsheet
  266:             $spreadsheet->modify_cell($ENV{'form.cell'},
  267:                                       $ENV{'form.newformula'});
  268:             $spreadsheet->save_tmp();
  269:             # output that we are dealing with a temporary file
  270:             $r->print(&hiddenfield('workcopy',$sheettype));
  271:             $r->print('<pre>'.$ENV{'form.cell'}.' = '.
  272:                       $ENV{'form.newformula'}.'</pre>'."\n");
  273:         }
  274:         ##
  275:         ## Editing code
  276:         $r->print(&hiddenfield('cell','').
  277:                   &hiddenfield('newformula',''));
  278:         ##
  279:         ## Create the save and load dialogs
  280:         $filename = $spreadsheet->filename();
  281:         $filename = '' if ($filename =~ /^default\.$sheettype/i);
  282:         $filename =~ s/_$sheettype$//;
  283:         my $save_dialog = 
  284:             '<input type="submit" name="save" value="Save as ..." /> '.
  285:                 '<input type="text" name="savefilename" size="30" value="'.
  286:                     $filename.'" />';
  287:         my $makedefault_dialog = 
  288:             '<input type="submit" name="makedefault" value="Make Default"/>';
  289:         #
  290:         my $load_dialog = 
  291:             '<input type="submit" name="load" value="Load ..." />'.
  292:                 '<select name="loadfilename">'.
  293:                     '<option name="Default">Default</option>'."\n";
  294:         foreach my $sheetfilename ($spreadsheet->othersheets()) {
  295:             $sheetfilename =~ s/_$sheettype$//;
  296:             $load_dialog .= '<option name="'.$sheetfilename.'"';
  297:             if ($filename eq $sheetfilename) {
  298:                 $load_dialog .= ' selected';
  299:             }
  300:             $load_dialog .= '>'.$sheetfilename."</option>\n";
  301:         }
  302:         #
  303:         $r->print(<<END);
  304: <!-- load / save dialogs -->
  305: <table cellspacing="3">
  306: <tr>
  307: <td>$load_dialog</td>
  308: <td>$save_dialog</td>
  309: <td>$makedefault_dialog</td>
  310: </tr>
  311: </table>
  312: END
  313:         $r->rflush();
  314:     }
  315:     #
  316:     # Keep track of the filename
  317:     $r->print(&hiddenfield('filename',$filename));
  318:     #
  319:     $r->print($spreadsheet->get_title());
  320:     $r->print($spreadsheet->parent_link());
  321:     if (defined($spreadsheet)) {
  322:         $spreadsheet->display($r);
  323:     }
  324:     $r->print('</form></body></html>');
  325:     return OK;
  326: }
  327: 
  328: 1;
  329: 
  330: __END__
  331: 

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