1: # The LearningOnline Network with CAPA
2: # Handler to drop and add students in courses
3: #
4: # $Id: londropadd.pm,v 1.24 2002/04/15 23:37:37 albertel 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: my $r=shift;
63: $r->print(<<ENDHEAD);
64: <html>
65: <head>
66: <title>LON-CAPA Student Drop/Add</title>
67: </head>
68: <body bgcolor="#FFFFFF">
69: <img align=right src=/adm/lonIcons/lonlogos.gif>
70: <h1>Drop/Add Students</h1>
71: <form method="post" enctype="multipart/form-data"
72: action="/adm/dropadd" name="studentform">
73: <h2>Course: $ENV{'course.'.$ENV{'request.course.id'}.'.description'}</h2>
74: ENDHEAD
75: }
76:
77: # =========== Drop student from all sections of a course, except optional $csec
78:
79: sub dropstudent {
80: my ($udom,$unam,$courseid,$csec)=@_;
81: $courseid=~s/\_/\//g;
82: $courseid=~s/^(\w)/\/$1/;
83: foreach (split(/\&/,
84: &Apache::lonnet::reply('dump:'.$udom.':'.$unam.':roles',
85: &Apache::lonnet::homeserver($unam,$udom)))) {
86: my ($key,$value)=split(/\=/,$_);
87: $key=&Apache::lonnet::unescape($key);
88: if ($key=~/^$courseid(?:\/)*(\w+)*\_st$/) {
89: my $section=$1;
90: if ($key eq $courseid.'_st') { $section=''; }
91: if (((!$section) && (!$csec)) || ($section ne $csec)) {
92: my ($dummy,$end,$start)=split(/\_/,
93: &Apache::lonnet::unescape($value));
94: my $now=time;
95: my $notactive=0;
96: if ($start) {
97: if ($now<$start) { $notactive=1; }
98: }
99: if ($end) {
100: if ($now>$end) { $notactive=1; }
101: }
102: unless ($notactive) {
103: my $reply=&Apache::lonnet::modifystudent(
104: $udom,$unam,'','','',
105: '','','','',$section,time);
106: }
107: }
108: }
109: }
110: }
111:
112: # ============================================================== Menu Phase One
113:
114: sub menu_phase_one {
115: my $r=shift;
116: my $upfile_select=&Apache::loncommon::upfile_select_html();
117: $r->print(<<ENDUPFORM);
118: <input type=hidden name=phase value=two>
119: <hr>
120: <h3>Upload a courselist</h3>
121: $upfile_select
122: <p><input type=submit name=fileupload value="Upload Courselist">
123: <hr>
124: <h3>Enroll a single student</h3>
125: <p><input type=submit name=enroll value="Enroll Student">
126: <hr>
127: <h3>Drop students</h3>
128: <p><input type=submit name=drop value="Selection List">
129: ENDUPFORM
130: }
131:
132:
133: sub phase_two_header {
134: my ($r,$datatoken,$distotal,$krbdefdom)=@_;
135: my $javascript;
136: if ($ENV{'form.upfile_associate'} eq 'reverse') {
137: $javascript=&phase_two_javascript_reverse_associate();
138: } else {
139: $javascript=&phase_two_javascript_forward_associate();
140: }
141: my $javascript_validations=&javascript_validations($krbdefdom);
142: $r->print(<<ENDPICK);
143: <hr>
144: <h3>Identify fields</h3>
145: Total number of records found in file: $distotal <hr />
146: Enter as many fields as you can. The system will inform you and bring you back
147: to this page if the data selected is insufficient to run your class.<hr />
148: <input type="submit" name="associate" value="Reverse Association" />
149: <input type="hidden" name="phase" value="three" />
150: <input type="hidden" name="datatoken" value="$datatoken" />
151: <input type="hidden" name="fileupload" value="$ENV{'form.fileupload'}" />
152: <input type="hidden" name="upfiletype" value="$ENV{'form.upfiletype'}" />
153: <input type="hidden" name="upfile_associate" value="$ENV{'form.upfile_associate'}" />
154: <hr />
155: <script>
156: $javascript
157:
158: $javascript_validations
159: </script>
160: ENDPICK
161: }
162:
163: sub javascript_validations {
164: my ($krbdefdom)=@_;
165: return (<<ENDPICK);
166: function verify_message (vf,founduname,foundpwd,foundname,foundid,foundsec) {
167: var foundatype=0;
168: var message='';
169: if (founduname==0) {
170: alert('You need to specify at least the username field');
171: return;
172: }
173: if (vf.login[0].checked) {
174: foundatype=1;
175: if (vf.krbdom.value=='') {
176: alert('You need to specify the Kerberos domain');
177: return;
178: }
179: }
180: if (vf.login[1].checked) {
181: foundatype=1;
182: if ((vf.intpwd.value=='') && (foundpwd==0)) {
183: alert('You need to specify the initial password');
184: return;
185: }
186: }
187: if (vf.login[2].checked) {
188: foundatype=1;
189: //An argument is not required
190: }
191: if (foundatype==0) {
192: alert('You need to set the login type');
193: return;
194: }
195: if (foundname==0) { message='No name fields specified. '; }
196: if (foundid==0) { message+='No ID or student number field specified. '; }
197: if (foundsec==0) { message+='No section or group field specified. '; }
198: if (vf.startdate.value=='') {
199: message+='No starting date set. ';
200: }
201: if (vf.enddate.value=='') {
202: message+='No ending date set. ';
203: }
204: if ((vf.enddate.value!='') && (vf.startdate.value!='')) {
205: if (Math.round(vf.enddate.value)<Math.round(vf.startdate.value)) {
206: alert('Ending date is before starting date');
207: return;
208: }
209: }
210: if (message!='') {
211: message+='Continue enrollment?';
212: if (confirm(message)) {
213: pclose();
214: vf.submit();
215: }
216: } else {
217: pclose();
218: vf.submit();
219: }
220: }
221:
222: function setkrb(vf) {
223: if (vf.krbdom.value!='') {
224: clearpwd(vf);
225: vf.login[0].checked=true;
226: vf.krbdom.value=vf.krbdom.value.toUpperCase();
227: vf.intpwd.value='';
228: vf.locarg.value='';
229: }
230: }
231:
232: function setint(vf) {
233: if (vf.intpwd.value!='') {
234: clearpwd(vf);
235: vf.login[1].checked=true;
236: vf.krbdom.value='';
237: vf.locarg.value='';
238: }
239: }
240:
241: function setloc(vf) {
242: if (vf.locarg.value!='') {
243: vf.login[2].checked=true;
244: vf.krbdom.value='';
245: vf.intpwd.value='';
246: }
247: }
248:
249: function clickkrb(vf) {
250: vf.krbdom.value='$krbdefdom';
251: clearpwd(vf);
252: vf.intpwd.value='';
253: vf.locarg.value='';
254: }
255:
256: function clickint(vf) {
257: vf.krbdom.value='';
258: vf.locarg.value='';
259: }
260:
261: function clickloc(vf) {
262: vf.krbdom.value='';
263: vf.intpwd.value='';
264: }
265:
266: function pclose() {
267: parmwin=window.open("/adm/rat/empty.html","LONCAPAparms",
268: "height=350,width=350,scrollbars=no,menubar=no");
269: parmwin.close();
270: }
271:
272: function pjump(type,dis,value,marker,ret,call) {
273: parmwin=window.open("/adm/rat/parameter.html?type="+escape(type)
274: +"&value="+escape(value)+"&marker="+escape(marker)
275: +"&return="+escape(ret)
276: +"&call="+escape(call)+"&name="+escape(dis),"LONCAPAparms",
277: "height=350,width=350,scrollbars=no,menubar=no");
278:
279: }
280:
281: function dateset() {
282: if (document.studentform.pres_marker.value=='end') {
283: document.studentform.enddate.value=
284: document.studentform.pres_value.value;
285: }
286: if (document.studentform.pres_marker.value=='start') {
287: document.studentform.startdate.value=
288: document.studentform.pres_value.value;
289: }
290: pclose();
291: }
292:
293: ENDPICK
294: }
295:
296: sub phase_two_javascript_forward_associate {
297: return(<<ENDPICK);
298: function verify(vf) {
299: var founduname=0;
300: var foundpwd=0;
301: var foundname=0;
302: var foundid=0;
303: var foundsec=0;
304: var tw;
305: for (i=0;i<=vf.nfields.value;i++) {
306: tw=eval('vf.f'+i+'.selectedIndex');
307: if (tw==1) { founduname=1; }
308: if ((tw>=2) && (tw<=6)) { foundname=1; }
309: if (tw==7) { foundid=1; }
310: if (tw==8) { foundsec=1; }
311: if (tw==9) { foundpwd=1; }
312: }
313: verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec);
314: }
315:
316:
317: function flip(vf,tf) {
318: var nw=eval('vf.f'+tf+'.selectedIndex');
319: var i;
320: for (i=0;i<=vf.nfields.value;i++) {
321: if ((i!=tf) && (eval('vf.f'+i+'.selectedIndex')==nw)) {
322: eval('vf.f'+i+'.selectedIndex=0;')
323: }
324: }
325: if (tf==1 && nw!=0) {
326: for (i=2;i<=5;i++) {
327: eval('vf.f'+i+'.selectedIndex=0;')
328: }
329: }
330: if (nw==2) {
331: for (i=0;i<=vf.nfields.value;i++) {
332: if ((eval('vf.f'+i+'.selectedIndex')>=3) &&
333: (eval('vf.f'+i+'.selectedIndex')<=6)) {
334: eval('vf.f'+i+'.selectedIndex=0;')
335: }
336: }
337: }
338: if ((nw>=3) && (nw<=6)) {
339: for (i=0;i<=vf.nfields.value;i++) {
340: if (eval('vf.f'+i+'.selectedIndex')==2) {
341: eval('vf.f'+i+'.selectedIndex=0;')
342: }
343: }
344: }
345: if (nw==9) {
346: vf.login[1].checked=true;
347: vf.intpwd.value='';
348: vf.krbdom.value='';
349: vf.locarg.value='';
350: }
351: }
352:
353: function clearpwd(vf) {
354: var i;
355: for (i=0;i<=vf.nfields.value;i++) {
356: if (eval('vf.f'+i+'.selectedIndex')==9) {
357: eval('vf.f'+i+'.selectedIndex=0;')
358: }
359: }
360: }
361:
362: ENDPICK
363: }
364:
365: sub phase_two_javascript_reverse_associate {
366: return(<<ENDPICK);
367: function verify(vf) {
368: var founduname=0;
369: var foundpwd=0;
370: var foundname=0;
371: var foundid=0;
372: var foundsec=0;
373: var tw;
374: for (i=0;i<=vf.nfields.value;i++) {
375: tw=eval('vf.f'+i+'.selectedIndex');
376: if (i==0 && tw!=0) { founduname=1; }
377: if (((i>=1) && (i<=5)) && tw!=0 ) { foundname=1; }
378: if (i==6 && tw!=0) { foundid=1; }
379: if (i==7 && tw!=0) { foundsec=1; }
380: if (i==8 && tw!=0) { foundpwd=1; }
381: }
382: verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec);
383: }
384:
385: function flip(vf,tf) {
386: var nw=eval('vf.f'+tf+'.selectedIndex');
387: var i;
388: // picked the all one one name field, reset the other name ones to blank
389: if (tf==1 && nw!=0) {
390: for (i=2;i<=5;i++) {
391: eval('vf.f'+i+'.selectedIndex=0;')
392: }
393: }
394: //picked one of the piecewise name fields, reset the all in
395: //one field to blank
396: if ((tf>=2) && (tf<=5) && (nw!=0)) {
397: eval('vf.f1.selectedIndex=0;')
398: }
399: // intial password specified, pick internal authentication
400: if (tf==8 && nw!=0) {
401: vf.login[1].checked=true;
402: vf.intpwd.value='';
403: vf.krbdom.value='';
404: vf.locarg.value='';
405: }
406: }
407:
408: function clearpwd(vf) {
409: var i;
410: if (eval('vf.f8.selectedIndex')!=0) {
411: eval('vf.f8.selectedIndex=0;')
412: }
413: }
414: ENDPICK
415: }
416:
417: sub phase_two_end {
418: my ($r,$i,$keyfields,$defdom,$today,$halfyear)=@_;
419: $r->print(<<ENDPICK);
420: </table>
421: <input type=hidden name=nfields value=$i>
422: <input type=hidden name=keyfields value="$keyfields">
423: <h3>Login Type</h3>
424: <p>Note: this will not take effect if the user already exists</p>
425: <p>
426: <input type=radio name=login value=krb onClick="clickkrb(this.form);" />
427: Kerberos authenticated with domain
428: <input type=text size=10 name=krbdom onChange="setkrb(this.form);" />
429: </p>
430: <p>
431: <input type=radio name=login value=int onClick="clickint(this.form);" />
432: Internally authenticated (with initial password
433: <input type=text size=10 name=intpwd onChange="setint(this.form);" />)
434: </p>
435: <p>
436: <input type=radio name=login value=loc onClick="clickloc(this.form);" />
437: Local Authentication with argument
438: <input type=text size=10 name=locarg onChange="setloc(this.form);" />
439: </p>
440: <h3>LON-CAPA Domain for Students</h3>
441: LON-CAPA domain: <input type=text size=10 value=$defdom name=lcdomain><p>
442: <h3>Starting and Ending Dates</h3>
443: <input type="hidden" value='' name="pres_value">
444: <input type="hidden" value='' name="pres_type">
445: <input type="hidden" value='' name="pres_marker">
446: <input type="hidden" value='$today' name=startdate>
447: <input type="hidden" value='$halfyear' name=enddate>
448: <a
449: href="javascript:pjump('date_start','Enrollment Starting Date',document.studentform.startdate.value,'start','studentform.pres','dateset');"
450: >Set Starting Date</a><p>
451:
452: <a
453: href="javascript:pjump('date_end','Enrollment Ending Date',document.studentform.enddate.value,'end','studentform.pres','dateset');"
454: >Set Ending Date</a><p>
455: <h3>Full Update</h3>
456: <input type=checkbox name=fullup value=yes> Full update
457: (also print list of users not enrolled anymore)<p>
458: <h3>ID/Student Number</h3>
459: <input type=checkbox name=forceid value=yes>
460: Disable ID/Student Number Safeguard and Force Change of Conflicting IDs
461: (only do if you know what you are doing)<p>
462: <input type=button onClick="verify(this.form)" value="Update Courselist"><br>
463: Note: for large courses, this operation might be time consuming.
464: ENDPICK
465: }
466:
467: # ======================================================= Menu Phase Two Upload
468:
469: sub menu_phase_two_upload {
470: my $r=shift;
471:
472: my $datatoken;
473: if (!$ENV{'form.datatoken'}) {
474: $datatoken=&Apache::loncommon::upfile_store($r);
475: } else {
476: $datatoken=$ENV{'form.datatoken'};
477: &Apache::loncommon::load_tmp_file($r);
478: }
479: my @records=&Apache::loncommon::upfile_record_sep();
480: my $total=$#records;
481: my $distotal=$total+1;
482:
483: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
484: my $krbdefdom=$1;
485: $krbdefdom=~tr/a-z/A-Z/;
486:
487: my $today=time;
488: my $halfyear=$today+15552000;
489:
490: my $defdom=$r->dir_config('lonDefDomain');
491:
492: &phase_two_header($r,$datatoken,$distotal,$krbdefdom);
493:
494: my $i;
495: my $keyfields;
496: if ($total>=0) {
497: my @d=(['username','Username'],['names','Last Name, First Names'],
498: ['fname','First Name'],['mname','Middle Names/Initials'],
499: ['lname','Last Name'],['gen','Generation'],
500: ['id','ID/Student Number'],['sec','Group/Section'],
501: ['ipwd','Initial Password']);
502: if ($ENV{'form.upfile_associate'} eq 'reverse') {
503: &Apache::loncommon::csv_print_samples($r,\@records);
504: $i=&Apache::loncommon::csv_print_select_table($r,\@records,\@d);
505: foreach (@d) { $keyfields.=$_->[0].','; }
506: chop($keyfields);
507: } else {
508: unshift(@d,['none','']);
509: $i=&Apache::loncommon::csv_samples_select_table($r,\@records,\@d);
510: my %sone=&Apache::loncommon::record_sep($records[0]);
511: $keyfields=join(',',sort(keys(%sone)));
512: }
513: }
514:
515:
516: &phase_two_end($r,$i,$keyfields,$defdom,$today,$halfyear);
517: }
518:
519: # ======================================================= Enroll single student
520:
521: sub enroll_single_student {
522: my $r=shift;
523: $r->print('<h3>Enrolling Student</h3>');
524: if (($ENV{'form.cuname'})&&($ENV{'form.cuname'}!~/\W/)&&
525: ($ENV{'form.cdomain'})&&($ENV{'form.cdomain'}!~/\W/)) {
526: my $amode='';
527: my $genpwd='';
528: if ($ENV{'form.login'} eq 'krb') {
529: $amode='krb4';
530: $genpwd=$ENV{'form.krbdom'};
531: } elsif ($ENV{'form.login'} eq 'int') {
532: $amode='internal';
533: $genpwd=$ENV{'form.intpwd'};
534: } elsif ($ENV{'form.login'} eq 'loc') {
535: $amode='localauth';
536: $genpwd=$ENV{'form.locarg'};
537: if (!$genpwd) { $genpwd=" "; }
538: }
539: if (($amode) && ($genpwd)) {
540: &dropstudent($ENV{'form.cdomain'},$ENV{'form.cuname'},
541: $ENV{'request.course.id'},$ENV{'form.csec'});
542: $r->print(&Apache::lonnet::modifystudent(
543: $ENV{'form.cdomain'},$ENV{'form.cuname'},
544: $ENV{'form.cstid'},$amode,$genpwd,
545: $ENV{'form.cfirst'},$ENV{'form.cmiddle'},
546: $ENV{'form.clast'},$ENV{'form.cgen'},
547: $ENV{'form.csec'},$ENV{'form.enddate'},
548: $ENV{'form.startdate'},$ENV{'form.forceid'}));
549: } else {
550: $r->print('Invalid login mode or password');
551: }
552: } else {
553: $r->print('Invalid username or domain');
554: }
555: }
556:
557: # ======================================================= Menu Phase Two Enroll
558:
559: sub menu_phase_two_enroll {
560: my $r=shift;
561:
562: $ENV{'SERVER_NAME'}=~/(\w+\.\w+)$/;
563: my $krbdefdom=$1;
564: $krbdefdom=~tr/a-z/A-Z/;
565:
566: my $today=time;
567: my $halfyear=$today+15552000;
568:
569: my $defdom=$r->dir_config('lonDefDomain');
570: my $javascript_validations=&javascript_validations($krbdefdom);
571: $r->print(<<ENDSENROLL);
572: <script>
573: function verify(vf) {
574: var founduname=0;
575: var foundpwd=0;
576: var foundname=0;
577: var foundid=0;
578: var foundsec=0;
579: var tw;
580: if ((typeof(vf.cuname.value)!="undefined") && (vf.cuname.value!='') &&
581: (typeof(vf.cdomain.value)!="undefined") && (vf.cdomain.value!='')) {
582: founduname=1;
583: }
584: if ((typeof(vf.cfirst.value)!="undefined") && (vf.cfirst.value!='') &&
585: (typeof(vf.clast.value)!="undefined") && (vf.clast.value!='')) {
586: foundname=1;
587: }
588: if ((typeof(vf.csec.value)!="undefined") && (vf.csec.value!='')) {
589: foundsec=1;
590: }
591: if ((typeof(vf.cstid.value)!="undefined") && (vf.cstid.value!='')) {
592: foundid=1;
593: }
594: if (founduname==0) {
595: alert('You need to specify at least the username and domain fields');
596: return;
597: }
598: verify_message(vf,founduname,foundpwd,foundname,foundid,foundsec);
599: }
600:
601: $javascript_validations
602:
603: function clearpwd(vf) {
604: //nothing else needs clearing
605: }
606:
607: </script>
608: <h3>Personal Data</h3>
609: First Name: <input type=text name=cfirst size=15><br>
610: Middle Name: <input type=text name=cmiddle size=15><br>
611: Last Name: <input type=text name=clast size=15><br>
612: Generation: <input type=text name=cgen size=5><p>
613:
614: ID/Student Number: <input type=text name=cstid size=10><p>
615:
616: Group/Section: <input type=text name=csec size=5><p>
617:
618: <h3>Login Data</h3>
619: Username: <input type=text name=cuname size=15><p>
620: Domain: <input type=text size=10 value=$defdom name=cdomain><p>
621: Note: login settings below will not take effect if the user already exists<p>
622:
623: <input type=radio name=login value=krb onClick="clickkrb(this.form);">
624: Kerberos authenticated with domain
625: <input type=text size=10 name=krbdom onChange="setkrb(this.form);"><p>
626: <input type=radio name=login value=int onClick="clickint(this.form);">
627: Internally authenticated (with initial password
628: <input type=text size=10 name=intpwd onChange="setint(this.form);">)
629: <p>
630: <input type=radio name=login value=loc onClick="clickloc(this.form);" />
631: Local Authentication with argument
632: <input type=text size=10 name=locarg onChange="setloc(this.form);" />
633: </p>
634: <h3>Starting and Ending Dates</h3>
635: <input type="hidden" value='' name="pres_value">
636: <input type="hidden" value='' name="pres_type">
637: <input type="hidden" value='' name="pres_marker">
638: <input type="hidden" value='$today' name=startdate>
639: <input type="hidden" value='$halfyear' name=enddate>
640: <a
641: href="javascript:pjump('date_start','Enrollment Starting Date',document.studentform.startdate.value,'start','studentform.pres','dateset');"
642: >Set Starting Date</a><p>
643:
644: <a
645: href="javascript:pjump('date_end','Enrollment Ending Date',document.studentform.enddate.value,'end','studentform.pres','dateset');"
646: >Set Ending Date</a><p>
647: <h3>ID/Student Number</h3>
648: <input type=checkbox name=forceid value=yes>
649: Disable ID/Student Number Safeguard and Force Change of Conflicting IDs
650: (only do if you know what you are doing)<p>
651: <input type=button onClick="verify(this.form)" value="Enroll as student"><br>
652: <input type=hidden name=phase value=five>
653: ENDSENROLL
654: }
655:
656: # ========================================================= Menu Phase Two Drop
657:
658: sub menu_phase_two_drop {
659: my $r=shift;
660: my $cid=$ENV{'request.course.id'};
661: my $classlst=&Apache::lonnet::reply
662: ('dump:'.$ENV{'course.'.$cid.'.domain'}.':'.
663: $ENV{'course.'.$cid.'.num'}.':classlist',
664: $ENV{'course.'.$cid.'.home'});
665: my %currentlist=();
666: my $now=time;
667: unless ($classlst=~/^error\:/) {
668: foreach (split(/\&/,$classlst)) {
669: my ($name,$value)=split(/\=/,$_);
670: my ($end,$start)=split(/\:/,
671: &Apache::lonnet::unescape($value));
672: my $active=1;
673: if (($end) && ($now>$end)) { $active=0; }
674: if ($active) {
675: $currentlist{&Apache::lonnet::unescape($name)}=1;
676: }
677: }
678: # ----------------------------------------------------------- Print out choices
679: &show_drop_list($r,%currentlist);
680: } else {
681: $r->print(
682: '<font color=red><h3>Could not access classlist: '.$classlst.
683: '</h3></font>');
684: }
685: }
686:
687: # =================================================== Show student list to drop
688:
689: sub show_drop_list {
690: my ($r,%currentlist)=@_;
691: my $cid=$ENV{'request.course.id'};
692:
693: $r->print('<input type=hidden name=phase value=four>');
694: $r->print('<table border=2>');
695: foreach (sort keys %currentlist) {
696: my ($sname,$sdom)=split(/\:/,$_);
697: my %reply=&Apache::lonnet::idrget($sdom,$sname);
698: my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid);
699: my @reply=split(/[\&\=]/,&Apache::lonnet::reply(
700: 'get:'.$sdom.':'.$sname.
701: ':environment:firstname&middlename&lastname&generation',
702: &Apache::lonnet::homeserver($sname,$sdom)));
703: $r->print(
704: '<tr><td><input type=checkbox name="drop:'.$_.'"></td><td>'.
705: $sname.'</td><td>'.$sdom.'</td><td>'.
706: $reply{$sname}.'</td><td>'.
707: &Apache::lonnet::unescape($reply[2]).' '.
708: &Apache::lonnet::unescape($reply[3]).', '.
709: &Apache::lonnet::unescape($reply[0]).' '.
710: &Apache::lonnet::unescape($reply[1]).
711: '</td><td>'.
712: $ssec."</td></tr>\n");
713: }
714: $r->print('</table><br>');
715: $r->print('<input type=submit value="Drop Students">');
716: }
717:
718: # ================================================= Drop/Add from uploaded file
719:
720: sub upfile_drop_add {
721: my $r=shift;
722:
723: &Apache::loncommon::load_tmp_file($r);
724: my @studentdata=&Apache::loncommon::upfile_record_sep();
725:
726: my @keyfields=split(/\,/,$ENV{'form.keyfields'});
727: my $cid=$ENV{'request.course.id'};
728: my %fields=();
729: for (my $i=0;$i<=$ENV{'form.nfields'};$i++) {
730: if ($ENV{'form.upfile_associate'} eq 'reverse') {
731: if ($ENV{'form.f'.$i} ne 'none') {
732: $fields{$keyfields[$i]}=$ENV{'form.f'.$i};
733: }
734: } else {
735: $fields{$ENV{'form.f'.$i}}=$keyfields[$i];
736: }
737: }
738: my $startdate=$ENV{'form.startdate'};
739: my $enddate=$ENV{'form.enddate'};
740: if ($startdate=~/\D/) { $startdate=''; }
741: if ($enddate=~/\D/) { $enddate=''; }
742: my $domain=$ENV{'form.lcdomain'};
743: my $amode='';
744: my $genpwd='';
745: if ($ENV{'form.login'} eq 'krb') {
746: $amode='krb4';
747: $genpwd=$ENV{'form.krbdom'};
748: } elsif ($ENV{'form.login'} eq 'int') {
749: $amode='internal';
750: if ((defined($ENV{'form.intpwd'})) && ($ENV{'form.intpwd'})) {
751: $genpwd=$ENV{'form.intpwd'};
752: }
753: } elsif ($ENV{'form.login'} eq 'loc') {
754: $amode='localauth';
755: if ((defined($ENV{'form.locarg'})) && ($ENV{'form.locarg'})) {
756: $genpwd=$ENV{'form.locarg'};
757: }
758: }
759: unless (($domain=~/\W/) || ($amode eq '')) {
760: $r->print('<h3>Enrolling Students</h3>');
761: my $count=0;
762: my $flushc=0;
763: my %student=();
764: # ----------------------------------------------------------- Get new classlist
765: # --------------------------------------------------------- Enroll new students
766: foreach (@studentdata) {
767: my %entries=&Apache::loncommon::record_sep($_);
768:
769: unless (($entries{$fields{'username'}} eq '') ||
770: (!defined($entries{$fields{'username'}}))) {
771: my $fname=''; my $mname=''; my $lname=''; my $gen='';
772: if (defined($fields{'names'})) {
773: ($lname,$fname,$mname)=
774: ($entries{$fields{'names'}}=~/([^\,]+)\,\s*(\w+)\s*(.*)$/);
775: } else {
776: if (defined($fields{'fname'})) {
777: $fname=$entries{$fields{'fname'}};
778: }
779: if (defined($fields{'mname'})) {
780: $mname=$entries{$fields{'mname'}};
781: }
782: if (defined($fields{'lname'})) {
783: $lname=$entries{$fields{'lname'}};
784: }
785: if (defined($fields{'gen'})) {
786: $gen=$entries{$fields{'gen'}};
787: }
788: }
789: if ($entries{$fields{'username'}}=~/\W/) {
790: $r->print('<p><b>Unacceptable username: '.
791: $entries{$fields{'username'}}.' for user '.
792: $fname.' '.$mname.' '.$lname.' '.$gen.'</b><p>');
793: } else {
794: my $sec='';
795: my $username=$entries{$fields{'username'}};
796: if (defined($fields{'sec'})) {
797: if (defined($entries{$fields{'sec'}})) {
798: $sec=$entries{$fields{'sec'}};
799: }
800: }
801: my $id='';
802: if (defined($fields{'id'})) {
803: if (defined($entries{$fields{'id'}})) {
804: $id=$entries{$fields{'id'}};
805: }
806: $id=~tr/A-Z/a-z/;
807: }
808: my $password='';
809: if ($genpwd) {
810: $password=$genpwd;
811: } else {
812: if (defined($fields{'ipwd'})) {
813: if ($entries{$fields{'ipwd'}}) {
814: $password=$entries{$fields{'ipwd'}};
815: }
816: }
817: }
818: if ($password) {
819: &dropstudent($domain,$username,$cid,$sec);
820: my $reply=&Apache::lonnet::modifystudent(
821: $domain,$username,$id,$amode,$password,
822: $fname,$mname,$lname,$gen,$sec,$enddate,$startdate,
823: $ENV{'form.forceid'});
824: unless ($reply eq 'ok') {
825: $r->print(
826: "<p><b>Error enrolling $username: $reply</b><p>");
827: } else {
828: $count++; $flushc++;
829: $student{$username}=1;
830: $r->print('. ');
831: if ($flushc>15) {
832: $r->rflush;
833: $flushc=0;
834: }
835: }
836: } else {
837: $r->print(
838: "<p><b>No password for $username</b><p>");
839: }
840: }
841: }
842: }
843: $r->print('<p>Processed Students: '.$count);
844: # --------------------------------------------------------------- Drop students
845: if ($ENV{'form.fullup'} eq 'yes') {
846: $r->print('<h3>Dropping Students</h3>');
847: # ------------------------------------------------------- Get current classlist
848: my $classlst=&Apache::lonnet::reply
849: ('dump:'.$ENV{'course.'.$cid.'.domain'}.':'.
850: $ENV{'course.'.$cid.'.num'}.':classlist',
851: $ENV{'course.'.$cid.'.home'});
852: my %currentlist=();
853: my $now=time;
854: unless ($classlst=~/^error\:/) {
855: foreach (split(/\&/,$classlst)) {
856: my ($name,$value)=split(/\=/,$_);
857: my ($end,$start)=split(/\:/,
858: &Apache::lonnet::unescape($value));
859: my $active=1;
860: if (($end) && ($now>$end)) { $active=0; }
861: if ($active) {
862: $currentlist{&Apache::lonnet::unescape($name)}=1;
863: }
864: }
865: # ------------------------------------------------ Now got up-to-date classlist
866: foreach (@studentdata) {
867: my %entries=&Apache::loncommon::record_sep($_);
868: unless (($entries{$fields{'username'}} eq '') ||
869: (!defined($entries{$fields{'username'}}))) {
870: delete($currentlist{
871: $entries{$fields{'username'}}.':'.
872: $domain});
873: }
874: }
875: # ----------------------------------------------------------- Print out choices
876: &show_drop_list($r,%currentlist);
877: } else {
878: $r->print(
879: '<font color=red><h3>Could not access classlist: '.$classlst.
880: '</h3></font>');
881: }
882: }
883: # ------------------------------------------------------------------------ Done
884:
885: }
886: }
887:
888: # ================================================================== Phase four
889:
890: sub drop_student_list {
891: my $r=shift;
892: my $count=0;
893: foreach (keys %ENV) {
894: if ($_=~/^form\.drop\:/) {
895: my ($dummy,$uname,$udom)=split(/\:/,$_);
896: &dropstudent($udom,$uname,$ENV{'request.course.id'});
897: $r->print('Dropped '.$uname.' at '.$udom.'<br>');
898: $count++;
899: }
900: }
901: $r->print('<p><b>Dropped '.$count.' student(s).</b>');
902: $r->print('<p>Re-enrollment will re-activate data.');
903: }
904:
905: # ================================================================ Main Handler
906:
907: sub handler {
908: my $r=shift;
909: $Apache::lonxml::debug=1;
910: if ($r->header_only) {
911: $r->content_type('text/html');
912: $r->send_http_header;
913: return OK;
914: }
915:
916: # ----------------------------------------------------- Needs to be in a course
917:
918: if (($ENV{'request.course.fn'}) &&
919: (&Apache::lonnet::allowed('cst',$ENV{'request.course.id'}))) {
920:
921: # ------------------------------------------------------------------ Start page
922: $r->content_type('text/html');
923: $r->send_http_header;
924: &header($r);
925:
926: # --------------------------------------------------- Phase one, initial screen
927: unless ($ENV{'form.phase'}) {
928: &menu_phase_one($r);
929: }
930: # ------------------------------------------------------------------- Phase two
931:
932: if ($ENV{'form.associate'} eq 'Reverse Association') {
933: $ENV{'form.phase'} = 'two';
934: if ( $ENV{'form.upfile_associate'} ne 'reverse' ) {
935: $ENV{'form.upfile_associate'} = 'reverse';
936: } else {
937: $ENV{'form.upfile_associate'} = 'forward';
938: }
939: }
940: if ($ENV{'form.phase'} eq 'two') {
941: if ($ENV{'form.fileupload'}) {
942: &menu_phase_two_upload($r);
943: } elsif ($ENV{'form.enroll'}) {
944: &menu_phase_two_enroll($r);
945: } elsif ($ENV{'form.drop'}) {
946: &menu_phase_two_drop($r);
947: }
948: }
949:
950:
951:
952:
953: # ----------------------------------------------------------------- Phase three
954: if ($ENV{'form.phase'} eq 'three') {
955: if ($ENV{'form.datatoken'}) {
956: &upfile_drop_add($r);
957: }
958: }
959: # ------------------------------------------------------------------ Phase four
960: if ($ENV{'form.phase'} eq 'four') {
961: &drop_student_list($r);
962: }
963: # ------------------------------------------------------------------ Phase five
964: if ($ENV{'form.phase'} eq 'five') {
965: &enroll_single_student($r);
966: }
967: # ------------------------------------------------------------------------- End
968: $r->print('</form></body></html>');
969: } else {
970: # ----------------------------- Not in a course, or not allowed to modify parms
971: $ENV{'user.error.msg'}=
972: "/adm/dropadd:cst:0:0:Cannot drop or add students";
973: return HTTP_NOT_ACCEPTABLE;
974: }
975: return OK;
976: }
977:
978: 1;
979: __END__
980:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>