Annotation of loncom/interface/coursecatalog.pm, revision 1.5
1.1 raeburn 1: #
2: # Copyright Michigan State University Board of Trustees
3: #
4: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
5: #
6: # LON-CAPA is free software; you can redistribute it and/or modify
7: # it under the terms of the GNU General Public License as published by
8: # the Free Software Foundation; either version 2 of the License, or
9: # (at your option) any later version.
10: #
11: # LON-CAPA is distributed in the hope that it will be useful,
12: # but WITHOUT ANY WARRANTY; without even the implied warranty of
13: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14: # GNU General Public License for more details.
15: #
16: # You should have received a copy of the GNU General Public License
17: # along with LON-CAPA; if not, write to the Free Software
18: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19: #
20: # /home/httpd/html/adm/gpl.txt
21: #
22: # http://www.lon-capa.org/
23: #
24:
25: package Apache::coursecatalog;
26:
27: use strict;
28: use lib qw(/home/httpd/lib/perl);
29: use Apache::Constants qw(:common);
30: use Apache::loncommon;
31: use Apache::lonnet;
32: use Apache::lonlocal;
33: use Apache::lonsupportreq;
34: use Apache::lonacc;
35: use lib '/home/httpd/lib/perl/';
36: use LONCAPA;
37:
38: sub handler {
39: my ($r) = @_;
40: &Apache::loncommon::content_type($r,'text/html');
41: $r->send_http_header;
42: if ($r->header_only) {
43: return OK;
44: }
45: &Apache::lonacc::get_posted_cgi($r);
46: &Apache::lonlocal::get_language_handle($r);
47: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},['sortby']);
48: my $codedom = $Apache::lonnet::perlvar{'lonDefDomain'};
49: my $ccode = '';
50: my %coursecodes = ();
51: my %codes = ();
52: my @codetitles = ();
53: my %cat_titles = ();
54: my %cat_order = ();
55: my %idlist = ();
56: my %idnums = ();
57: my %idlist_titles = ();
58: my $caller = 'global';
59: my $format_reply;
60: my $totcodes = 0;
61: my $jscript = '';
62: my $formname = 'coursecatalog';
1.5 ! raeburn 63: my $domdesc = $Apache::lonnet::domaindescription{$codedom};
1.1 raeburn 64: $totcodes = &Apache::lonsupportreq::retrieve_instcodes(\%coursecodes,$codedom,$totcodes);
65: if ($totcodes > 0) {
66: if ($ccode eq '') {
67: $format_reply = &Apache::lonnet::auto_instcode_format($caller,$codedom,\%coursecodes,\%codes,\@codetitles,\%cat_titles,\%cat_order);
68: if ($format_reply eq 'ok') {
69: my $numtypes = @codetitles;
70: &Apache::lonsupportreq::build_code_selections(\%codes,\@codetitles,\%cat_titles,\%cat_order,\%idlist,\%idnums,\%idlist_titles);
71: &Apache::lonsupportreq::javascript_code_selections($formname,$numtypes,\%cat_titles,\$jscript,\%idlist,\%idnums,\%idlist_titles,\@codetitles);
72: }
73: }
74: if ($env{'form.state'} eq 'listing') {
75: $jscript .= '
76: function setElements() {
77: ';
78: for (my $i=0; $i<@codetitles; $i++) {
79: if ($env{'form.'.$codetitles[$i]} != -1) {
80: $jscript .= '
81: for (var j=0; j<document.'.$formname.'.'.$codetitles[$i].'.length; j++) {
82: if (document.'.$formname.'.'.$codetitles[$i].'[j].value == "'.$env{'form.'.$codetitles[$i]}.'") {
83: document.'.$formname.'.'.$codetitles[$i].'.selectedIndex = j;
84: }
85: }
86: ';
87: $jscript .= ' courseSet('."'$codetitles[$i]'".');'."\n";
88: } else {
89: last;
90: }
91: }
92: $jscript .= '}';
93: $jscript .= qq|
94: function changeSort(caller) {
95: document.coursecatalog.sortby.value = caller;
96: document.coursecatalog.submit();
97: }\n|;
98: }
99: my $js = '<script type"text/javascript">'."\n$jscript\n".
100: '</script>';
101: my %add_entries = (topmargin => "0",
102: marginheight => "0",
103: onLoad =>"setElements()",);
104: my $start_page =
105: &Apache::loncommon::start_page('Course Catalog',$js,
106: {
107: 'add_entries' => \%add_entries,
108: 'no_inline_link' => 1,});
109: $r->print($start_page);
110:
111: my $numtitles = @codetitles;
1.2 raeburn 112: $r->print('<h3>'.&mt('Display information about official [_1] classes for which LON-CAPA courses have been created:',$domdesc).'</h3>');
1.1 raeburn 113: $r->print(&mt('<b>Choose which course(s) to list.</b><br />'));
114: $r->print('<form name="coursecatalog" method="post">');
115: if ($numtitles > 0) {
116: my $lasttitle = $numtitles;
117: if ($numtitles > 4) {
118: $lasttitle = 4;
119: }
120: $r->print('<table><tr><td>'.$codetitles[0].'<br />'."\n".
121: '<select name="'.$codetitles[0].'" onChange="courseSet('."'$codetitles[0]'".')">'."\n".
122: ' <option value="-1" />Select'."\n");
123: my @items = ();
124: my @longitems = ();
125: if ($idlist{$codetitles[0]} =~ /","/) {
1.4 albertel 126: @items = split(/","/,$idlist{$codetitles[0]});
1.1 raeburn 127: } else {
128: $items[0] = $idlist{$codetitles[0]};
129: }
130: if (defined($idlist_titles{$codetitles[0]})) {
131: if ($idlist_titles{$codetitles[0]} =~ /","/) {
1.4 albertel 132: @longitems = split(/","/,$idlist_titles{$codetitles[0]});
1.1 raeburn 133: } else {
134: $longitems[0] = $idlist_titles{$codetitles[0]};
135: }
136: for (my $i=0; $i<@longitems; $i++) {
137: if ($longitems[$i] eq '') {
138: $longitems[$i] = $items[$i];
139: }
140: }
141: } else {
142: @longitems = @items;
143: }
144: for (my $i=0; $i<@items; $i++) {
145: $r->print(' <option value="'.$items[$i].'">'.$longitems[$i].'</option>');
146: }
147: $r->print('</select></td>');
148: for (my $i=1; $i<$numtitles; $i++) {
149: $r->print('<td>'.$codetitles[$i].'<br />'."\n".
150: '<select name="'.$codetitles[$i].'" onChange="courseSet('."'$codetitles[$i]'".')">'."\n".
151: '<option value="-1"><-Pick '.$codetitles[$i-1].'</option>'."\n".
152: '</select>'."\n".
153: '</td>'
154: );
155: }
156: $r->print('</tr></table>');
157: if ($numtitles > 4) {
158: $r->print('<br /><br />'.$codetitles[$numtitles].'<br />'."\n".
159: '<select name="'.$codetitles[$numtitles].
160: '" onChange="courseSet('."'$codetitles[$numtitles]'".')">'."\n".
161: '<option value="-1"><-Pick '.$codetitles[$numtitles-1].
162: '</option>'."\n".'</select>'."\n");
163: }
164: }
165: $r->print('<br /><input type="hidden" name="state" value="listing" /><input type="hidden" name="sortby" value="" /><input type="submit" name="catalogfilter" value="'.&mt('Display courses').'" /></form>');
1.5 ! raeburn 166: } else {
! 167: $r->print(&Apache::loncommon::start_page('Course Catalog','',
! 168: {
! 169: 'no_inline_link' => 1,}));
! 170: $r->print('<br />'.&mt('No official courses to display for [_1].',$domdesc));
1.1 raeburn 171: }
172: if ($env{'form.state'} eq 'listing') {
1.4 albertel 173: $r->print('<br /><br />'.&print_course_listing($codedom));
1.1 raeburn 174: }
175: $r->print(&Apache::loncommon::end_page());
1.5 ! raeburn 176: return OK;
1.1 raeburn 177: }
178:
179: sub print_course_listing {
180: my ($domain) = @_;
181: my $output;
182: my $year = $env{'form.Year'};
183: my $sem = $env{'form.Semester'};
184: my $dept = $env{'form.Department'};
185: my $coursenum = $env{'form.Number'};
186: my $instcode;
187: if ($sem != -1) {
188: $instcode .= $sem;
189: }
190: if ($year != -1) {
191: $instcode .= $year;
192: }
193: if ($dept != -1) {
194: $instcode .= $dept;
195: }
196: if ($coursenum != -1) {
197: $instcode .= $coursenum;
198: }
199: my %courses = &Apache::lonnet::courseiddump($domain,'.',1,$instcode,'.','.',
200: undef,undef,'Course');
201: if (keys(%courses) == 0) {
1.2 raeburn 202: $output = &mt('No courses match the criteria you selected.');
1.1 raeburn 203: return $output;
204: }
1.2 raeburn 205: $output = &mt('<b>Note for students:</b> If you are officially enrolled in a course but there is no student role for the course in your LON-CAPA roles screen, check the default access dates and/or auto-enrollment settings for the course below. Your roles screen displays only currently accessible roles.<br /><br />');
1.1 raeburn 206: $output .= &Apache::loncommon::start_data_table().
207: &Apache::loncommon::start_data_table_header_row().
208: '<th><a href="javascript:changeSort('."'code'".')">'.&mt('Code').'</a></th>'.
209: '<th>'.&mt('Sections').'</th>'.
1.2 raeburn 210: '<th>'.&mt('Crosslisted').'</th>'.
1.1 raeburn 211: '<th><a href="javascript:changeSort('."'title'".')">'.&mt('Title').'</a></th>'.
212: '<th><a href="javascript:changeSort('."'owner'".')">'.&mt('Owner').'</a></th>'.
1.2 raeburn 213: '<th>'.&mt('Student Status').'</th>'.
1.1 raeburn 214: '<th>'.&mt('Default Access Dates').'</th>'.
1.2 raeburn 215: '<th>'.&mt('Auto-enrollment').'</th>'.
1.1 raeburn 216: &Apache::loncommon::end_data_table_header_row();
217: my %courseinfo;
218: foreach my $course (keys(%courses)) {
219: my $descr;
220: if ($courses{$course} =~ m/^([^:]*):/i) {
221: $descr = &unescape($1);
222: } else {
223: $descr = &unescape($courses{$course});
224: }
225: my $cleandesc=&HTML::Entities::encode($descr,'<>&"');
226: $cleandesc=~s/'/\\'/g;
227: my ($cdom,$cnum)=split(/\_/,$course);
1.2 raeburn 228:
1.4 albertel 229: my ($desc,$instcode,$owner,$ttype) = split(/:/,$courses{$course});
1.1 raeburn 230: $owner = &unescape($owner);
231: my ($ownername,$ownerdom);
232: if ($owner =~ /:/) {
233: ($ownername,$ownerdom) = split(/:/,$owner);
234: } else {
235: $ownername = $owner;
236: if ($owner ne '') {
237: $ownerdom = $cdom;
238: }
239: }
240: my %ownernames;
241: if ($ownername ne '' && $ownerdom ne '') {
242: %ownernames = &Apache::loncommon::getnames($ownername,$ownerdom);
243: }
244: $courseinfo{$course}{'cdom'} = $cdom;
245: $courseinfo{$course}{'cnum'} = $cnum;
246: $courseinfo{$course}{'code'} = $instcode;
247: $courseinfo{$course}{'ownerlastname'} = $ownernames{'lastname'};
248: $courseinfo{$course}{'title'} = $cleandesc;
1.2 raeburn 249: $courseinfo{$course}{'owner'} = $owner;
1.1 raeburn 250: }
251: my %Sortby;
252: foreach my $course (sort(keys(%courses))) {
253: if ($env{'form.sortby'} eq 'code') {
254: push(@{$Sortby{$courseinfo{$course}{'code'}}},$course);
255: } elsif ($env{'form.sortby'} eq 'owner') {
256: push(@{$Sortby{$courseinfo{$course}{'ownerlastname'}}},$course);
257: } else {
258: push(@{$Sortby{$courseinfo{$course}{'title'}}},$course);
259: }
260: }
261: my @sorted_courses;
262: if (($env{'form.sortby'} eq 'code') || ($env{'form.sortby'} eq 'owner')) {
263: @sorted_courses = sort(keys(%Sortby));
264: } else {
265: @sorted_courses = sort { lc($a) cmp lc($b) } (keys(%Sortby));
266: }
267: foreach my $item (@sorted_courses) {
268: foreach my $course (@{$Sortby{$item}}) {
269: $output.=&Apache::loncommon::start_data_table_row();
270: $output.=&courseinfo_row($courseinfo{$course});
271: $output.=&Apache::loncommon::end_data_table_row();
272: }
273: }
274: $output .= &Apache::loncommon::end_data_table();
275: return $output;
276: }
277:
278: sub courseinfo_row {
279: my ($info) = @_;
1.2 raeburn 280: my ($cdom,$cnum,$title,$ownerlast,$code,$owner,$output);
1.1 raeburn 281: if (ref($info) eq 'HASH') {
282: $cdom = $info->{'cdom'};
283: $cnum = $info->{'cnum'};
284: $title = $info->{'title'};
1.2 raeburn 285: $ownerlast = $info->{'ownerlastname'};
286: $code = $info->{'code'};
287: $owner = $info->{'owner'};
1.1 raeburn 288: } else {
1.2 raeburn 289: $output = '<td colspan="8">'.&mt('No information available for [_1].',
290: $code).'</td>';
1.1 raeburn 291: return $output;
292: }
293: my %coursehash = &Apache::lonnet::dump('environment',$cdom,$cnum);
294: my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cnum);
295: my %idx;
1.2 raeburn 296: my @classids;
297: my @crosslistings;
1.1 raeburn 298: $idx{'status'} = &Apache::loncoursedata::CL_STATUS();
1.4 albertel 299: my %status_title = &Apache::lonlocal::texthash(
1.1 raeburn 300: Expired => 'Previous access',
301: Active => 'Current access',
302: Future => 'Future access',
303: );
304: my %student_count = (
305: Expired => 0,
306: Active => 0,
307: Future => 0,
308: );
1.4 albertel 309: while (my ($student,$data) = each(%$classlist)) {
1.1 raeburn 310: $student_count{$data->[$idx{'status'}]} ++;
311: }
312: my $seclist = &identify_sections($coursehash{'internal.sectionnums'});
1.2 raeburn 313: my $xlist_items = &identify_sections($coursehash{'internal.crosslistings'});
1.1 raeburn 314: my $countslist;
315: my $startaccess = '';
316: my $endaccess = '';
1.2 raeburn 317: my $now;
318: my ($accessdates,$autoenrolldates,$showsyllabus);
1.1 raeburn 319: if ( defined($coursehash{'default_enrollment_start_date'}) ) {
320: $startaccess = &Apache::lonlocal::locallocaltime($coursehash{'default_enrollment_start_date'});
321: }
322: if ( defined($coursehash{'default_enrollment_end_date'}) ) {
323: $endaccess = &Apache::lonlocal::locallocaltime($coursehash{'default_enrollment_end_date'});
324: if ($coursehash{'default_enrollment_end_date'} == 0) {
325: $endaccess = "No ending date";
326: }
327: }
328: if ($startaccess) {
329: $accessdates .= &mt('From: ').$startaccess.'<br />';
330: }
331: if ($endaccess) {
332: $accessdates .= &mt('To: ').$endaccess.'<br />';
333: }
1.2 raeburn 334: $autoenrolldates = &mt('Not enabled');
335: if (defined($coursehash{'internal.autoadds'}) && $coursehash{'internal.autoadds'} == 1) {
1.1 raeburn 336: my ($autostart,$autoend);
337: if ( defined($coursehash{'internal.autostart'}) ) {
338: $autostart = &Apache::lonlocal::locallocaltime($coursehash{'internal.autostart'});
339: }
340: if ( defined($coursehash{'internal.autoend'}) ) {
341: $autoend = &Apache::lonlocal::locallocaltime($coursehash{'internal.autoend'});
1.2 raeburn 342: }
343: if ($coursehash{'internal.autostart'} > $now) {
344: if ($coursehash{'internal.autoend'} && $coursehash{'internal.autoend'} < $now) {
345: $autoenrolldates = &mt('Not enabled');
346: } else {
347: my $valid_classes = &get_valid_classes($seclist,$xlist_items,
348: $code,$owner,$cdom,$cnum);
349: if ($valid_classes ne '') {
350: $autoenrolldates = &mt('Not enabled<br />Starts: ').
351: $autostart.'<br />'.$valid_classes;
352: }
353: }
354: } else {
355: if ($coursehash{'internal.autoend'} && $coursehash{'internal.autoend'} < $now) {
356: $autoenrolldates = &mt('Not enabled<br />Ended: ').$autoend;
357: } else {
358: my $valid_classes = &get_valid_classes($seclist,$xlist_items,
359: $code,$owner,$cdom,$cnum);
360: if ($valid_classes ne '') {
361: $autoenrolldates = &mt('Currently enabled<br />').
362: $valid_classes;
363: }
1.1 raeburn 364: }
365: }
366: }
1.2 raeburn 367: if (defined($coursehash{'showsyllabus'})) {
368: $showsyllabus = $coursehash{'showsyllabus'};
369: }
1.1 raeburn 370: foreach my $status ('Active','Future','Expired') {
371: $countslist .= '<nobr>'.$status_title{$status}.': '.
372: $student_count{$status}.'</nobr><br />';
373: }
1.2 raeburn 374: if ($xlist_items eq '') {
375: $xlist_items = &mt('No');
376: }
1.1 raeburn 377: $output = '<td>'.$coursehash{'internal.coursecode'}.'</td>'.
378: '<td>'.$seclist.'</td>'.
1.2 raeburn 379: '<td>'.$xlist_items.'</td>'.
380: '<td>'.$title.' <font size="-2">';
381: if ($showsyllabus) {
382: $output .= &Apache::loncommon::syllabuswrapper(&mt('Syllabus'),$cnum,$cdom);
383: }
384: $output .= '</font></td>'.
385: '<td>'.$ownerlast.'</td>'.
386: '<td>'.$countslist.'</td>'.
387: '<td>'.$accessdates.'</td>'.
388: '<td>'.$autoenrolldates.'</td>';
1.1 raeburn 389: return $output;
390: }
391:
392: sub identify_sections {
393: my ($seclist) = @_;
394: my @secnums;
395: if ($seclist =~ /,/) {
1.4 albertel 396: my @sections = split(/,/,$seclist);
1.1 raeburn 397: foreach my $sec (@sections) {
398: $sec =~ s/:[^:]*$//;
399: push(@secnums,$sec);
400: }
401: } else {
402: if ($seclist =~ m/^([^:]+):/) {
403: my $sec = $1;
1.4 albertel 404: if (!grep(/^\Q$sec\E$/,@secnums)) {
405: push(@secnums,$sec);
1.1 raeburn 406: }
407: }
408: }
409: @secnums = sort {$a <=> $b} @secnums;
410: my $seclist = join(', ',@secnums);
411: return $seclist;
412: }
413:
1.2 raeburn 414: sub get_valid_classes {
415: my ($seclist,$xlist_items,$crscode,$owner,$cdom,$cnum) = @_;
416: my $response;
417: my %validations;
418: @{$validations{'sections'}} = ();
419: @{$validations{'xlists'}} = ();
420: my $totalitems = 0;
421: if ($seclist) {
422: foreach my $sec (split(',',$seclist)) {
423: my $class = $crscode.$sec;
1.3 albertel 424: if (&Apache::lonnet::auto_validate_class_sec($cdom,$cnum,$owner,
425: $class) eq 'ok') {
1.2 raeburn 426: if (!grep(/^\Q$sec$\E/,@{$validations{'sections'}})) {
1.4 albertel 427: push(@{$validations{'sections'}},$sec);
1.2 raeburn 428: $totalitems ++;
429: }
430: }
431: }
432: }
433: if ($xlist_items) {
434: foreach my $item (split(',',$xlist_items)) {
1.3 albertel 435: if (&Apache::lonnet::auto_validate_class_sec($cdom,$cnum,$owner,
436: $item) eq 'ok') {
1.2 raeburn 437: if (!grep(/^\Q$item$\E/,@{$validations{'xlists'}})) {
1.4 albertel 438: push(@{$validations{'xlists'}},$item);
1.2 raeburn 439: $totalitems ++;
440: }
441: }
442: }
443: }
444: if ($totalitems > 0) {
445: if (@{$validations{'sections'}}) {
446: $response = &mt('Sections: ').
447: join(',',@{$validations{'sections'}}).'<br />';
448: }
449: if (@{$validations{'xlists'}}) {
450: $response .= &mt('Courses: ').
451: join(',',@{$validations{'xlists'}});
452: }
453: }
454: return $response;
455: }
456:
1.1 raeburn 457:
458: 1;
459:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>