![]() ![]() | ![]() |
Added some more help, fixed some tex typos.
1: # The LearningOnline Network with CAPA 2: # Handler to drop and add students in courses 3: # 4: # $Id: londropadd.pm,v 1.43 2002/07/31 14:56:34 bowersj2 Exp $ 5: # 6: # Copyright Michigan State University Board of Trustees 7: # 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA). 9: # 10: # LON-CAPA is free software; you can redistribute it and/or modify 11: # it under the terms of the GNU General Public License as published by 12: # the Free Software Foundation; either version 2 of the License, or 13: # (at your option) any later version. 14: # 15: # LON-CAPA is distributed in the hope that it will be useful, 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18: # GNU General Public License for more details. 19: # 20: # You should have received a copy of the GNU General Public License 21: # along with LON-CAPA; if not, write to the Free Software 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23: # 24: # /home/httpd/html/adm/gpl.txt 25: # 26: # http://www.lon-capa.org/ 27: # 28: # (Handler to set parameters for assessments 29: # 30: # (Handler to resolve ambiguous file locations 31: # 32: # (TeX Content Handler 33: # 34: # YEAR=2000 35: # 05/29/00,05/30,10/11 Gerd Kortemeyer) 36: # 37: # 10/11,10/12,10/16 Gerd Kortemeyer) 38: # 39: # 11/20,11/21,11/22,11/23,11/24,11/25,11/27,11/28, 40: # 12/08,12/12 Gerd Kortemeyer) 41: # 42: # 12/26,12/27,12/28, 43: # YEAR=2001 44: # 01/01/01,01/15,02/10,02/13,02/14,02/22 Gerd Kortemeyer 45: # 8/6 Scott Harrison 46: # Guy Albertelli 47: # 9/25 Gerd Kortemeyer 48: # 12/19 Guy Albertelli 49: # YEAR=2002 50: # 1/4 Gerd Kortemeyer 51: 52: package Apache::londropadd; 53: 54: use strict; 55: use Apache::lonnet(); 56: use Apache::loncommon(); 57: use Apache::Constants qw(:common :http REDIRECT); 58: 59: # ================================================================ Print header 60: 61: sub header { 62: return(<<ENDHEAD); 63: <html> 64: <head> 65: <title>LON-CAPA Enrollment Manager</title> 66: </head> 67: <body bgcolor="#FFFFFF"> 68: <img align=right src=/adm/lonIcons/lonlogos.gif> 69: <h1>$ENV{'course.'.$ENV{'request.course.id'}.'.description'}</h1> 70: <h2>Enrollment Manager</h2> 71: <form method="post" enctype="multipart/form-data" 72: action="/adm/dropadd" name="studentform"> 73: ENDHEAD 74: } 75: 76: # =========== Drop student from all sections of a course, except optional $csec 77: sub modifystudent { 78: my ($udom,$unam,$courseid,$csec,$desiredhost)=@_; 79: # if $csec is undefined, drop the student from all the courses matching 80: # this one. If $csec is defined, drop them from all other sections of 81: # this course and add them to section $csec 82: $courseid=~s/\_/\//g; 83: $courseid=~s/^(\w)/\/$1/; 84: my %roles = &Apache::lonnet::dump('roles',$udom,$unam); 85: my ($tmp) = keys(%roles); 86: # Bail out if we were unable to get the students roles 87: return "$1" if ($tmp =~ /^(con_lost|error|no_such_host)/i); 88: # Go through the roles looking for enrollment in this course 89: my $result = ''; 90: foreach my $course (keys(%roles)) { 91: if ($course=~/^$courseid(?:\/)*(?:\s+)*(\w+)*\_st$/) { 92: # We are in this course 93: my $section=$1; 94: $section='' if ($course eq $courseid.'_st'); 95: if ( ((!$section) && (!$csec)) || ($section ne $csec) ) { 96: my (undef,$end,$start)=split(/\_/,$roles{$course}); 97: my $now=time; 98: if (!($start && ($now<$start)) || !($end && ($now>$end))) { 99: my $reply=&Apache::lonnet::modifystudent 100: ($udom,$unam,'','','','','','','', 101: $section,time,undef,undef,$desiredhost); 102: $result .= $reply.':'; 103: } 104: } 105: } 106: } 107: if ($result eq '') { 108: $result eq 'Unable to find section for this student'; 109: } else { 110: $result =~ s/(ok:)+/ok/g; 111: } 112: return $result; 113: } 114: 115: # ============ build a domain and server selection form 116: sub domain_form { 117: my ($defdom) = @_; 118: # Set up domain and server selection forms 119: # 120: # Get the domains 121: my @domains = &Apache::loncommon::get_domains(); 122: # build up the menu information to be passed to 123: # &Apache::loncommon::linked_select_forms 124: my %select_menus; 125: foreach my $dom (@domains) { 126: # set up the text for this domain 127: $select_menus{$dom}->{'text'}= $dom; 128: # we want a choice of 'default' as the default in the second menu 129: $select_menus{$dom}->{'default'}= 'default'; 130: $select_menus{$dom}->{'select2'}->{'default'} = 'default'; 131: # Now build up the other items in the second menu 132: my %servers = &Apache::loncommon::get_home_servers($dom); 133: foreach my $server (keys(%servers)) { 134: $select_menus{$dom}->{'select2'}->{$server} 135: = "$server $servers{$server}"; 136: } 137: } 138: my $result = &Apache::loncommon::linked_select_forms 139: ('studentform',' with home server ',$defdom, 140: 'lcdomain','lcserver',\%select_menus); 141: return $result; 142: } 143: 144: # ============================================================== Menu Phase One 145: sub menu_phase_one { 146: my $r=shift; 147: my $upfile_select=&Apache::loncommon::upfile_select_html(); 148: my $create_classlist_help = 149: &Apache::loncommon::help_open_topic("Course_Create_Class_List"); 150: my $create_csv_help = 151: &Apache::loncommon::help_open_topic("Course_Convert_To_CSV"); 152: $r->print(<<ENDUPFORM); 153: <input type=hidden name=phase value=two> 154: <hr> 155: <h3>Upload a courselist</h3> 156: $upfile_select 157: <p><input type=submit name="fileupload" value="Upload Courselist"> 158: <br /> 159: How to create a class list from a spreadsheet $create_classlist_help 160: <br /> 161: How to create a CSV file from your spreadsheet $create_csv_help 162: 163: <hr /> 164: <h3>Enroll a single student</h3> 165: <p><input type=submit name="enroll" value="Enroll Student"></p> 166: <hr /> 167: <h3>Classlist</h3> 168: <p><input type=submit name="view" value="View Class List"> 169: <input type=submit name="viewcsv" value="Comma Separated Class List"></p> 170: <hr /> 171: <h3>Drop students</h3> 172: <p><input type=submit name="drop" value="Selection List"></p> 173: ENDUPFORM 174: } 175: 176: sub phase_two_header { 177: my ($r,$datatoken,$distotal,$krbdefdom)=@_; 178: my $javascript; 179: if ($ENV{'form.upfile_associate'} eq 'reverse') { 180: $javascript=&phase_two_javascript_reverse_associate(); 181: } else { 182: $javascript=&phase_two_javascript_forward_associate(); 183: } 184: my $javascript_validations=&javascript_validations($krbdefdom); 185: $r->print(<<ENDPICK); 186: <h3>Uploading Class List</h3> 187: <hr> 188: <h3>Identify fields</h3> 189: Total number of records found in file: $distotal <hr /> 190: Enter as many fields as you can. The system will inform you and bring you back 191: to this page if the data selected is insufficient to run your class.<hr /> 192: <input type="button" value="Reverse Association" onClick="javascript:this.form.associate.value='Reverse Association';submit(this.form);" /> 193: <input type="hidden" name="associate" value="" /> 194: <input type="hidden" name="phase" value="three" /> 195: <input type="hidden" name="datatoken" value="$datatoken" /> 196: <input type="hidden" name="fileupload" value="$ENV{'form.fileupload'}" /> 197: <input type="hidden" name="upfiletype" value="$ENV{'form.upfiletype'}" /> 198: <input type="hidden" name="upfile_associate" 199: value="$ENV{'form.upfile_associate'}" /> 200: <hr /> 201: <script type="text/javascript" language="Javascript"> 202: $javascript 203: $javascript_validations 204: </script> 205: ENDPICK 206: } 207: 208: sub javascript_validations { 209: my ($krbdefdom)=@_; 210: my %param = ( formname => 'studentform', 211: kerb_def_dom => $krbdefdom ); 212: my $authheader = &Apache::loncommon::authform_header(%param); 213: return (<<ENDPICK); 214: function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec) { 215: var foundatype=0; 216: var message=''; 217: if (founduname==0) { 218: alert('You need to specify the username field'); 219: return; 220: } 221: if (current.radiovalue == null || current.radiovalue == 'nochange') { 222: // They did not check any of the login radiobuttons. 223: alert('You must choose an authentication type'); 224: return; 225: } 226: foundatype=1; 227: if (current.argfield == null || current.argfield == '') { 228: var alertmsg = ''; 229: switch (current.value) { 230: case 'krb': 231: alertmsg = 'You need to specify the Kerberos domain'; 232: break; 233: case 'loc': 234: case 'fsys': 235: alertmsg = 'You need to specify the initial password'; 236: break; 237: case 'fsys': 238: alertmsg = ''; 239: break; 240: default: 241: alertmsg = ''; 242: } 243: if (alertmsg != '') { 244: alert(alertmsg); 245: return; 246: } 247: } 248: 249: if (foundname==0) { message='No name fields specified. '; } 250: if (foundid==0) { message+='No ID or student number field specified. '; } 251: if (foundsec==0) { message+='No section or group field specified. '; } 252: if (vf.startdate.value=='') { 253: message+='No starting date set. '; 254: } 255: if (vf.enddate.value=='') { 256: message+='No ending date set. '; 257: } 258: if ((vf.enddate.value!='') && (vf.startdate.value!='')) { 259: if (Math.round(vf.enddate.value)<Math.round(vf.startdate.value)) { 260: alert('Ending date is before starting date'); 261: return; 262: } 263: } 264: if (message!='') { 265: message+='Continue enrollment?'; 266: if (confirm(message)) { 267: pclose(); 268: vf.submit(); 269: } 270: } else { 271: pclose(); 272: vf.submit(); 273: } 274: } 275: 276: 277: function pclose() { 278: parmwin=window.open("/adm/rat/empty.html","LONCAPAparms", 279: "height=350,width=350,scrollbars=no,menubar=no"); 280: parmwin.close(); 281: } 282: 283: function pjump(type,dis,value,marker,ret,call) { 284: parmwin=window.open("/adm/rat/parameter.html?type="+escape(type) 285: +"&value="+escape(value)+"&marker="+escape(marker) 286: +"&return="+escape(ret) 287: +"&call="+escape(call)+"&name="+escape(dis),"LONCAPAparms", 288: "height=350,width=350,scrollbars=no,menubar=no"); 289: 290: } 291: 292: function dateset() { 293: if (document.studentform.pres_marker.value=='end') { 294: document.studentform.enddate.value= 295: document.studentform.pres_value.value; 296: } 297: if (document.studentform.pres_marker.value=='start') { 298: document.studentform.startdate.value= 299: document.studentform.pres_value.value; 300: } 301: pclose(); 302: } 303: 304: $authheader 305: ENDPICK 306: 307: } 308: 309: sub phase_two_javascript_forward_associate { 310: return(<<ENDPICK); 311: function verify(vf) { 312: var founduname=0; 313: var foundpwd=0; 314: var foundname=0; 315: var foundid=0; 316: var foundsec=0; 317: var tw; 318: for (i=0;i<=vf.nfields.value;i++) { 319: tw=eval('vf.f'+i+'.selectedIndex'); 320: if (tw==1) { founduname=1; } 321: if ((tw>=2) && (tw<=6)) { foundname=1; } 322: if (tw==7) { foundid=1; } 323: if (tw==8) { foundsec=1; } 324: if (tw==9) { foundpwd=1; } 325: } 326: verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec); 327: } 328: 329: function flip(vf,tf) { 330: var nw=eval('vf.f'+tf+'.selectedIndex'); 331: var i; 332: for (i=0;i<=vf.nfields.value;i++) { 333: if ((i!=tf) && (eval('vf.f'+i+'.selectedIndex')==nw)) { 334: eval('vf.f'+i+'.selectedIndex=0;') 335: } 336: } 337: if (tf==1 && nw!=0) { 338: for (i=2;i<=5;i++) { 339: eval('vf.f'+i+'.selectedIndex=0;') 340: } 341: } 342: if (nw==2) { 343: for (i=0;i<=vf.nfields.value;i++) { 344: if ((eval('vf.f'+i+'.selectedIndex')>=3) && 345: (eval('vf.f'+i+'.selectedIndex')<=6)) { 346: eval('vf.f'+i+'.selectedIndex=0;') 347: } 348: } 349: } 350: if ((nw>=3) && (nw<=6)) { 351: for (i=0;i<=vf.nfields.value;i++) { 352: if (eval('vf.f'+i+'.selectedIndex')==2) { 353: eval('vf.f'+i+'.selectedIndex=0;') 354: } 355: } 356: } 357: if (nw==9) { 358: changed_radio('int',document.studentform); 359: set_auth_radio_buttons('int',document.studentform); 360: vf.intarg.value=''; 361: vf.krbarg.value=''; 362: vf.locarg.value=''; 363: } 364: } 365: 366: function clearpwd(vf) { 367: var i; 368: for (i=0;i<=vf.nfields.value;i++) { 369: if (eval('vf.f'+i+'.selectedIndex')==9) { 370: eval('vf.f'+i+'.selectedIndex=0;') 371: } 372: } 373: } 374: 375: ENDPICK 376: } 377: 378: sub phase_two_javascript_reverse_associate { 379: return(<<ENDPICK); 380: function verify(vf) { 381: var founduname=0; 382: var foundpwd=0; 383: var foundname=0; 384: var foundid=0; 385: var foundsec=0; 386: var tw; 387: for (i=0;i<=vf.nfields.value;i++) { 388: tw=eval('vf.f'+i+'.selectedIndex'); 389: if (i==0 && tw!=0) { founduname=1; } 390: if (((i>=1) && (i<=5)) && tw!=0 ) { foundname=1; } 391: if (i==6 && tw!=0) { foundid=1; } 392: if (i==7 && tw!=0) { foundsec=1; } 393: if (i==8 && tw!=0) { foundpwd=1; } 394: } 395: verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec); 396: } 397: 398: function flip(vf,tf) { 399: var nw=eval('vf.f'+tf+'.selectedIndex'); 400: var i; 401: // picked the all one one name field, reset the other name ones to blank 402: if (tf==1 && nw!=0) { 403: for (i=2;i<=5;i++) { 404: eval('vf.f'+i+'.selectedIndex=0;') 405: } 406: } 407: //picked one of the piecewise name fields, reset the all in 408: //one field to blank 409: if ((tf>=2) && (tf<=5) && (nw!=0)) { 410: eval('vf.f1.selectedIndex=0;') 411: } 412: // intial password specified, pick internal authentication 413: if (tf==8 && nw!=0) { 414: changed_radio('int',document.studentform); 415: set_auth_radio_buttons('int',document.studentform); 416: vf.krbarg.value=''; 417: vf.intarg.value=''; 418: vf.locarg.value=''; 419: } 420: } 421: 422: function clearpwd(vf) { 423: var i; 424: if (eval('vf.f8.selectedIndex')!=0) { 425: eval('vf.f8.selectedIndex=0;') 426: } 427: } 428: ENDPICK 429: } 430: 431: sub phase_two_end { 432: my ($r,$i,$keyfields,$defdom,$today,$halfyear)=@_; 433: my %param = ( formname => 'document.studentform'); 434: my $krbform = &Apache::loncommon::authform_kerberos(%param); 435: my $intform = &Apache::loncommon::authform_internal(%param); 436: my $locform = &Apache::loncommon::authform_local(%param); 437: my $domform = &domain_form($defdom); 438: $r->print(<<ENDPICK); 439: </table> 440: <input type=hidden name=nfields value=$i> 441: <input type=hidden name=keyfields value="$keyfields"> 442: <h3>Login Type</h3> 443: <p>Note: this will not take effect if the user already exists</p> 444: <p> 445: $krbform 446: </p> 447: <p> 448: $intform 449: </p> 450: <p> 451: $locform 452: </p> 453: <h3>LON-CAPA Domain for Students</h3> 454: LON-CAPA domain: $domform <p> 455: <h3>Starting and Ending Dates</h3> 456: <input type="hidden" value='' name="pres_value" > 457: <input type="hidden" value='' name="pres_type" > 458: <input type="hidden" value='' name="pres_marker" > 459: <input type="hidden" value='$today' name="startdate" > 460: <input type="hidden" value='$halfyear' name="enddate" > 461: <a 462: href="javascript:pjump('date_start','Enrollment Starting Date',document.studentform.startdate.value,'start','studentform.pres','dateset');" 463: >Set Starting Date</a><p> 464: 465: <a 466: href="javascript:pjump('date_end','Enrollment Ending Date',document.studentform.enddate.value,'end','studentform.pres','dateset');" 467: >Set Ending Date</a><p> 468: <h3>Full Update</h3> 469: <input type=checkbox name=fullup value=yes> Full update 470: (also print list of users not enrolled anymore)<p> 471: <h3>ID/Student Number</h3> 472: <input type=checkbox name=forceid value=yes> 473: Disable ID/Student Number Safeguard and Force Change of Conflicting IDs 474: (only do if you know what you are doing)<p> 475: <input type="button" onClick="javascript:verify(this.form)" value="Update Courselist" /><br /> 476: Note: for large courses, this operation might be time consuming. 477: ENDPICK 478: } 479: 480: # ======================================================= Menu Phase Two Upload 481: sub menu_phase_two_upload { 482: my $r=shift; 483: 484: my $datatoken; 485: if (!$ENV{'form.datatoken'}) { 486: $datatoken=&Apache::loncommon::upfile_store($r); 487: } else { 488: $datatoken=$ENV{'form.datatoken'}; 489: &Apache::loncommon::load_tmp_file($r); 490: } 491: my @records=&Apache::loncommon::upfile_record_sep(); 492: my $total=$#records; 493: my $distotal=$total+1; 494: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/; 495: my $krbdefdom=$1; 496: $krbdefdom=~tr/a-z/A-Z/; 497: my $today=time; 498: my $halfyear=$today+15552000; 499: my $defdom=$r->dir_config('lonDefDomain'); 500: &phase_two_header($r,$datatoken,$distotal,$krbdefdom); 501: my $i; 502: my $keyfields; 503: if ($total>=0) { 504: my @d=(['username','Username'],['names','Last Name, First Names'], 505: ['fname','First Name'],['mname','Middle Names/Initials'], 506: ['lname','Last Name'],['gen','Generation'], 507: ['id','ID/Student Number'],['sec','Group/Section'], 508: ['ipwd','Initial Password']); 509: if ($ENV{'form.upfile_associate'} eq 'reverse') { 510: &Apache::loncommon::csv_print_samples($r,\@records); 511: $i=&Apache::loncommon::csv_print_select_table($r,\@records,\@d); 512: foreach (@d) { $keyfields.=$_->[0].','; } 513: chop($keyfields); 514: } else { 515: unshift(@d,['none','']); 516: $i=&Apache::loncommon::csv_samples_select_table($r,\@records,\@d); 517: my %sone=&Apache::loncommon::record_sep($records[0]); 518: $keyfields=join(',',sort(keys(%sone))); 519: } 520: } 521: &phase_two_end($r,$i,$keyfields,$defdom,$today,$halfyear); 522: } 523: 524: # ======================================================= Enroll single student 525: sub enroll_single_student { 526: my $r=shift; 527: $r->print('<h3>Enrolling Student</h3>'); 528: $r->print('<p>Enrolling '.$ENV{'form.cuname'}." in domain ". 529: $ENV{'form.lcdomain'}.'</p>'); 530: if (($ENV{'form.cuname'})&&($ENV{'form.cuname'}!~/\W/)&& 531: ($ENV{'form.lcdomain'})&&($ENV{'form.lcdomain'}!~/\W/)) { 532: # Deal with home server selection 533: my $domain=$ENV{'form.lcdomain'}; 534: my $desiredhost = $ENV{'form.lcserver'}; 535: if (lc($desiredhost) eq 'default') { 536: $desiredhost = undef; 537: } else { 538: my %home_servers = &Apache::loncommon::get_home_servers($domain); 539: if (! exists($home_servers{$desiredhost})) { 540: $r->print('<font color="#ff0000">Error:</font>'. 541: 'Invalid home server specified'); 542: return; 543: } 544: } 545: $r->print(" with server $desiredhost :") if (defined($desiredhost)); 546: # End of home server selection logic 547: my $amode=''; 548: my $genpwd=''; 549: if ($ENV{'form.login'} eq 'krb') { 550: $amode='krb4'; 551: $genpwd=$ENV{'form.krbarg'}; 552: } elsif ($ENV{'form.login'} eq 'int') { 553: $amode='internal'; 554: $genpwd=$ENV{'form.intarg'}; 555: } elsif ($ENV{'form.login'} eq 'loc') { 556: $amode='localauth'; 557: $genpwd=$ENV{'form.locarg'}; 558: if (!$genpwd) { $genpwd=" "; } 559: } 560: my $home = &Apache::lonnet::homeserver($ENV{'form.cuname'}, 561: $ENV{'form.lcdomain'}); 562: if ((($amode) && ($genpwd)) || ($home ne 'no_host')) { 563: &modifystudent($ENV{'form.lcdomain'},$ENV{'form.cuname'}, 564: $ENV{'request.course.id'},$ENV{'form.csec'}, 565: $desiredhost); 566: $r->print(&Apache::lonnet::modifystudent( 567: $ENV{'form.lcdomain'},$ENV{'form.cuname'}, 568: $ENV{'form.cstid'},$amode,$genpwd, 569: $ENV{'form.cfirst'},$ENV{'form.cmiddle'}, 570: $ENV{'form.clast'},$ENV{'form.cgen'}, 571: $ENV{'form.csec'},$ENV{'form.enddate'}, 572: $ENV{'form.startdate'},$ENV{'form.forceid'}, 573: $desiredhost)); 574: } else { 575: $r->print('<p><font color="#ff0000">ERROR</font> '. 576: 'Invalid login mode or password. '. 577: 'Unable to enroll '.$ENV{'form.cuname'}.'.</p>'); 578: } 579: } else { 580: $r->print('Invalid username or domain'); 581: } 582: } 583: 584: # ======================================================= Menu Phase Two Enroll 585: sub menu_phase_two_enroll { 586: my $r=shift; 587: $r->print("<h3>Enroll One Student</h3>"); 588: my ($krbdefdom) = $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/; 589: $krbdefdom=~tr/a-z/A-Z/; 590: my $today = time; 591: my $halfyear = $today+15552000; 592: my $defdom=$r->dir_config('lonDefDomain'); 593: my $javascript_validations=&javascript_validations($krbdefdom); 594: # Set up authentication forms 595: my %param = ( formname => 'document.studentform'); 596: my $krbform = &Apache::loncommon::authform_kerberos(%param); 597: my $intform = &Apache::loncommon::authform_internal(%param); 598: my $locform = &Apache::loncommon::authform_local(%param); 599: # Set up domain selection form 600: my $domform = &domain_form($defdom); 601: # Print it all out 602: $r->print(<<ENDSENROLL); 603: <script type="text/javascript" language="Javascript"> 604: function verify(vf) { 605: var founduname=0; 606: var foundpwd=0; 607: var foundname=0; 608: var foundid=0; 609: var foundsec=0; 610: var tw; 611: if ((typeof(vf.cuname.value) !="undefined") && (vf.cuname.value!='') && 612: (typeof(vf.lcdomain.value)!="undefined") && (vf.lcdomain.value!='')) { 613: founduname=1; 614: } 615: if ((typeof(vf.cfirst.value)!="undefined") && (vf.cfirst.value!='') && 616: (typeof(vf.clast.value) !="undefined") && (vf.clast.value!='')) { 617: foundname=1; 618: } 619: if ((typeof(vf.csec.value)!="undefined") && (vf.csec.value!='')) { 620: foundsec=1; 621: } 622: if ((typeof(vf.cstid.value)!="undefined") && (vf.cstid.value!='')) { 623: foundid=1; 624: } 625: if (founduname==0) { 626: alert('You need to specify at least the username and domain fields'); 627: return; 628: } 629: verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec); 630: } 631: 632: $javascript_validations 633: 634: function clearpwd(vf) { 635: //nothing else needs clearing 636: } 637: 638: </script> 639: <h3>Personal Data</h3> 640: First Name: <input type="text" name="cfirst" size="15"><br> 641: Middle Name: <input type="text" name="cmiddle" size="15"><br> 642: Last Name: <input type="text" name="clast" size="15"><br> 643: Generation: <input type="text" name="cgen" size="5"> 644: 645: <p>ID/Student Number: <input type="text" name="cstid" size="10"></p> 646: 647: <p>Group/Section: <input type=text name=csec size=5></p> 648: 649: <h3>Login Data</h3> 650: <p>Username: <input type="text" name="cuname" size="15"></p> 651: <p>Domain: $domform</p> 652: <p>Note: login settings below will not take effect if the user already exists 653: </p><p> 654: $krbform 655: </p><p> 656: $intform 657: </p><p> 658: $locform 659: </p><p> 660: <h3>Starting and Ending Dates</h3> 661: <input type="hidden" value='' name="pres_value"> 662: <input type="hidden" value='' name="pres_type"> 663: <input type="hidden" value='' name="pres_marker"> 664: <input type="hidden" value='$today' name=startdate> 665: <input type="hidden" value='$halfyear' name=enddate> 666: </p><p> 667: <a 668: href="javascript:pjump('date_start','Enrollment Starting Date',document.studentform.startdate.value,'start','studentform.pres','dateset');" 669: >Set Starting Date</a> 670: </p><p> 671: <a 672: href="javascript:pjump('date_end','Enrollment Ending Date',document.studentform.enddate.value,'end','studentform.pres','dateset');" 673: >Set Ending Date</a> 674: </p><p> 675: <h3>ID/Student Number</h3> 676: <input type="checkbox" name="forceid" value="yes"> 677: Disable ID/Student Number Safeguard and Force Change of Conflicting IDs 678: (only do if you know what you are doing)<p> 679: <input type="button" onClick="verify(this.form)" value="Enroll as student"><br> 680: <input type="hidden" name="phase" value="five"> 681: </p> 682: ENDSENROLL 683: } 684: 685: # =================================================== get the current classlist 686: sub get_current_classlist { 687: my ($domain,$identifier) = @_; 688: # domain is the domain the class is being run in 689: # identifier is the internal, unique identifier for the class. 690: my %currentlist=(); 691: my $now=time; 692: my %results=&Apache::lonnet::dump('classlist',$domain,$identifier); 693: my ($tmp) = keys(%results); 694: if ($tmp !~ /^(con_lost|error|no_such_host)/i) { 695: foreach my $student (keys(%results)) { 696: # Extract the start and end dates 697: my ($end,$start)=split(/\:/,$results{$student}); 698: # If the class isn't over, put it in the list 699: unless (($end) && ($now>$end)) { 700: $currentlist{$student}=1; 701: } 702: } 703: return (undef,%currentlist); 704: } else { 705: $tmp =~ s/^error://; 706: return ($tmp,undef); 707: } 708: } 709: 710: # ========================================================= Menu Phase Two Drop 711: sub menu_phase_two_drop { 712: my $r=shift; 713: $r->print("<h3>Drop Students</h3>"); 714: my $cid=$ENV{'request.course.id'}; 715: my ($error,%currentlist)=&get_current_classlist 716: ($ENV{'course.'.$cid.'.domain'},$ENV{'course.'.$cid.'.num'}); 717: if (defined($error)) { 718: if ($error =~ /^No such file or directory/) { 719: $r->print("There are no students currently enrolled.\n"); 720: } else { 721: $r->print("<pre>ERROR:$error</pre>"); 722: } 723: } elsif (!defined(%currentlist)) { 724: $r->print("There are no students currently enrolled.\n"); 725: } else { 726: # Print out the available choices 727: &show_drop_list($r,%currentlist); 728: } 729: } 730: 731: # ============================================== view classlist 732: sub menu_phase_two_view { 733: my $r=shift; 734: $r->print("<h3>Current Classlist</h3>"); 735: my $cid=$ENV{'request.course.id'}; 736: my ($error,%currentlist)=&get_current_classlist 737: ($ENV{'course.'.$cid.'.domain'},$ENV{'course.'.$cid.'.num'}); 738: if (defined($error)) { 739: if ($error =~ /^No such file or directory/) { 740: $r->print("There are no students currently enrolled.\n"); 741: } else { 742: $r->print("<pre>ERROR:$error</pre>"); 743: } 744: } elsif (!defined(%currentlist)) { 745: $r->print("There are no students currently enrolled.\n"); 746: } else { 747: # Print out the available choices 748: &show_class_list($r,'view',%currentlist); 749: } 750: } 751: 752: # ============================================== view classlist 753: sub menu_phase_two_viewcsv { 754: my $r=shift; 755: my $cid=$ENV{'request.course.id'}; 756: my ($error,%currentlist)=&get_current_classlist 757: ($ENV{'course.'.$cid.'.domain'},$ENV{'course.'.$cid.'.num'}); 758: if (defined($error)) { 759: if ($error =~ /^No such file or directory/) { 760: $r->print("There are no students currently enrolled.\n"); 761: } else { 762: $r->print("<pre>ERROR:$error</pre>"); 763: } 764: } elsif (!defined(%currentlist)) { 765: $r->print("There are no students currently enrolled.\n"); 766: } else { 767: &show_class_list($r,'csv',%currentlist); 768: } 769: } 770: 771: # =================================================== Show student list to drop 772: sub show_class_list { 773: my ($r,$mode,%currentlist)=@_; 774: my $cid=$ENV{'request.course.id'}; 775: # Print out header 776: if ($mode eq 'view') { 777: $r->print(<<END); 778: <p> 779: <table border=2> 780: <tr><th>username</th><th>domain</th><th>ID</th> 781: <th>student name</th><th>generation</th><th>section</th></tr> 782: END 783: } elsif ($mode eq 'csv') { 784: $r->print(<<END); 785: username,domain,ID,last name,first name,middle name,generation,section 786: END 787: } 788: foreach (sort keys %currentlist) { 789: my ($sname,$sdom)=split(/\:/,$_); 790: my %reply=&Apache::lonnet::idrget($sdom,$sname); 791: my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid); 792: my %info=&Apache::lonnet::get('environment', 793: ['firstname','middlename', 794: 'lastname','generation'], 795: $sdom, $sname); 796: my ($tmp) = keys(%info); 797: if ($tmp =~ /^(con_lost|error|no_such_host)/i) { 798: $r->print( ($mode eq 'view' ? 799: '<tr><td colspan="6"><font color="red">' :''). 800: 'Internal error: unable to get environment '. 801: 'for '.$sname.' in domain '.$sdom. 802: ( $mode eq 'view' ?'</font></td></tr>' :'')); 803: } else { 804: if ($mode eq 'view') { 805: $r->print(<<"END"); 806: <tr> 807: <td>$sname</td> 808: <td>$sdom</td> 809: <td>$reply{$sname}</td> 810: <td>$info{'lastname'}, $info{'firstname'} $info{'middlename'}</td> 811: <td>$info{'generation'}</td> 812: <td>$ssec</td> 813: </tr> 814: END 815: } elsif ($mode eq 'csv') { 816: my @line = (); 817: foreach ($sname,$sdom,$reply{$sname}, 818: $info{'lastname'},$info{'firstname'}, 819: $info{'middlename'},$info{'generation'},$ssec) { 820: push @line,&Apache::loncommon::csv_translate($_); 821: } 822: my $tmp = $"; 823: $" = '","'; 824: $r->print("\"@line\"\n"); 825: $" = $tmp; 826: } 827: } 828: } 829: $r->print('</table><br>') if ($mode eq 'view'); 830: } 831: 832: # =================================================== Show student list to drop 833: sub show_drop_list { 834: my ($r,%currentlist)=@_; 835: my $cid=$ENV{'request.course.id'}; 836: $r->print(<<'END'); 837: <script> 838: function checkAll(field) 839: { 840: for (i = 0; i < field.length; i++) 841: field[i].checked = true ; 842: } 843: 844: function uncheckAll(field) 845: { 846: for (i = 0; i < field.length; i++) 847: field[i].checked = false ; 848: } 849: </script> 850: <p> 851: <input type="hidden" name="phase" value="four"> 852: <table border=2> 853: <tr><th> </th><th>username</th><th>domain</th> 854: <th>ID</th><th>student name</th><th>generation</th> 855: <th>section</th></tr> 856: END 857: foreach (sort keys %currentlist) { 858: my ($sname,$sdom)=split(/\:/,$_); 859: my %reply=&Apache::lonnet::idrget($sdom,$sname); 860: my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid); 861: my %info=&Apache::lonnet::get('environment', 862: ['firstname','middlename', 863: 'lastname','generation'], 864: $sdom, $sname); 865: my ($tmp) = keys(%info); 866: if ($tmp =~ /^(con_lost|error|no_such_host)/i) { 867: $r->print('<tr><td colspan="7"><font color="red">'. 868: 'Internal error: unable to get environment '. 869: 'for '.$sname.' in domain '.$sdom.'</font></td></tr>'); 870: } else { 871: $r->print(<<"END"); 872: <tr> 873: <td><input type="checkbox" name="droplist" value="$_"></td> 874: <td>$sname</td> 875: <td>$sdom</td> 876: <td>$reply{$sname}</td> 877: <td>$info{'lastname'}, $info{'firstname'} $info{'middlename'}</td> 878: <td>$info{'generation'}</td> 879: <td>$ssec</td> 880: </tr> 881: END 882: } 883: } 884: $r->print('</table><br>'); 885: $r->print(<<"END"); 886: </p><p> 887: <input type="button" value="check all" onclick="javascript:checkAll(document.studentform.droplist)"> 888: <input type="button" value="uncheck all" onclick="javascript:uncheckAll(document.studentform.droplist)"> 889: <p><input type=submit value="Drop Students"></p> 890: END 891: } 892: 893: # ================================================= Drop/Add from uploaded file 894: sub upfile_drop_add { 895: my $r=shift; 896: &Apache::loncommon::load_tmp_file($r); 897: my @studentdata=&Apache::loncommon::upfile_record_sep(); 898: my @keyfields = split(/\,/,$ENV{'form.keyfields'}); 899: my $cid = $ENV{'request.course.id'}; 900: my %fields=(); 901: for (my $i=0; $i<=$ENV{'form.nfields'}; $i++) { 902: if ($ENV{'form.upfile_associate'} eq 'reverse') { 903: if ($ENV{'form.f'.$i} ne 'none') { 904: $fields{$keyfields[$i]}=$ENV{'form.f'.$i}; 905: } 906: } else { 907: $fields{$ENV{'form.f'.$i}}=$keyfields[$i]; 908: } 909: } 910: # 911: my $startdate = $ENV{'form.startdate'}; 912: my $enddate = $ENV{'form.enddate'}; 913: if ($startdate=~/\D/) { $startdate=''; } 914: if ($enddate=~/\D/) { $enddate=''; } 915: # Determine domain and desired host (home server) 916: my $domain=$ENV{'form.lcdomain'}; 917: my $desiredhost = $ENV{'form.lcserver'}; 918: if (lc($desiredhost) eq 'default') { 919: $desiredhost = undef; 920: } else { 921: my %home_servers = &Apache::loncommon::get_home_servers($domain); 922: if (! exists($home_servers{$desiredhost})) { 923: $r->print('<font color="#ff0000">Error:</font>'. 924: 'Invalid home server specified'); 925: return; 926: } 927: } 928: # Determine authentication mechanism 929: my $amode = ''; 930: my $genpwd = ''; 931: if ($ENV{'form.login'} eq 'krb') { 932: $amode='krb4'; 933: $genpwd=$ENV{'form.krbarg'}; 934: } elsif ($ENV{'form.login'} eq 'int') { 935: $amode='internal'; 936: if ((defined($ENV{'form.intarg'})) && ($ENV{'form.intarg'})) { 937: $genpwd=$ENV{'form.intarg'}; 938: } 939: } elsif ($ENV{'form.login'} eq 'loc') { 940: $amode='localauth'; 941: if ((defined($ENV{'form.locarg'})) && ($ENV{'form.locarg'})) { 942: $genpwd=$ENV{'form.locarg'}; 943: } 944: } 945: unless (($domain=~/\W/) || ($amode eq '')) { 946: ####################################### 947: ## Enroll Students ## 948: ####################################### 949: $r->print('<h3>Enrolling Students</h3>'); 950: my $count=0; 951: my $flushc=0; 952: my %student=(); 953: # Get new classlist 954: foreach (@studentdata) { 955: my %entries=&Apache::loncommon::record_sep($_); 956: # Determine student name 957: unless (($entries{$fields{'username'}} eq '') || 958: (!defined($entries{$fields{'username'}}))) { 959: my ($fname, $mname, $lname,$gen) = ('','','',''); 960: if (defined($fields{'names'})) { 961: ($lname,$fname,$mname)=($entries{$fields{'names'}}=~ 962: /([^\,]+)\,\s*(\w+)\s*(.*)$/); 963: } else { 964: if (defined($fields{'fname'})) { 965: $fname=$entries{$fields{'fname'}}; 966: } 967: if (defined($fields{'mname'})) { 968: $mname=$entries{$fields{'mname'}}; 969: } 970: if (defined($fields{'lname'})) { 971: $lname=$entries{$fields{'lname'}}; 972: } 973: if (defined($fields{'gen'})) { 974: $gen=$entries{$fields{'gen'}}; 975: } 976: } 977: if ($entries{$fields{'username'}}=~/\W/) { 978: $r->print('<p><b>Unacceptable username: '. 979: $entries{$fields{'username'}}.' for user '. 980: $fname.' '.$mname.' '.$lname.' '.$gen.'</b><p>'); 981: } else { 982: # determine section number 983: my $sec=''; 984: my $username=$entries{$fields{'username'}}; 985: if (defined($fields{'sec'})) { 986: if (defined($entries{$fields{'sec'}})) { 987: $sec=$entries{$fields{'sec'}}; 988: } 989: } 990: # determine student id number 991: my $id=''; 992: if (defined($fields{'id'})) { 993: if (defined($entries{$fields{'id'}})) { 994: $id=$entries{$fields{'id'}}; 995: } 996: $id=~tr/A-Z/a-z/; 997: } 998: # determine student password 999: my $password=''; 1000: if ($genpwd) { 1001: $password=$genpwd; 1002: } else { 1003: if (defined($fields{'ipwd'})) { 1004: if ($entries{$fields{'ipwd'}}) { 1005: $password=$entries{$fields{'ipwd'}}; 1006: } 1007: } 1008: } 1009: if ($password) { 1010: &modifystudent($domain,$username,$cid,$sec, 1011: $desiredhost); 1012: my $reply=&Apache::lonnet::modifystudent 1013: ($domain,$username,$id,$amode,$password, 1014: $fname,$mname,$lname,$gen,$sec,$enddate, 1015: $startdate,$ENV{'form.forceid'},$desiredhost); 1016: if ($reply ne 'ok') { 1017: $r->print('<p><b>'. 1018: 'Error enrolling '.$username.': '. 1019: $reply.'</b></p>'); 1020: } else { 1021: $count++; $flushc++; 1022: $student{$username}=1; 1023: $r->print('. '); 1024: if ($flushc>15) { 1025: $r->rflush; 1026: $flushc=0; 1027: } 1028: } 1029: } else { 1030: $r->print("<p><b>No password for $username</b><p>"); 1031: } 1032: } 1033: } 1034: } # end of foreach (@studentdata) 1035: $r->print('<p>Processed Students: '.$count); 1036: ##################################### 1037: # Drop students # 1038: ##################################### 1039: if ($ENV{'form.fullup'} eq 'yes') { 1040: $r->print('<h3>Dropping Students</h3>'); 1041: # Get current classlist 1042: my ($error,%currentlist)=&get_current_classlist 1043: ($ENV{'course.'.$cid.'.domain'}, 1044: $ENV{'course.'.$cid.'.num'}); 1045: if (defined($error)) { 1046: $r->print('<pre>ERROR:$error</pre>'); 1047: } 1048: if (defined(%currentlist)) { 1049: # Drop the students 1050: foreach (@studentdata) { 1051: my %entries=&Apache::loncommon::record_sep($_); 1052: unless (($entries{$fields{'username'}} eq '') || 1053: (!defined($entries{$fields{'username'}}))) { 1054: delete($currentlist{$entries{$fields{'username'}}. 1055: ':'.$domain}); 1056: } 1057: } 1058: # Print out list of dropped students 1059: &show_drop_list($r,%currentlist); 1060: } else { 1061: $r->print("There are no students currently enrolled.\n"); 1062: } 1063: } 1064: } # end of unless 1065: } 1066: 1067: # ================================================================== Phase four 1068: sub drop_student_list { 1069: my $r=shift; 1070: my $count=0; 1071: my @droplist; 1072: if (ref($ENV{'form.droplist'})) { 1073: @droplist = @{$ENV{'form.droplist'}}; 1074: } else { 1075: @droplist = ($ENV{'form.droplist'}); 1076: } 1077: foreach (@droplist) { 1078: my ($uname,$udom)=split(/\:/,$_); 1079: my $result = &modifystudent($udom,$uname,$ENV{'request.course.id'}); 1080: if ($result eq 'ok' || $result eq 'ok:') { 1081: $r->print('Dropped '.$uname.' at '.$udom.'<br>'); 1082: } else { 1083: $r->print('Error dropping '.$uname.' at '.$udom.': '.$result. 1084: '<br />'); 1085: } 1086: $count++; 1087: } 1088: $r->print('<p><b>Dropped '.$count.' student(s).</b>'); 1089: $r->print('<p>Re-enrollment will re-activate data.'); 1090: } 1091: 1092: # ================================================================ Main Handler 1093: sub handler { 1094: my $r=shift; 1095: if ($r->header_only) { 1096: $r->content_type('text/html'); 1097: $r->send_http_header; 1098: return OK; 1099: } 1100: # Needs to be in a course 1101: if (($ENV{'request.course.fn'}) && 1102: (&Apache::lonnet::allowed('cst',$ENV{'request.course.id'}))) { 1103: # Start page 1104: $r->content_type('text/html') if (! exists($ENV{'form.viewcsv'})); 1105: $r->send_http_header; 1106: $r->print(&header()) if (! exists($ENV{'form.viewcsv'})); 1107: # Phase one, initial screen 1108: unless ($ENV{'form.phase'}) { 1109: &menu_phase_one($r); 1110: } 1111: # Phase two 1112: if ($ENV{'form.associate'} eq 'Reverse Association') { 1113: $ENV{'form.phase'} = 'two'; 1114: if ( $ENV{'form.upfile_associate'} ne 'reverse' ) { 1115: $ENV{'form.upfile_associate'} = 'reverse'; 1116: } else { 1117: $ENV{'form.upfile_associate'} = 'forward'; 1118: } 1119: } 1120: if ($ENV{'form.phase'} eq 'two') { 1121: if ($ENV{'form.fileupload'}) { 1122: &menu_phase_two_upload($r); 1123: } elsif ($ENV{'form.enroll'}) { 1124: &menu_phase_two_enroll($r); 1125: } elsif ($ENV{'form.drop'}) { 1126: &menu_phase_two_drop($r); 1127: } elsif ($ENV{'form.view'}) { 1128: &menu_phase_two_view($r); 1129: } elsif ($ENV{'form.viewcsv'}) { 1130: &menu_phase_two_viewcsv($r); 1131: } 1132: } 1133: # Phase three 1134: if ($ENV{'form.phase'} eq 'three') { 1135: if ($ENV{'form.datatoken'}) { 1136: &upfile_drop_add($r); 1137: } 1138: } 1139: # Phase four 1140: if ($ENV{'form.phase'} eq 'four') { 1141: &drop_student_list($r); 1142: } 1143: # Phase five 1144: if ($ENV{'form.phase'} eq 'five') { 1145: &enroll_single_student($r); 1146: } 1147: # End 1148: $r->print('</form></body></html>') if (! exists($ENV{'form.viewcsv'})); 1149: } else { 1150: # Not in a course, or not allowed to modify parms 1151: $ENV{'user.error.msg'}= 1152: "/adm/dropadd:cst:0:0:Cannot drop or add students"; 1153: return HTTP_NOT_ACCEPTABLE; 1154: } 1155: return OK; 1156: } 1157: 1158: 1; 1159: __END__ 1160: