Annotation of loncom/interface/coursecatalog.pm, revision 1.20
1.17 albertel 1: # The LearningOnline Network with CAPA
2: # Handler for displaying the course catalog interface
3: #
1.20 ! albertel 4: # $Id: coursecatalog.pm,v 1.19 2007/01/14 01:59:37 raeburn Exp $
1.1 raeburn 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:
29: package Apache::coursecatalog;
30:
31: use strict;
32: use lib qw(/home/httpd/lib/perl);
33: use Apache::Constants qw(:common);
34: use Apache::loncommon;
1.7 raeburn 35: use Apache::lonhtmlcommon;
1.1 raeburn 36: use Apache::lonnet;
37: use Apache::lonlocal;
1.6 raeburn 38: use Apache::courseclassifier;
1.1 raeburn 39: use Apache::lonacc;
40: use LONCAPA;
41:
42: sub handler {
43: my ($r) = @_;
44: &Apache::loncommon::content_type($r,'text/html');
45: $r->send_http_header;
46: if ($r->header_only) {
47: return OK;
48: }
1.8 raeburn 49: my %cookies=CGI::Cookie->parse($r->header_in('Cookie'));
50: my $lonid=$cookies{'lonID'};
51: my $lonidsdir=$r->dir_config('lonIDsDir');
52: my $handle;
53: if ($lonid) {
1.12 raeburn 54: $handle=&LONCAPA::clean_handle($lonid->value);
1.8 raeburn 55: }
56: if ((-e "$lonidsdir/$handle.id") && ($handle ne '')) {
57: &Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle);
58: }
1.1 raeburn 59: &Apache::lonacc::get_posted_cgi($r);
60: &Apache::lonlocal::get_language_handle($r);
61: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['sortby']);
1.19 raeburn 62: my $codedom = &Apache::lonnet::default_login_domain();
63:
64: if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne 'public')) {
65: $codedom = $env{'user.domain'};
66: if ($env{'request.role.domain'} ne '') {
67: $codedom = $env{'request.role.domain'};
68: }
69: }
1.7 raeburn 70: my $formname = 'coursecatalog';
1.20 ! albertel 71: my $domdesc = &Apache::lonnet::domain($codedom,'description');
1.7 raeburn 72:
73: &Apache::lonhtmlcommon::clear_breadcrumbs();
1.8 raeburn 74: if ($env{'form.coursenum'} ne '' && &user_is_known()) {
1.7 raeburn 75: &course_details($r,$codedom,$formname,$domdesc);
76: } else {
1.18 raeburn 77: my $numtitles = &course_selector($r,$codedom,$formname,$domdesc);
1.7 raeburn 78: if ($env{'form.state'} eq 'listing') {
1.18 raeburn 79: $r->print(&print_course_listing($codedom,$numtitles).'<br />');
80: }
1.7 raeburn 81: }
82: $r->print(&Apache::loncommon::end_page());
83: return OK;
84: }
85:
86: sub course_details {
87: my ($r,$codedom,$formname,$domdesc) = @_;
88: my $output;
89: my %add_entries = (topmargin => "0",
90: marginheight => "0",);
91: my $start_page =
92: &Apache::loncommon::start_page('Course Catalog','',
93: {
94: 'add_entries' => \%add_entries,
95: 'no_inline_link' => 1,});
96: $r->print($start_page);
1.19 raeburn 97: if ($env{'form.numtitles'} > 0) {
98: &Apache::lonhtmlcommon::add_breadcrumb
99: ({href=>"/adm/coursecatalog",
100: text=>"Select courses"});
101: }
1.7 raeburn 102: &Apache::lonhtmlcommon::add_breadcrumb
1.19 raeburn 103: ({href=>"javascript:document.$formname.submit()",
1.7 raeburn 104: text=>"Course listing"},
105: {text=>"Course details"});
106: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Details'));
107: $r->print('<br />'.&mt('Detailed course information:').'<br /><br />'.
108: '<form name="coursecatalog" method="post">'.
109: &print_course_listing($codedom).'<br /><br />');
110: $r->print('<a href = "javascript:document.coursecatalog.submit()">'.
111: &mt('Back to course listing').'</a>'.
112: '<input type="hidden" name="sortby" value="'.
113: $env{'form.sortby'}.'" />'.
114: '<input type="hidden" name="state" value="listing" /></form>');
115: }
116:
117: sub course_selector {
118: my ($r,$codedom,$formname,$domdesc) = @_;
1.1 raeburn 119: my %coursecodes = ();
120: my %codes = ();
121: my @codetitles = ();
122: my %cat_titles = ();
123: my %cat_order = ();
124: my %idlist = ();
125: my %idnums = ();
126: my %idlist_titles = ();
1.6 raeburn 127: my %by_year;
128: my %by_sem;
129: my %by_dept;
130: my %cat_items;
1.1 raeburn 131: my $caller = 'global';
132: my $format_reply;
133: my $totcodes = 0;
134: my $jscript = '';
1.6 raeburn 135: my ($numtitles,$lasttitle);
136: $totcodes = &Apache::courseclassifier::retrieve_instcodes(\%coursecodes,$codedom,$totcodes);
1.1 raeburn 137: if ($totcodes > 0) {
1.6 raeburn 138: $format_reply = &Apache::lonnet::auto_instcode_format($caller,$codedom,\%coursecodes,\%codes,\@codetitles,\%cat_titles,\%cat_order);
139: if ($format_reply eq 'ok') {
140: my $numtypes = @codetitles;
141: &Apache::courseclassifier::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);
142: my ($scripttext,$longtitles) = &Apache::courseclassifier::javascript_definitions(\@codetitles,\%idlist,\%idlist_titles,\%idnums,\%cat_titles);
143: my $longtitles_str = join('","',@{$longtitles});
144: my $allidlist = $idlist{$codetitles[0]};
145: $numtitles = @codetitles;
146: $lasttitle = $numtitles;
147: if ($numtitles > 4) {
148: $lasttitle = 4;
1.1 raeburn 149: }
1.18 raeburn 150: if ($numtitles == 0) {
151: if (!defined($env{'form.state'})) {
152: $env{'form.state'} = 'listing';
153: }
154: } else {
155: my @data = ('top');
156: for (my $k=0; $k<$lasttitle; $k++) {
157: my $cat = $codetitles[$k];
158: my $level = 1;
159: $level = &recurse_options($codetitles[$k],$idlist{$codetitles[$k]},$level,$cat,\%cat_items,\@data,\%by_year,\%by_sem,\%by_dept);
160: }
161: $scripttext .= &build_javascript(\%by_year,\%by_sem,\%by_dept,\%cat_order,\@codetitles);
162: $jscript .= &javascript_select_filler($formname,$scripttext,\@codetitles,$longtitles_str,$allidlist);
163: if ($env{'form.state'} eq 'listing') {
164: $jscript .= '
1.1 raeburn 165: function setElements() {
166: ';
1.18 raeburn 167: for (my $i=0; $i<@codetitles-1; $i++) {
168: if ($env{'form.'.$codetitles[$i]} != -1) {
169: $jscript .= '
1.1 raeburn 170: for (var j=0; j<document.'.$formname.'.'.$codetitles[$i].'.length; j++) {
171: if (document.'.$formname.'.'.$codetitles[$i].'[j].value == "'.$env{'form.'.$codetitles[$i]}.'") {
172: document.'.$formname.'.'.$codetitles[$i].'.selectedIndex = j;
173: }
174: }
175: ';
1.18 raeburn 176: }
177: }
178: $jscript .= ' courseSet()'."\n";
179: if ($env{'form.'.$codetitles[-1]} != -1) {
180: $jscript .= '
1.6 raeburn 181: for (var j=0; j<document.'.$formname.'.'.$codetitles[-1].'.length; j++) {
182: if (document.'.$formname.'.'.$codetitles[-1].'[j].value == "'.$env{'form.'.$codetitles[-1]}.'") {
183: document.'.$formname.'.'.$codetitles[-1].'.selectedIndex = j;
184: }
185: }
186: ';
1.18 raeburn 187: }
188: $jscript .= '}';
189: }
1.6 raeburn 190: }
1.18 raeburn 191: if ($env{'form.state'} eq 'listing') {
192: $jscript .= qq|
1.1 raeburn 193: function changeSort(caller) {
1.7 raeburn 194: document.$formname.sortby.value = caller;
195: document.$formname.submit();
196: }
197: function setCourseId(caller) {
198: document.$formname.coursenum.value = caller;
199: document.$formname.submit();
1.1 raeburn 200: }\n|;
1.18 raeburn 201: }
1.1 raeburn 202: }
203: my $js = '<script type"text/javascript">'."\n$jscript\n".
204: '</script>';
205: my %add_entries = (topmargin => "0",
1.7 raeburn 206: marginheight => "0",);
1.18 raeburn 207: if (($env{'form.state'} eq 'listing') && ($numtitles > 0)) {
1.7 raeburn 208: $add_entries{'onLoad'} = 'setElements()';
209: }
1.1 raeburn 210: my $start_page =
211: &Apache::loncommon::start_page('Course Catalog',$js,
1.7 raeburn 212: {
1.1 raeburn 213: 'add_entries' => \%add_entries,
214: 'no_inline_link' => 1,});
215: $r->print($start_page);
1.7 raeburn 216: if ($env{'form.state'} eq 'listing') {
1.19 raeburn 217: if ($numtitles > 0) {
218: &Apache::lonhtmlcommon::add_breadcrumb
219: ({href=>"/adm/coursecatalog",
220: text=>"Select courses"},
221: {text=>"Course listing"});
222: } else {
223: &Apache::lonhtmlcommon::add_breadcrumb
224: ({text=>"Course listing"});
225: }
226: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Listing'));
1.7 raeburn 227: } else {
228: &Apache::lonhtmlcommon::add_breadcrumb
229: ({href=>"/adm/coursecatalog",
230: text=>"Select courses"});
231: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Select courses'));
232: }
1.2 raeburn 233: $r->print('<h3>'.&mt('Display information about official [_1] classes for which LON-CAPA courses have been created:',$domdesc).'</h3>');
1.7 raeburn 234: $r->print('<form name="coursecatalog" method="post">');
1.1 raeburn 235: if ($numtitles > 0) {
1.18 raeburn 236: $r->print(&mt('<b>Choose which course(s) to list.</b><br />'));
1.6 raeburn 237: $r->print('<table><tr>');
238: for (my $k=0; $k<$lasttitle-1; $k++) {
239: my @unsorted = @{$cat_items{$codetitles[$k]}};
240: my @items;
241: &Apache::courseclassifier::sort_cats($k,\%cat_order,\@codetitles,\@unsorted,\@items);
242: my @longitems;
243: if (defined($cat_titles{$codetitles[$k]})) {
244: foreach my $item (@items) {
245: push(@longitems,$cat_titles{$codetitles[$k]}{$item});
246: }
1.1 raeburn 247: } else {
1.6 raeburn 248: @longitems = @items;
1.1 raeburn 249: }
1.6 raeburn 250: $r->print('<td align="center">'.$codetitles[$k].'<br />'."\n".
251: '<select name="'.$codetitles[$k].'" onChange="courseSet()"');
252: $r->print('>'."\n".'<option value="0" />All'."\n");
253: for (my $i=0; $i<@items; $i++) {
1.1 raeburn 254: if ($longitems[$i] eq '') {
255: $longitems[$i] = $items[$i];
256: }
1.6 raeburn 257: $r->print(' <option value="'.$items[$i].'">'.$longitems[$i].'</option>');
1.1 raeburn 258: }
1.6 raeburn 259: $r->print('</select></td>');
1.1 raeburn 260: }
1.6 raeburn 261: $r->print('<td align="center">'.$codetitles[$lasttitle-1].'<br />'."\n".
262: '<select name="'.$codetitles[$lasttitle-1].'">'."\n".
263: '<option value="0">All'."\n".
264: '</option>'."\n".'</select>'."\n".
1.1 raeburn 265: '</td>'
266: );
1.16 raeburn 267: if (&user_is_dc($codedom)) {
268: my $showdetails_status;
269: if ($env{'form.showdetails'}) {
270: $showdetails_status = 'checked="checked" ';
271: }
272: $r->print('<td></td><td><input type="checkbox" name="showdetails" value="1" '.$showdetails_status.'/>'.&mt('Show full details for each course (DC only)').'</td>');
273: }
1.1 raeburn 274: $r->print('</tr></table>');
275: if ($numtitles > 4) {
1.6 raeburn 276: $r->print('<br /><br />'.$codetitles[$numtitles-1].'<br />'."\n".
277: '<input type="text" name="'.$codetitles[$numtitles-1].'" /><br />'."\n");
1.1 raeburn 278: }
1.18 raeburn 279: $r->print('<br />');
280: }
281: $r->print('<input type="hidden" name="coursenum" value="" /><input type="hidden" name="sortby" value="" /><input type="hidden" name="state" value="listing" />');
282: if ($numtitles > 0) {
283: $r->print('<input type="submit" name="catalogfilter" value="'.&mt('Display courses').'" />');
284: }
1.19 raeburn 285: $r->print('<input type="hidden" name="numtitles" value="'.
286: $numtitles.'" /></form>');
1.18 raeburn 287: if (($numtitles > 0) && ($env{'form.state'} eq 'listing')) {
288: $r->print('<br /><br />');
1.1 raeburn 289: }
1.5 raeburn 290: } else {
291: $r->print(&Apache::loncommon::start_page('Course Catalog','',
292: {
293: 'no_inline_link' => 1,}));
294: $r->print('<br />'.&mt('No official courses to display for [_1].',$domdesc));
1.1 raeburn 295: }
1.18 raeburn 296: return $numtitles;
1.1 raeburn 297: }
298:
1.16 raeburn 299: sub user_is_dc {
300: my ($codedom) = @_;
301: if (exists($env{'user.role.dc./'.$codedom.'/'})) {
302: my $livedc = 1;
303: my $now = time;
304: my ($start,$end)=split(/\./,$env{'user.role.dc./'.$codedom.'/'});
305: if ($start && $start>$now) { $livedc = 0; }
306: if ($end && $end <$now) { $livedc = 0; }
307: return $livedc;
308: }
309: return;
310: }
1.7 raeburn 311:
1.6 raeburn 312: sub recurse_options {
313: my ($currkey,$currlist,$level,$cat,$cat_options,$data,$by_year,$by_sem,$by_dept) = @_;
314: if (ref($currlist) eq 'HASH') {
315: $level ++;
316: foreach my $key (sort(keys(%{$currlist}))) {
317: $$data[$level-1]= $key;
318: &recurse_options($key,$currlist->{$key},$level,$cat,$cat_options,$data,$by_year,$by_sem,$by_dept);
319: }
320: } else {
321: $level --;
322: my @contents = split(/","/,$currlist);
323: foreach my $item (@contents) {
324: if (!grep(/^\Q$item\E$/,@{$cat_options->{$cat}})) {
325: push(@{$cat_options->{$cat}},$item);
326: }
327: if ($level == 3) {
328: if (!grep/^\Q$item\E$/,@{$by_year->{$data->[1]}->{$currkey}}) {
329: push(@{$by_year->{$data->[1]}->{$currkey}},$item);
330: }
331: if (!grep/^\Q$item\E$/,@{$by_sem->{$data->[2]}->{$currkey}}) {
332: push(@{$by_sem->{$data->[2]}->{$currkey}},$item);
333: }
334: if (!grep/^\Q$item\E$/,@{$by_dept->{$currkey}}) {
335: push(@{$by_dept->{$currkey}},$item);
336: }
337:
338: }
339: }
340: }
341: return $level;
342: }
343:
344: sub build_javascript {
345: my ($by_year,$by_sem,$by_dept,$cat_order,$codetitles) = @_;
346: my @unsorted = keys(%{$by_year});
347: my @sorted_yrs;
348: &Apache::courseclassifier::sort_cats('0',$cat_order,$codetitles,\@unsorted,\@sorted_yrs);
349: my $output = 'var idcse_by_yr_year = new Array("'.join('","',@sorted_yrs).'");'."\n".
350: 'var idcse_by_yr_dept = new Array('.scalar(@sorted_yrs).');'."\n".
351: 'var idcse_by_yr_num = new Array('.scalar(@sorted_yrs).');'."\n";
352: for (my $i=0; $i<@sorted_yrs; $i++) {
353: my $numkeys = keys(%{$by_year->{$sorted_yrs[$i]}});
354: $output .= " idcse_by_yr_num[$i] = new Array($numkeys);\n";
355: if (ref($by_year->{$sorted_yrs[$i]}) eq 'HASH') {
356: @unsorted = keys(%{$by_year->{$sorted_yrs[$i]}});
357: my @sorted_depts;
358: &Apache::courseclassifier::sort_cats('2',$cat_order,$codetitles,\@unsorted,\@sorted_depts);
359: $output .= qq| idcse_by_yr_dept[$i] = new Array ("|.join('","',@sorted_depts).'");'."\n";
360: for (my $j=0; $j<@sorted_depts; $j++) {
361: $output .= qq| idcse_by_yr_num[$i][$j] = new Array ("|;
362: $output .= join('","',sort(@{$by_year->{$sorted_yrs[$i]}->{$sorted_depts[$j]}})).'");'."\n";
363: }
364: }
365: }
366: @unsorted = keys(%{$by_sem});
367: my @sorted_sems;
368: &Apache::courseclassifier::sort_cats('1',$cat_order,$codetitles,\@unsorted,\@sorted_sems);
369: $output .= 'idcse_by_sem_sems = new Array("'.join('","',@sorted_sems).'");'."\n".
370: 'idcse_by_sem_dept = new Array('.scalar(@sorted_sems).');'."\n".
371: 'idcse_by_sem_num = new Array('.scalar(@sorted_sems).');'."\n";
372: for (my $i=0; $i<@sorted_sems; $i++) {
373: my $numkeys = keys(%{$by_sem->{$sorted_sems[$i]}});
374: $output .= " idcse_by_sem_num[$i] = new Array($numkeys);\n";
375: if (ref($by_sem->{$sorted_sems[$i]}) eq 'HASH') {
376: @unsorted = keys(%{$by_sem->{$sorted_sems[$i]}});
377: my @sorted_depts;
378: &Apache::courseclassifier::sort_cats('2',$cat_order,$codetitles,\@unsorted,\@sorted_depts);
379: $output .= qq| idcse_by_sem_dept[$i] = new Array("|.join('","',@sorted_depts).'");'."\n";
380: for (my $j=0; $j<@sorted_depts; $j++) {
381: $output .= qq| idcse_by_sem_num[$i][$j] = new Array ("|.join('","',sort(@{$by_sem->{$sorted_sems[$i]}->{$sorted_depts[$j]}})).'");'."\n";
382: }
383: }
384: }
385: @unsorted = keys(%{$by_dept});
386: my @sorted_deps;
387: &Apache::courseclassifier::sort_cats('2',$cat_order,$codetitles,\@unsorted,\@sorted_deps);
388: $output .= 'idcse_by_dep = new Array('.scalar(@sorted_deps).');'."\n";
389: for (my $k=0; $k<@sorted_deps; $k++) {
390: $output .= qq| idcse_by_dep[$k] = new Array ("|.join('","',sort(@{$by_dept->{$sorted_deps[$k]}})).'");'."\n";
391: }
392: return $output;
393: }
394:
1.7 raeburn 395: sub search_courselist {
1.18 raeburn 396: my ($domain,$numtitles) = @_;
397: my $instcode;
398: if (defined($numtitles) && $numtitles == 0) {
399: $instcode = '.+';
400: } else {
401: my (%codedefaults,@code_order);
402: my $defaults_result =
403: &Apache::lonnet::auto_instcode_defaults($domain,\%codedefaults,
404: \@code_order);
405: if ($defaults_result eq 'ok') {
406: $instcode ='^';
407: foreach my $item (@code_order) {
408: if ($env{'form.'.$item} eq '0' ) {
409: $instcode .= $codedefaults{$item};
410: } else {
411: $instcode .= $env{'form.'.$item};
412: }
1.7 raeburn 413: }
1.18 raeburn 414: $instcode .= '$';
415: } else {
416: $instcode = '.';
1.7 raeburn 417: }
418: }
419: my %courses = &Apache::lonnet::courseiddump($domain,'.',1,$instcode,'.','.',
420: undef,undef,'Course',1);
421: return %courses;
422: }
423:
1.6 raeburn 424:
1.1 raeburn 425: sub print_course_listing {
1.18 raeburn 426: my ($domain,$numtitles) = @_;
1.1 raeburn 427: my $output;
1.7 raeburn 428: my %courses;
1.15 raeburn 429: my $knownuser = &user_is_known();
1.16 raeburn 430: my $details = $env{'form.coursenum'};
431: if (&user_is_dc($domain)) {
432: if ($env{'form.showdetails'}) {
433: $details = 1;
434: }
435: }
1.7 raeburn 436: if ($env{'form.coursenum'} ne '') {
437: %courses = &Apache::lonnet::courseiddump($domain,'.',1,'.','.',
438: $env{'form.coursenum'},
439: undef,undef,'Course');
440: if (keys(%courses) == 0) {
441: $output .= &mt('The courseID provided does not match a course in this domain.');
442: return $output;
443: }
1.6 raeburn 444: } else {
1.18 raeburn 445: %courses = &search_courselist($domain,$numtitles);
1.7 raeburn 446: if (keys(%courses) == 0) {
447: $output = &mt('No courses match the criteria you selected.');
448: return $output;
449: }
1.16 raeburn 450: if ($knownuser && !$env{'form.showdetails'}) {
1.8 raeburn 451: $output = &mt('<b>Note for students:</b> If you are officially enrolled in a course but the course is not listed in your LON-CAPA courses, click the "Show more details" link for the specific course and check the default access dates and/or automated enrollment settings.<br /><br />');
452: }
1.7 raeburn 453: }
1.16 raeburn 454: $output .= &construct_data_table($knownuser,\%courses,$details);
455: $output .= &Apache::lonhtmlcommon::echo_form_input(['coursenum','state','catalogfilter','sortby','showdetails']);
1.15 raeburn 456: return $output;
457: }
458:
459: sub construct_data_table {
460: my ($knownuser,$courses,$details,$usersections) = @_;
1.7 raeburn 461: my %sortname;
1.16 raeburn 462: if (($details eq '') || ($env{'form.showdetails'})) {
1.7 raeburn 463: $sortname{'Code'} = 'code';
464: $sortname{'Title'} = 'title';
465: $sortname{'Owner'} = 'owner';
466: }
1.15 raeburn 467: my $output = &Apache::loncommon::start_data_table().
468: &Apache::loncommon::start_data_table_header_row();
469: my @coltitles = ('Code','Sections','Crosslisted','Title','Owner');
470: if (ref($usersections) eq 'HASH') {
471: $coltitles[1] = 'Your Section';
472: }
1.7 raeburn 473: foreach my $item (@coltitles) {
474: $output .= '<th>';
475: if (defined($sortname{$item})) {
476: $output .= '<a href="javascript:changeSort('."'$sortname{$item}'".')">'.&mt($item).'</a>';
477: } else {
478: $output .= &mt($item);
479: }
480: $output .= '</th>';
1.1 raeburn 481: }
1.15 raeburn 482: if ($knownuser) {
483: if ($details) {
1.8 raeburn 484: $output .=
1.7 raeburn 485: '<th>'.&mt('Default Access Dates for Students').'</th>'.
486: '<th>'.&mt('Student Counts').'</th>'.
487: '<th>'.&mt('Auto-enrollment of <br />registered students').'</th>';
1.15 raeburn 488: } else {
489: $output .= '<th> </th>';
1.8 raeburn 490: }
1.1 raeburn 491: }
1.7 raeburn 492: &Apache::loncommon::end_data_table_header_row();
1.15 raeburn 493: my %courseinfo = &build_courseinfo_hash($courses,$knownuser,$details,
494: $usersections);
1.7 raeburn 495: my %Sortby;
1.15 raeburn 496: foreach my $course (sort(keys(%{$courses}))) {
1.7 raeburn 497: if ($env{'form.sortby'} eq 'code') {
498: push(@{$Sortby{$courseinfo{$course}{'code'}}},$course);
499: } elsif ($env{'form.sortby'} eq 'owner') {
500: push(@{$Sortby{$courseinfo{$course}{'ownerlastname'}}},$course);
501: } else {
502: push(@{$Sortby{$courseinfo{$course}{'title'}}},$course);
503: }
504: }
505: my @sorted_courses;
506: if (($env{'form.sortby'} eq 'code') || ($env{'form.sortby'} eq 'owner')) {
507: @sorted_courses = sort(keys(%Sortby));
1.6 raeburn 508: } else {
1.7 raeburn 509: @sorted_courses = sort { lc($a) cmp lc($b) } (keys(%Sortby));
1.1 raeburn 510: }
1.7 raeburn 511: foreach my $item (@sorted_courses) {
512: foreach my $course (@{$Sortby{$item}}) {
513: $output.=&Apache::loncommon::start_data_table_row();
1.15 raeburn 514: $output.=&courseinfo_row($courseinfo{$course},$knownuser,$details);
1.7 raeburn 515: $output.=&Apache::loncommon::end_data_table_row();
516: }
1.1 raeburn 517: }
1.7 raeburn 518: $output .= &Apache::loncommon::end_data_table();
519: return $output;
520: }
521:
522: sub build_courseinfo_hash {
1.15 raeburn 523: my ($courses,$knownuser,$details,$usersections) = @_;
1.1 raeburn 524: my %courseinfo;
1.7 raeburn 525: my $now = time;
1.15 raeburn 526: foreach my $course (keys(%{$courses})) {
1.1 raeburn 527: my $descr;
1.15 raeburn 528: if ($courses->{$course} =~ m/^([^:]*):/i) {
1.1 raeburn 529: $descr = &unescape($1);
530: } else {
1.15 raeburn 531: $descr = &unescape($courses->{$course});
1.1 raeburn 532: }
533: my $cleandesc=&HTML::Entities::encode($descr,'<>&"');
534: $cleandesc=~s/'/\\'/g;
1.10 raeburn 535: $cleandesc =~ s/^\s+//;
1.1 raeburn 536: my ($cdom,$cnum)=split(/\_/,$course);
1.7 raeburn 537:
1.15 raeburn 538: my ($desc,$instcode,$owner,$ttype) = split(/:/,$courses->{$course});
1.1 raeburn 539: $owner = &unescape($owner);
540: my ($ownername,$ownerdom);
541: if ($owner =~ /:/) {
542: ($ownername,$ownerdom) = split(/:/,$owner);
543: } else {
544: $ownername = $owner;
545: if ($owner ne '') {
546: $ownerdom = $cdom;
547: }
548: }
549: my %ownernames;
550: if ($ownername ne '' && $ownerdom ne '') {
551: %ownernames = &Apache::loncommon::getnames($ownername,$ownerdom);
552: }
553: $courseinfo{$course}{'cdom'} = $cdom;
554: $courseinfo{$course}{'cnum'} = $cnum;
555: $courseinfo{$course}{'code'} = $instcode;
556: $courseinfo{$course}{'ownerlastname'} = $ownernames{'lastname'};
557: $courseinfo{$course}{'title'} = $cleandesc;
1.7 raeburn 558: $courseinfo{$course}{'owner'} = $owner;
559:
560: my %coursehash = &Apache::lonnet::dump('environment',$cdom,$cnum);
561: my @classids;
562: my @crosslistings;
1.15 raeburn 563: my ($seclist,$numsec) =
564: &identify_sections($coursehash{'internal.sectionnums'});
565: if (ref($usersections) eq 'HASH') {
566: if (ref($usersections->{$course}) eq 'ARRAY') {
567: $seclist = join(', ',@{$usersections->{$course}});
568: }
569: }
1.7 raeburn 570: $courseinfo{$course}{'seclist'} = $seclist;
1.15 raeburn 571: my ($xlist_items,$numxlist) =
572: &identify_sections($coursehash{'internal.crosslistings'});
1.7 raeburn 573: my $showsyllabus = 1; # default is to include a syllabus link
574: if (defined($coursehash{'showsyllabus'})) {
575: $showsyllabus = $coursehash{'showsyllabus'};
576: }
577: $courseinfo{$course}{'showsyllabus'} = $showsyllabus;
1.15 raeburn 578: if (((defined($env{'form.coursenum'}) && ($cnum eq $env{'form.coursenum'}))) ||
579: ($knownuser && ($details == 1))) {
580: $courseinfo{$course}{'counts'} = &count_students($cdom,$cnum,$numsec);
581: $courseinfo{$course}{'autoenrollment'} =
582: &autoenroll_info(\%coursehash,$now,$seclist,$xlist_items,
583: $instcode,$owner,$cdom,$cnum);
584:
585: my $startaccess = '';
586: my $endaccess = '';
587: my $accessdates;
588: if ( defined($coursehash{'default_enrollment_start_date'}) ) {
589: $startaccess = &Apache::lonlocal::locallocaltime($coursehash{'default_enrollment_start_date'});
590: }
591: if ( defined($coursehash{'default_enrollment_end_date'}) ) {
592: $endaccess = &Apache::lonlocal::locallocaltime($coursehash{'default_enrollment_end_date'});
593: if ($coursehash{'default_enrollment_end_date'} == 0) {
594: $endaccess = "No ending date";
595: }
596: }
597: if ($startaccess) {
598: $accessdates .= &mt('<i>From:</i> ').$startaccess.'<br />';
1.7 raeburn 599: }
1.15 raeburn 600: if ($endaccess) {
601: $accessdates .= &mt('<i>To:</i> ').$endaccess.'<br />';
602: }
603: $courseinfo{$course}{'access'} = $accessdates;
1.1 raeburn 604: }
1.7 raeburn 605: if ($xlist_items eq '') {
606: $xlist_items = &mt('No');
1.1 raeburn 607: }
1.7 raeburn 608: $courseinfo{$course}{'xlist'} = $xlist_items;
1.1 raeburn 609: }
1.7 raeburn 610: return %courseinfo;
1.1 raeburn 611: }
612:
1.7 raeburn 613: sub count_students {
1.15 raeburn 614: my ($cdom,$cnum,$numsec) = @_;
1.1 raeburn 615: my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1.7 raeburn 616: my %student_count = (
617: Active => 0,
618: Future => 0,
619: Expired => 0,
620: );
1.1 raeburn 621: my %idx;
622: $idx{'status'} = &Apache::loncoursedata::CL_STATUS();
1.4 albertel 623: my %status_title = &Apache::lonlocal::texthash(
1.1 raeburn 624: Expired => 'Previous access',
625: Active => 'Current access',
626: Future => 'Future access',
627: );
1.7 raeburn 628:
1.4 albertel 629: while (my ($student,$data) = each(%$classlist)) {
1.1 raeburn 630: $student_count{$data->[$idx{'status'}]} ++;
631: }
1.7 raeburn 632:
1.15 raeburn 633: my $countslist = &mt('[quant,_1,section]',$numsec).':<br />';
1.7 raeburn 634: foreach my $status ('Active','Future') {
1.1 raeburn 635: $countslist .= '<nobr>'.$status_title{$status}.': '.
636: $student_count{$status}.'</nobr><br />';
637: }
1.7 raeburn 638: return $countslist;
639: }
640:
641: sub courseinfo_row {
1.15 raeburn 642: my ($info,$knownuser,$details) = @_;
1.7 raeburn 643: my ($cdom,$cnum,$title,$ownerlast,$code,$owner,$seclist,$xlist_items,
644: $accessdates,$showsyllabus,$counts,$autoenrollment,$output);
645: if (ref($info) eq 'HASH') {
646: $cdom = $info->{'cdom'};
647: $cnum = $info->{'cnum'};
648: $title = $info->{'title'};
649: $ownerlast = $info->{'ownerlastname'};
650: $code = $info->{'code'};
651: $owner = $info->{'owner'};
652: $seclist = $info->{'seclist'};
653: $xlist_items = $info->{'xlist'};
654: $accessdates = $info->{'access'};
655: $counts = $info->{'counts'};
656: $autoenrollment = $info->{'autoenrollment'};
657: $showsyllabus = $info->{'showsyllabus'};
658: } else {
659: $output = '<td colspan="8">'.&mt('No information available for [_1].',
660: $code).'</td>';
661: return $output;
1.2 raeburn 662: }
1.7 raeburn 663: $output .= '<td>'.$code.'</td>'.
664: '<td>'.$seclist.'</td>'.
665: '<td>'.$xlist_items.'</td>'.
666: '<td>'.$title.' <font size="-2">';
1.2 raeburn 667: if ($showsyllabus) {
668: $output .= &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$cnum,$cdom);
1.7 raeburn 669: } else {
670: $output .= ' ';
1.2 raeburn 671: }
672: $output .= '</font></td>'.
1.7 raeburn 673: '<td>'.$ownerlast.'</td>';
1.15 raeburn 674: if ($knownuser) {
675: if ($details) {
1.8 raeburn 676: $output .=
1.7 raeburn 677: '<td>'.$accessdates.'</td>'.
678: '<td>'.$counts.'</td>'.
679: '<td>'.$autoenrollment.'</td>';
1.15 raeburn 680: } else {
681: $output .= "<td><a href=\"javascript:setCourseId('$cnum')\">".&mt('Show more details').'</a></td>';
1.8 raeburn 682: }
1.7 raeburn 683: }
1.1 raeburn 684: return $output;
685: }
686:
687: sub identify_sections {
688: my ($seclist) = @_;
689: my @secnums;
690: if ($seclist =~ /,/) {
1.4 albertel 691: my @sections = split(/,/,$seclist);
1.1 raeburn 692: foreach my $sec (@sections) {
693: $sec =~ s/:[^:]*$//;
694: push(@secnums,$sec);
695: }
696: } else {
697: if ($seclist =~ m/^([^:]+):/) {
698: my $sec = $1;
1.4 albertel 699: if (!grep(/^\Q$sec\E$/,@secnums)) {
700: push(@secnums,$sec);
1.1 raeburn 701: }
702: }
703: }
704: @secnums = sort {$a <=> $b} @secnums;
705: my $seclist = join(', ',@secnums);
1.15 raeburn 706: my $numsec = @secnums;
707: return ($seclist,$numsec);
1.1 raeburn 708: }
709:
1.2 raeburn 710: sub get_valid_classes {
711: my ($seclist,$xlist_items,$crscode,$owner,$cdom,$cnum) = @_;
712: my $response;
713: my %validations;
714: @{$validations{'sections'}} = ();
715: @{$validations{'xlists'}} = ();
716: my $totalitems = 0;
717: if ($seclist) {
1.13 raeburn 718: foreach my $sec (split(/, /,$seclist)) {
1.2 raeburn 719: my $class = $crscode.$sec;
1.3 albertel 720: if (&Apache::lonnet::auto_validate_class_sec($cdom,$cnum,$owner,
721: $class) eq 'ok') {
1.2 raeburn 722: if (!grep(/^\Q$sec$\E/,@{$validations{'sections'}})) {
1.4 albertel 723: push(@{$validations{'sections'}},$sec);
1.2 raeburn 724: $totalitems ++;
725: }
726: }
727: }
728: }
729: if ($xlist_items) {
1.13 raeburn 730: foreach my $item (split(/, /,$xlist_items)) {
1.3 albertel 731: if (&Apache::lonnet::auto_validate_class_sec($cdom,$cnum,$owner,
732: $item) eq 'ok') {
1.2 raeburn 733: if (!grep(/^\Q$item$\E/,@{$validations{'xlists'}})) {
1.4 albertel 734: push(@{$validations{'xlists'}},$item);
1.2 raeburn 735: $totalitems ++;
736: }
737: }
738: }
739: }
740: if ($totalitems > 0) {
741: if (@{$validations{'sections'}}) {
742: $response = &mt('Sections: ').
1.14 raeburn 743: join(', ',@{$validations{'sections'}}).'<br />';
1.2 raeburn 744: }
745: if (@{$validations{'xlists'}}) {
746: $response .= &mt('Courses: ').
1.14 raeburn 747: join(', ',@{$validations{'xlists'}});
1.2 raeburn 748: }
749: }
750: return $response;
751: }
752:
1.6 raeburn 753: sub javascript_select_filler {
754: my ($formname,$scripttext,$codetitles,$longtitles_str,$allidlist) = @_;
755: my $output = <<END;
756: function courseSet() {
757: var longtitles = new Array ("$longtitles_str");
758: var valyr = document.$formname.Year.options[document.$formname.Year.selectedIndex].value
759: var valsem = document.$formname.Semester.options[document.$formname.Semester.selectedIndex].value
760: var valdept = document.$formname.Department.options[document.$formname.Department.selectedIndex].value
761: var valclass = document.$formname.Number.options[document.$formname.Number.selectedIndex].value
762: var idyears = new Array("$allidlist");
763: var idyr = -1;
764: var idsem = -1;
765: var iddept = -1;
766: document.$formname.Number.length = 0;
767:
768: $scripttext
769:
770: selYear = document.$formname.Year.selectedIndex-1;
771: selSemester = document.$formname.Semester.selectedIndex-1;
772: selDepartment = document.$formname.Department.selectedIndex-1;
773: if (selYear == -1) {
774: if (selSemester == -1) {
775: if (selDepartment > -1) {
776: document.$formname.Number.options[0] = new Option('All','0',false,false);
777: for (var k=0; k<idcse_by_dep[selDepartment].length; k++) {
778: document.$formname.Number.options[k+1] = new Option(idcse_by_dep[selDepartment][k],idcse_by_dep[selDepartment][k],false,false);
779:
780: }
781: }
782: else {
783: document.$formname.Number.options[0] = new Option("All","0",true,true);
784: }
785: }
786: else {
787: if (selDepartment > -1) {
788: for (var i=0; i<idcse_by_sem_sems.length; i++) {
789: if (idcse_by_sem_sems[i] == valsem) {
790: idsem = i;
791: }
792: }
793: if (idsem != -1) {
794: for (var i=0; i<idcse_by_sem_dept[idsem].length; i++) {
795: if (idcse_by_sem_dept[idsem][i] == valdept) {
796: iddept = i;
797: }
798: }
799: }
800: if (iddept != -1) {
801: document.$formname.Number.options[0] = new Option('All','0',false,false);
802: for (var k=0; k<idcse_by_sem_num[idsem][iddept].length; k++) {
803: document.$formname.Number.options[k+1] = new Option(idcse_by_sem_num[idsem][iddept][k],idcse_by_sem_num[idsem][iddept][k],false,false);
804: }
805: }
806: else {
807: document.$formname.Number.options[0] = new Option('No courses','0',true,true);
808: }
809: }
810: else {
811: document.$formname.Number.options[0] = new Option("All","0",true,true);
812: }
813: }
814: }
815: else {
816: if (selSemester == -1) {
817: if (selDepartment > -1) {
818: for (var i=0; i<idcse_by_yr_year.length; i++) {
819: if (idcse_by_yr_year[i] == valyr) {
820: idyr = i;
821: }
822: }
823: if (idyr != -1) {
824: for (var i=0; i<idcse_by_yr_dept[idyr].length; i++) {
825: if (idcse_by_yr_dept[idyr][i] == valdept) {
826: iddept = i;
827: }
828: }
829: }
830: if (iddept != -1) {
831: document.$formname.Number.options[0] = new Option('All','0',false,false);
832: for (var k=0; k<idcse_by_yr_num[idyr][iddept].length; k++) {
833: document.$formname.Number.options[k+1] = new Option(idcse_by_yr_num[idyr][iddept][k],idcse_by_yr_num[idyr][iddept][k],false,false);
834: }
835: }
836: else {
837: document.$formname.Number.options[0] = new Option('No courses','0',true,true);
838: }
839: }
840: else {
841: document.$formname.Number.options[0] = new Option("All","0",true,true);
842: }
843: }
844: else {
1.9 raeburn 845: if (selDepartment > -1) {
846: for (var k=0; k<idyears.length; k++) {
847: if (idyears[k] == valyr) {
848: idyr = k;
849: }
1.6 raeburn 850: }
1.9 raeburn 851: if (idyr != -1) {
852: for (var k=0; k<idsems[idyr].length; k++) {
853: if (idsems[idyr][k] == valsem) {
854: idsem = k;
855: }
1.6 raeburn 856: }
857: }
1.9 raeburn 858: if (idsem != -1) {
859: for (var k=0; k<idcodes[idyr][idsem].length; k++) {
860: if (idcodes[idyr][idsem][k] == valdept) {
861: iddept = k;
862: }
1.6 raeburn 863: }
864: }
1.9 raeburn 865: if (iddept != -1) {
866: document.$formname.Number.options[0] = new Option('All','0',false,false);
867: for (var i=0; i<idcourses[idyr][idsem][iddept].length; i++) {
868: var display = idcourses[idyr][idsem][iddept][i];
869: if (longtitles[3] == 1) {
870: if (idcourseslongs[idyr][idsem][iddept][i] != "") {
871: display = idcourseslongs[idyr][idsem][iddept][i]
872: }
1.6 raeburn 873: }
1.9 raeburn 874: document.$formname.Number.options[i+1] = new Option(display,idcourses[idyr][idsem][iddept][i],false,false)
1.6 raeburn 875: }
1.9 raeburn 876: }
877: else {
878: document.$formname.Number.options[0] = new Option('No courses','0',true,true);
1.6 raeburn 879: }
1.9 raeburn 880: }
1.6 raeburn 881: else {
1.9 raeburn 882: document.$formname.Number.options[0] = new Option('All','0',true,true);
1.6 raeburn 883: }
884: }
885: document.$formname.Number.selectedIndex = 0
886: }
887: }
888: END
889: return $output;
890: }
1.1 raeburn 891:
1.7 raeburn 892: sub autoenroll_info {
893: my ($coursehash,$now,$seclist,$xlist_items,$code,$owner,$cdom,$cnum) = @_;
894: my $autoenrolldates = &mt('Not enabled');
895: if (defined($coursehash->{'internal.autoadds'}) && $coursehash->{'internal.autoadds'} == 1) {
896: my ($autostart,$autoend);
897: if ( defined($coursehash->{'internal.autostart'}) ) {
898: $autostart = &Apache::lonlocal::locallocaltime($coursehash->{'internal.autostart'});
899: }
900: if ( defined($coursehash->{'internal.autoend'}) ) {
901: $autoend = &Apache::lonlocal::locallocaltime($coursehash->{'internal.autoend'});
902: }
903: if ($coursehash->{'internal.autostart'} > $now) {
904: if ($coursehash->{'internal.autoend'} && $coursehash->{'internal.autoend'} < $now) {
905: $autoenrolldates = &mt('Not enabled');
906: } else {
907: my $valid_classes =
908: &get_valid_classes($seclist,$xlist_items,$code,
909: $owner,$cdom,$cnum);
910: if ($valid_classes ne '') {
911: $autoenrolldates = &mt('Not enabled<br />Starts: ').
912: $autostart.'<br />'.$valid_classes; }
913: }
914: } else {
915: if ($coursehash->{'internal.autoend'} && $coursehash->{'internal.autoend'} < $now) {
916: $autoenrolldates = &mt('Not enabled<br />Ended: ').$autoend;
917: } else {
918: my $valid_classes = &get_valid_classes($seclist,$xlist_items,
919: $code,$owner,$cdom,$cnum);
920: if ($valid_classes ne '') {
921: $autoenrolldates = &mt('Currently enabled<br />').
922: $valid_classes;
923: }
924: }
925: }
926: }
927: return $autoenrolldates;
928: }
929:
1.8 raeburn 930: sub user_is_known {
931: my $known = 0;
932: if ($env{'user.name'} ne '' && $env{'user.name'} ne 'public'
933: && $env{'user.domain'} ne '' && $env{'user.domain'} ne 'public') {
934: $known = 1;
935: }
936: return $known;
937: }
938:
1.1 raeburn 939: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>