1: # The LearningOnline Network with CAPA
2: # Handler for displaying the course catalog interface
3: #
4: # $Id: coursecatalog.pm,v 1.106 2025/02/15 00:07:48 raeburn 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:
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;
35: use Apache::lonhtmlcommon;
36: use Apache::lonnet;
37: use Apache::lonlocal;
38: use Apache::courseclassifier;
39: use Apache::lonacc;
40: use LONCAPA;
41: use LONCAPA::lonauthcgi;
42:
43: sub handler {
44: my ($r) = @_;
45: &Apache::loncommon::content_type($r,'text/html');
46: $r->send_http_header;
47: if ($r->header_only) {
48: return OK;
49: }
50: my $handle = &Apache::lonnet::check_for_valid_session($r);
51: my $lonidsdir=$r->dir_config('lonIDsDir');
52: if ($handle ne '') {
53: &Apache::lonnet::transfer_profile_to_env($lonidsdir,$handle);
54: }
55: &Apache::lonacc::get_posted_cgi($r);
56: &Apache::lonlocal::get_language_handle($r);
57: &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
58: ['sortby','showdom']);
59:
60: my $serverdefdom = &Apache::lonnet::default_login_domain();
61: my $codedom = $serverdefdom;
62: my $hostname = $r->hostname();
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: }
70: my $formname = 'coursecatalog';
71: if ($env{'form.showdom'} ne '') {
72: $env{'form.showdom'} = &LONCAPA::clean_domain($env{'form.showdom'});
73: if (&Apache::lonnet::domain($env{'form.showdom'}) ne '') {
74: $codedom = $env{'form.showdom'};
75: } else {
76: $env{'form.showdom'} = '';
77: }
78: }
79: my $domdesc = &Apache::lonnet::domain($serverdefdom,'description');
80: &Apache::lonhtmlcommon::clear_breadcrumbs();
81:
82: unless (($serverdefdom eq $codedom) ||
83: (&Apache::lonnet::will_trust('catalog',$serverdefdom,$codedom))) {
84: my $serverdomdesc = &Apache::lonnet::domain($serverdefdom,'description');
85: $r->print(&Apache::loncommon::start_page('Course/Community Catalog'));
86: &Apache::lonhtmlcommon::add_breadcrumb
87: ({href=>"/adm/coursecatalog",
88: text=>"Course/Community Catalog"});
89: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog'));
90: $r->print('<div>'.&mt('Access to catalog LON-CAPA courses/communities unavailable for: "[_1]" on servers run by: "[_2]".',
91: $domdesc,$serverdomdesc).'</div>');
92: $r->print(&Apache::loncommon::end_page());
93: return OK;
94: }
95: my $crscats = &Apache::lonnet::get_dom_cats($codedom);
96: my %domdefaults = &Apache::lonnet::get_domain_defaults($codedom);
97: my $knownuser = &user_is_known();
98: my $canviewall = &canview_all($knownuser,$codedom);
99:
100: my ($cathash,$cattype);
101: if (ref($crscats) eq 'HASH') {
102: %{$cathash} = %{$crscats};
103: } else {
104: $cathash = {};
105: }
106: if ($knownuser || $canviewall) {
107: $cattype = $domdefaults{'catauth'};
108: } else {
109: $cattype = $domdefaults{'catunauth'};
110: }
111: if ($cattype eq '') {
112: $cattype = 'std';
113: }
114: if ($cattype eq 'none') {
115: $r->print(&Apache::loncommon::start_page('Course/Community Catalog'));
116: &Apache::lonhtmlcommon::add_breadcrumb
117: ({href=>"/adm/coursecatalog",
118: text=>"Course/Community Catalog"});
119: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog'));
120: if ($knownuser || $canviewall) {
121: $r->print('<div>'.&mt('No catalog of LON-CAPA courses/communities is provided for: [_1]',$domdesc).'</div>');
122: } else {
123: if ($domdefaults{'catauth'} eq 'none') {
124: $r->print('<div>'.&mt('No catalog of LON-CAPA courses/communities is provided for: [_1]',$domdesc).'</div>');
125: } else {
126: $r->print('<div>'.&mt('The catalog of LON-CAPA courses/communities provided for: "[_1]" is only available to users who are logged in.',$domdesc).'</div>');
127: }
128: }
129: $r->print(&Apache::loncommon::end_page());
130: return OK;
131: }
132:
133: my $cnum;
134: if ($cattype eq 'codesrch') {
135: my ($uniquecode,$codemsg,$brtext);
136: if ($env{'form.uniquecode'}) {
137: $uniquecode = $env{'form.uniquecode'};
138: $uniquecode =~ s/^\s+|\s+$//g;
139: }
140: my $js = '<script type="text/javascript">'."\n".
141: '// <![CDATA['."\n".
142: &courselink_javascript($hostname)."\n".
143: '// ]]>'."\n".
144: '</script>'."\n";
145: $r->print(&Apache::loncommon::start_page('Search for a Course/Community',$js));
146: if ($uniquecode =~ /^\w{6}$/) {
147: &Apache::lonhtmlcommon::add_breadcrumb
148: ({href=>"/adm/coursecatalog",
149: text=>"Course/Community Catalog"});
150: $brtext = 'Search Result';
151: } else {
152: $brtext = 'Course/Community Catalog';
153: }
154: &Apache::lonhtmlcommon::add_breadcrumb
155: ({href=>"/adm/coursecatalog",
156: text=>"$brtext"});
157: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog'));
158: $r->print(&coursesearch($codedom,$domdesc,$uniquecode));
159: if ($uniquecode =~ /^\w{6}$/) {
160: $r->print('<hr />');
161: my $confname = $codedom.'-domainconfig';
162: my %codes = &Apache::lonnet::get('uniquecodes',[$uniquecode],$codedom,$confname);
163: if ($codes{$uniquecode}) {
164: $cnum = $codes{$uniquecode};
165: my %courses = &Apache::lonnet::courseiddump($codedom,'.',1,'.','.',
166: $cnum,undef,undef,'.',1);
167: if (keys(%courses)) {
168: $env{'form.coursenum'} = $cnum;
169: my %courseinfo = &build_courseinfo_hash(\%courses,$knownuser,$codedom,$canviewall);
170: undef($env{'form.coursenum'});
171: if (ref($courseinfo{$codedom.'_'.$cnum}) eq 'HASH') {
172: $r->print(&Apache::lonhtmlcommon::start_pick_box());
173: my @cols = ('title','ownerlastnames','seclist','access');
174: my %lt = &Apache::lonlocal::texthash(
175: title => 'Title',
176: ownerlastnames => 'Owner & Co-owner(s)',
177: seclist => 'Sections',
178: access => 'Default Access Dates for Students',
179: );
180: my @shown;
181: foreach my $item (@cols) {
182: if ($courseinfo{$codedom.'_'.$cnum}{$item}) {
183: push(@shown,$item);
184: }
185: }
186: my $num = 0;
187: foreach my $item (@shown) {
188: $num ++;
189: $r->print(&Apache::lonhtmlcommon::row_title($lt{$item}).
190: $courseinfo{$codedom.'_'.$cnum}{$item});
191: if ($item eq 'title') {
192: if ($courseinfo{$codedom.'_'.$cnum}{'showsyllabus'}) {
193: my $usehttp = 0;
194: if (($ENV{'SERVER_PORT'} == 443) && ($courseinfo{$codedom.'_'.$cnum}{'extsyllplain'})) {
195: unless ((&Apache::lonnet::uses_sts()) ||
196: (&Apache::lonnet::waf_allssl($hostname))) {
197: $usehttp = 1;
198: }
199: }
200: $r->print(' <font size="-2">'.
201: '<a href="javascript:ToSyllabus('."'$codedom','$cnum','$usehttp'".')">'.
202: &mt('Syllabus').'</a></font>');
203: }
204: }
205: my $arg = ( $num == scalar(@shown) ? 1 : '' );
206: $r->print(&Apache::lonhtmlcommon::row_closure($arg));
207: }
208: $r->print(&Apache::lonhtmlcommon::end_pick_box());
209: my $selfenroll = &selfenroll_status($courseinfo{$codedom.'_'.$cnum},$codedom.'_'.$cnum);
210: if ($selfenroll) {
211: $r->print('<br />'.$selfenroll);
212: }
213: $r->print('<form name="linklaunch" method="post" action="">'."\n".
214: '<input type="hidden" name="backto" value="coursecatalog" />'."\n".
215: '<input type="hidden" name="courseid" value="" />'."\n".
216: '</form>'."\n");
217:
218: } else {
219: $codemsg = &mt('Code matched, but course ID to which this mapped is invalid.');
220: }
221: } else {
222: $codemsg = &mt('Code matched, but course ID to which this mapped is invalid.');
223: }
224: } else {
225: $codemsg = &mt('No match');
226: }
227: }
228: $r->print('<br />'.&Apache::loncommon::end_page());
229: return OK;
230: } else {
231: if ($env{'form.coursenum'} ne '') {
232: if ($env{'form.coursenum'} =~ /^$LONCAPA::match_courseid$/) {
233: $cnum = $env{'form.coursenum'};
234: } else {
235: delete($env{'form.coursenum'});
236: }
237: }
238: }
239:
240: my (@cats,@trails,%allitems,%idx,@jsarray,%subcathash,$subcats,%maxd,
241: $toplevelstr,$maxdepthstr);
242: if ($env{'form.withsubcats'}) {
243: $subcats = \%subcathash;
244: }
245: &Apache::loncommon::extract_categories($cathash,\@cats,\@trails,\%allitems,
246: \%idx,\@jsarray,$subcats,\%maxd);
247: if (ref($cats[0]) eq 'ARRAY') {
248: foreach my $item (@{$cats[0]}) {
249: $toplevelstr .= "'".&js_escape($item)."::0',";
250: $maxdepthstr .= "'$maxd{$item}',";
251: }
252: $toplevelstr =~ s/,$//;
253: $maxdepthstr =~ s/,$//;
254: }
255: &validate_input($codedom,\@cats,\%maxd,$cathash);
256: my ($numtitles,@codetitles);
257: if (($env{'form.coursenum'} ne '') && ($knownuser)) {
258: &course_details($r,$codedom,$formname,$domdesc,$hostname,\@trails,
259: \%allitems,\@codetitles);
260: } else {
261: my ($catlinks,$has_subcats,$selitem) = &category_breadcrumbs($codedom,@cats);
262: my $wasacctext = &get_wasactive_text();
263: my $catjs = <<"ENDSCRIPT";
264:
265: function setCatDepth(depth) {
266: var depth = parseInt(depth);
267: if (depth !== NaN) {
268: if (depth > 0) {
269: var possmaxd = 0;
270: var toplevel = new Array($toplevelstr);
271: var maxdepths = new Array($maxdepthstr);
272: if (toplevel.length) {
273: for (var i=0; i<toplevel.length; i++) {
274: var item = unescape(toplevel[i]);
275: if (item == document.coursecats.currcat_0.value) {
276: possmaxd = maxdepths[i];
277: break;
278: }
279: }
280: }
281: if (depth > possmaxd) {
282: depth = possmaxd;
283: }
284: }
285: document.coursecats.catalog_maxdepth.value = depth;
286: } else {
287: document.coursecats.currcat_0.value = '';
288: document.coursecats.catalog_maxdepth.value = '';
289: }
290: document.coursecats.submit();
291: return;
292: }
293:
294: function changeSort(caller) {
295: document.$formname.sortby.value = caller;
296: document.$formname.submit();
297: }
298:
299: function setCourseId(caller) {
300: document.$formname.coursenum.value = caller;
301: document.$formname.submit();
302: }
303:
304: ENDSCRIPT
305: $catjs .= &courselink_javascript($hostname);
306: if (&user_is_dc($codedom) || $canviewall) {
307: $catjs .= <<ENDTOGGJS
308:
309: function toggleStatuses() {
310: if (document.$formname.showdetails.checked) {
311: document.getElementById('statuschoice').style.display='block';
312: document.getElementById('statuscell').style.borderLeft='1px solid';
313: } else {
314: document.getElementById('statuschoice').style.display='none';
315: document.getElementById('statuscell').style.borderLeft='0px';
316: }
317: return;
318: }
319:
320: function toggleWasActive() {
321: if (document.getElementById('counts_Previous')) {
322: if (document.getElementById('counts_Previous').checked) {
323: document.getElementById('choosewasactive').style.display='block';
324: document.getElementById('choosewasacctext').innerHTML = '$wasacctext';
325: } else {
326: document.getElementById('choosewasactive').style.display='none';
327: document.getElementById('choosewasacctext').innerHTML = '';
328: }
329: }
330: return;
331: }
332:
333: ENDTOGGJS
334: }
335: if ($env{'form.currcat_0'} eq 'instcode::0') {
336: $numtitles = &instcode_course_selector($r,$codedom,$formname,$domdesc,
337: $catlinks,$catjs,\@codetitles,$cattype,$canviewall);
338: if ($env{'form.state'} eq 'listing') {
339: $r->print(&print_course_listing($codedom,$numtitles,undef,undef,undef,
340: \@codetitles,$canviewall,$hostname));
341: }
342: } else {
343: my (%add_entries);
344: my ($currdepth,$deeper) = &get_depth_values();
345: if ($selitem) {
346: my $alert = &mt('Choose a subcategory to display');
347: if (!$deeper) {
348: $alert = &mt('Choose a category to display');
349: }
350: &js_escape(\$alert);
351: $catjs .= <<ENDJS;
352: function check_selected() {
353: if (document.coursecats.$selitem.options[document.coursecats.$selitem.selectedIndex].value == "") {
354: alert('$alert');
355: return false;
356: }
357: }
358: ENDJS
359: }
360: my $js = '<script type="text/javascript">'."\n".
361: '// <![CDATA['."\n".
362: "$catjs\n".
363: '// ]]>'."\n".
364: '</script>';
365: &cat_header($r,$codedom,$js,\%add_entries,$catlinks,undef,$cattype);
366: if ($env{'form.currcat_0'} ne '') {
367: $r->print('<form name="'.$formname.
368: '" method="post" action="/adm/coursecatalog">'.
369: &additional_filters($codedom,$has_subcats,$canviewall)."\n");
370: $r->print('<input type="hidden" name="catalog_maxdepth" value="'.
371: $deeper.'" />'."\n");
372: for (my $i=0; $i<$deeper; $i++) {
373: $r->print('<input type="hidden" name="currcat_'.$i.'" value="'.$env{'form.currcat_'.$i}.'" />'."\n");
374: }
375: my $display_button;
376: if ($env{'form.currcat_0'} eq 'communities::0') {
377: $display_button = &mt('Display communities');
378: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
379: $display_button = &mt('Display placement tests');
380: } else {
381: $display_button = &mt('Display courses');
382: }
383: $r->print('<input type="hidden" name="coursenum" value="" />'."\n".
384: '<input type="hidden" name="sortby" value="" />'."\n".
385: '<input type="hidden" name="state" value="listing" />'."\n".
386: '<input type="hidden" name="showdom" value="'.
387: $env{'form.showdom'}.'" />'.
388: '<input type="submit" name="catalogfilter" value="'.
389: $display_button.'" /></form><br /><br />');
390: }
391: if ($env{'form.state'} eq 'listing') {
392: $r->print(&print_course_listing($codedom,undef,\@trails,\%allitems,$subcats,\@codetitles,
393: $canviewall,$hostname));
394: }
395: }
396: }
397: $r->print('<br />'.&Apache::loncommon::end_page());
398: return OK;
399: }
400:
401: sub validate_input {
402: my ($codedom,$cats,$maxd,$crscatsref) = @_;
403: my $currcat = '';
404: my $depth = 0;
405: if ($env{'form.catalog_maxdepth'} ne '') {
406: $env{'form.catalog_maxdepth'} =~ s{\D}{}g;
407: }
408: if ((ref($cats) eq 'ARRAY') && (ref($maxd) eq 'HASH')) {
409: if (ref($cats->[0]) eq 'ARRAY') {
410: if (@{$cats->[0]} == 1) {
411: if ($cats->[0][0] eq 'instcode') {
412: $currcat = 'instcode::0';
413: } elsif ($cats->[0][0] eq 'communities') {
414: $currcat = 'communities::0';
415: } elsif ($cats->[0][0] eq 'placement') {
416: $currcat = 'placement::0';
417: } else {
418: my $name = $cats->[0][0];
419: $currcat = &escape($name).'::0';
420: }
421: if (exists($maxd->{$cats->[0][0]})) {
422: if ($env{'form.catalog_maxdepth'} <= $maxd->{$cats->[0][0]}) {
423: $depth = $env{'form.catalog_maxdepth'};
424: } else {
425: $depth = $maxd->{$cats->[0][0]};
426: }
427: }
428: } elsif ((@{$cats->[0]} > 1) && ($env{'form.currcat_0'} ne '')) {
429: my ($escname) = ($env{'form.currcat_0'} =~ /^([^:]+)\:\:0$/);
430: if ($escname =~ /^instcode|communities|placement$/) {
431: $currcat = $env{'form.currcat_0'};
432: if (exists($maxd->{$escname})) {
433: if ($env{'form.catalog_maxdepth'} <= $maxd->{$escname}) {
434: $depth = $env{'form.catalog_maxdepth'};
435: } else {
436: $depth = $maxd->{$escname};
437: }
438: } else {
439: $depth = 1;
440: }
441: } elsif ($escname ne '') {
442: my $name = &unescape($escname);
443: if (grep(/^\Q$name\E$/,@{$cats->[0]})) {
444: $currcat = $env{'form.currcat_0'};
445: if (exists($maxd->{$name})) {
446: if ($env{'form.catalog_maxdepth'} <= $maxd->{$name}) {
447: $depth = $env{'form.catalog_maxdepth'};
448: } else {
449: $depth = $maxd->{$name};
450: }
451: }
452: }
453: }
454: }
455: }
456: }
457: $env{'form.currcat_0'} = $currcat;
458: $env{'form.catalog_maxdepth'} = $depth;
459:
460: my %possibles = (
461: backto => 1,
462: catalogfilter => 1,
463: catalog_maxdepth => 1,
464: courseid => 1,
465: coursenum => 1,
466: currcat_0 => 1,
467: numtitles => 1,
468: Year => 1,
469: Semester => 1,
470: Department => 1,
471: Number => 1,
472: showdom => 1,
473: sortby => 1,
474: showcounts => 1,
475: showdetails => 1,
476: showhidden => 1,
477: showselfenroll => 1,
478: state => 1,
479: uniquecode => 1,
480: wasactive => 1,
481: wasactiveon_day => 1,
482: wasactiveon_month => 1,
483: wasactiveon_year => 1,
484: withsubcats => 1,
485: );
486: my %currcats;
487: if ($env{'form.catalog_maxdepth'} > 0) {
488: for (my $i=1; $i<=$env{'form.catalog_maxdepth'}; $i++) {
489: $currcats{'currcat_'.$i} = 1;
490: $possibles{'currcat_'.$i} = 1;
491: }
492: }
493:
494: foreach my $key (sort(keys(%env))) {
495: if ($key =~ /^form\.(.+)$/) {
496: unless ($possibles{$1}) {
497: delete($env{$key});
498: }
499: }
500: }
501: if (exists($env{'form.backto'})) {
502: unless ($env{'form.backto'} eq 'coursecatalog') {
503: delete($env{'form.backto'});
504: }
505: }
506: if (exists($env{'form.catalogfilter'})) {
507: unless (($env{'form.catalogfilter'} eq &mt('Display courses')) ||
508: ($env{'form.catalogfilter'} eq &mt('Display communities')) ||
509: ($env{'form.catalogfilter'} eq &mt('Display placement tests'))) {
510: delete($env{'form.catalogfilter'});
511: }
512: }
513: if (exists($env{'form.courseid'})) {
514: if ($env{'form.courseid'} ne '') {
515: unless ($env{'form.courseid'} =~ /^\Q$codedom\E_$LONCAPA::match_courseid$/) {
516: $env{'form.courseid'} = '';
517: }
518: }
519: }
520: if (exists($env{'form.coursenum'})) {
521: unless ($env{'form.coursenum'} =~ /^$LONCAPA::match_courseid$/) {
522: $env{'form.coursenum'} = '';
523: }
524: }
525: if (exists($env{'form.currcat_0'})) {
526: unless ($env{'form.currcat_0'} =~ /^(instcode|communities|placement)\Q::0\E$/) {
527: if ($env{'form.currcat_0'} =~ /^.+\Q::0\E$/) {
528: if (ref($crscatsref) eq 'HASH') {
529: unless (exists($crscatsref->{$env{'form.currcat_0'}})) {
530: delete($env{'form.currcat_0'});
531: }
532: } else {
533: delete($env{'form.currcat_0'});
534: }
535: } else {
536: delete($env{'form.currcat_0'});
537: }
538: }
539: }
540: if (exists($env{'form.numtitles'})) {
541: unless ($env{'form.numtitles'} =~ /^\d+$/) {
542: delete($env{'form.numtitles'});
543: }
544: }
545: my ($gotcodes,%possvals);
546: foreach my $item ('Year','Semester','Department','Number') {
547: if (exists($env{'form.'.$item})) {
548: unless ($env{'form.'.$item} eq '0') {
549: unless ($gotcodes) {
550: $gotcodes = &get_instcode_allowable($codedom,\%possvals);
551: }
552: if (ref($possvals{$item}) eq 'HASH') {
553: unless (exists($possvals{$item}{$env{'form.'.$item}})) {
554: delete($env{'form.'.$item});
555: }
556: } else {
557: delete($env{'form.'.$item});
558: }
559: }
560: }
561: }
562: if (exists($env{'form.showdom'})) {
563: unless ($env{'form.showdom'} =~ /^$LONCAPA::match_domain$/) {
564: delete($env{'form.showdom'});
565: }
566: }
567: if (exists($env{'form.sortby'})) {
568: unless ($env{'form.sortby'} =~ /^(title|code|owner|cats)$/) {
569: delete($env{'form.sortby'});
570: }
571: }
572: if (exists($env{'form.showcounts'})) {
573: if (ref($env{'form.showcounts'}) eq 'ARRAY') {
574: foreach my $item (@{$env{'form.showcounts'}}) {
575: unless ($item =~ /^(Active|Future|Previous)$/) {
576: delete($env{'form.showcounts'});
577: last;
578: }
579: }
580: } else {
581: unless ($env{'form.showcounts'} =~ /^(Active|Future|Previous)$/) {
582: delete($env{'form.showcounts'});
583: }
584: }
585: }
586: foreach my $item ('showhidden','showdetails','showselfenroll','withsubcats') {
587: if (exists($env{'form.'.$item})) {
588: unless ($env{'form.'.$item} eq '1') {
589: delete($env{'form.'.$item});
590: }
591: }
592: }
593: if (exists($env{'form.state'})) {
594: unless ($env{'form.state'} eq 'listing') {
595: delete($env{'form.state'});
596: }
597: }
598: if (exists($env{'form.uniquecode'})) {
599: unless ($env{'form.uniquecode'} =~ /^\w{6}$/) {
600: delete($env{'form.uniquecode'});
601: }
602: }
603: if (exists($env{'form.wasactive'})) {
604: unless (($env{'form.wasactive'} eq 'accessend') || ($env{'form.wasactive'} eq 'enrollend')) {
605: delete($env{'form.wasactive'});
606: }
607: }
608: if (exists($env{'form.wasactiveon_day'})) {
609: my $tmpday = $env{'form.wasactiveon_day'};
610: unless (($tmpday =~ /^\d+$/) && ($tmpday > 0) && ($tmpday < 32)) {
611: delete($env{'form.wasactiveon_day'});
612: }
613: }
614: if (exists($env{'form.wasactiveon_month'})) {
615: my $tmpmonth = $env{'form.wasactiveon_month'};
616: unless (($tmpmonth =~ /^\d+$/) && ($tmpmonth > 0) && ($tmpmonth < 13)) {
617: delete($env{'form.wasactiveon_month'});
618: }
619: }
620: if (exists($env{'form.wasactiveon_year'})) {
621: my $tmpyear = $env{'form.wasactiveon_year'};
622: unless (($tmpyear =~ /^\d+$/) && ($tmpyear >= 1970)) {
623: delete($env{'form.wasactiveon_year'});
624: }
625: }
626: if (keys(%currcats)) {
627: foreach my $key (keys(%currcats)) {
628: if ($env{'form.'.$key} eq '') {
629: delete($env{'form.'.$key});
630: } elsif (ref($crscatsref) eq 'HASH') {
631: unless (exists($crscatsref->{$env{'form.'.$key}})) {
632: delete($env{'form.'.$key});
633: }
634: } else {
635: delete($env{'form.'.$key});
636: }
637: }
638: }
639: return;
640: }
641:
642: sub get_instcode_allowable {
643: my ($codedom,$possvalref) = @_;
644: return 1 unless (ref($possvalref) eq 'HASH');
645: my $instcats = &Apache::lonnet::get_dom_instcats($codedom);
646: if (ref($instcats) eq 'HASH') {
647: if ((ref($instcats->{'codetitles'}) eq 'ARRAY') && (ref($instcats->{'codes'}) eq 'HASH')) {
648: my %codes = %{$instcats->{'codes'}};
649: my @codetitles = @{$instcats->{'codetitles'}};
650: my @standardnames = &Apache::loncommon::get_standard_codeitems();
651: my %local_to_standard;
652: for (my $i=0; $i<@codetitles; $i++) {
653: $local_to_standard{$codetitles[$i]} = $standardnames[$i];
654: $possvalref->{$standardnames[$i]} = {};
655: }
656: foreach my $cid (sort(keys(%codes))) {
657: if (ref($codes{$cid}) eq 'HASH') {
658: foreach my $item (keys(%{$codes{$cid}})) {
659: $possvalref->{$local_to_standard{$item}}{$codes{$cid}{$item}} = 1;
660: }
661: }
662: }
663: }
664: }
665: return 1;
666: }
667:
668: sub course_details {
669: my ($r,$codedom,$formname,$domdesc,$hostname,$trails,$allitems,$codetitles) = @_;
670: my $output;
671: my %add_entries = (topmargin => "0",
672: marginheight => "0",);
673: my $js = '<script type="text/javascript">'."\n".
674: &courselink_javascript($hostname).'</script>'."\n";
675: my $start_page =
676: &Apache::loncommon::start_page('Course/Community Catalog',$js,
677: {'add_entries' => \%add_entries, });
678: $r->print($start_page);
679: if ($env{'form.numtitles'} > 0) {
680: &Apache::lonhtmlcommon::add_breadcrumb
681: ({href=>"/adm/coursecatalog",
682: text=>"Course/Community Catalog"});
683: }
684: my $brtextone = 'Course listing';
685: my $brtexttwo = 'Course details';
686: my $textthree = &mt('Detailed course information:');
687: my $textfour = &mt('Back to course listing');
688: if ($env{'form.currcat_0'} eq 'communities::0') {
689: $brtextone = 'Community listing';
690: $brtexttwo = 'Community details';
691: $textthree = &mt('Detailed community information:');
692: $textfour = &mt('Back to community listing');
693: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
694: $brtextone = 'Placement test listing';
695: $brtexttwo = 'Placement test details';
696: $textthree = &mt('Detailed placement test information:');
697: $textfour = &mt('Back to placement test listing');
698: }
699: &Apache::lonhtmlcommon::add_breadcrumb
700: ({href=>"javascript:document.$formname.submit()",
701: text=>$brtextone},
702: {text=>$brtexttwo});
703: $r->print(
704: &Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog').
705: '<h2>'.$textthree.'</h2>'.
706: &print_course_listing($codedom,undef,$trails,$allitems,undef,$codetitles,undef,$hostname).
707: '<br />'.
708: '<form name="'.$formname.'" method="post" action="/adm/coursecatalog">'.
709: &Apache::lonhtmlcommon::actionbox([
710: '<a href = "javascript:document.coursecatalog.submit()">'.$textfour.'</a>']).
711: &Apache::lonhtmlcommon::echo_form_input(['coursenum','catalogfilter',
712: 'showdetails','courseid']).
713: '</form>');
714: return;
715: }
716:
717: sub coursesearch {
718: my ($codedom,$domdesc,$uniquecode) = @_;
719: my %lt = &Apache::lonlocal::texthash (
720: crlk => 'Course look-up',
721: code => 'Code',
722: ifyo => 'Enter the course code (six letters and numbers)',
723: srch => 'Find course',
724: );
725: return <<"END";
726: <h3>$lt{'crlk'} ($domdesc)</h3>
727: $lt{'ifyo'}
728: <form name="searchbycode" method="post" action="">
729: <span class="LC_nobreak">
730: <input type="text" value="$uniquecode" size="6" name="uniquecode" />
731: <br />
732: <input type="submit" value="$lt{'srch'}" name="srch" /></span>
733: </form>
734: END
735: }
736:
737: sub courselink_javascript {
738: my ($hostname) = @_;
739: return <<"END";
740:
741: function ToSyllabus(cdom,cnum,usehttp) {
742: if (cdom == '' || cdom == null) {
743: return;
744: }
745: if (cnum == '' || cnum == null) {
746: return;
747: }
748: document.linklaunch.action = "/public/"+cdom+"/"+cnum+"/syllabus";
749: if (usehttp == 1) {
750: var hostname = '$hostname';
751: if (hostname != '') {
752: document.linklaunch.action = 'http://'+hostname+document.linklaunch.action;
753: }
754: document.linklaunch.action += '?usehttp=1';
755: }
756: document.linklaunch.submit();
757: }
758:
759: function ToSelfenroll(courseid) {
760: if (courseid == '') {
761: return;
762: }
763: document.linklaunch.action = "/adm/selfenroll";
764: document.linklaunch.courseid.value = courseid;
765: document.linklaunch.submit();
766: }
767:
768: END
769: }
770:
771: sub instcode_course_selector {
772: my ($r,$codedom,$formname,$domdesc,$catlinks,$catjs,$codetitles,$cattype,$canviewall) = @_;
773: my %cat_titles = ();
774: my %cat_order = ();
775: my %cat_items = ();
776: my %add_entries = (topmargin => "0",
777: marginheight => "0",);
778: my ($jscript,$totcodes,$numtitles,$lasttitle) =
779: &Apache::courseclassifier::instcode_selectors_data($codedom,$formname,
780: \%cat_items,$codetitles,\%cat_titles,\%cat_order);
781: my $js = '<script type="text/javascript">'."\n".
782: '// <![CDATA['."\n".
783: "$jscript\n$catjs\n".
784: '// ]]>'."\n".
785: '</script>';
786: if ($totcodes) {
787: if (($env{'form.state'} eq 'listing') && ($numtitles > 0)) {
788: $add_entries{'onload'} = 'setElements();';
789: }
790: if (&user_is_dc($codedom) || $canviewall) {
791: $add_entries{'onload'} .= ' toggleStatuses();toggleWasActive();'
792: }
793: &cat_header($r,$codedom,$js,\%add_entries,$catlinks,$numtitles,$cattype);
794: my $cat_maxdepth = $env{'form.catalog_maxdepth'};
795: $r->print('<form name="'.$formname.'" method="post" action="/adm/coursecatalog">'.
796: '<input type="hidden" name="catalog_maxdepth" value="'.$cat_maxdepth.'" />'."\n".
797: '<input type="hidden" name="showdom" value="'.$env{'form.showdom'}.'" />'."\n".
798: '<input type="hidden" name="currcat_0" value="instcode::0" />'.
799: &additional_filters($codedom,undef,$canviewall));
800: if ($numtitles > 0) {
801: $r->print('<b>'.&mt('Choose which course(s) to list.').'</b><br />'.
802: &Apache::courseclassifier::build_instcode_selectors($numtitles,
803: $lasttitle,\%cat_items,$codetitles,\%cat_titles,\%cat_order));
804: }
805: $r->print('<input type="hidden" name="coursenum" value="" />'."\n".
806: '<input type="hidden" name="sortby" value="" />'."\n".
807: '<input type="hidden" name="state" value="listing" />'."\n".
808: '<input type="submit" name="catalogfilter" value="'.
809: &mt('Display courses').'" />'.
810: '<input type="hidden" name="numtitles" value="'.$numtitles.
811: '" /></form><br /><br />');
812: } else {
813: $js = '<script type="text/javascript">'."\n".
814: '// <![CDATA['."\n".
815: "$catjs\n".
816: '// ]]>'."\n".
817: '</script>';
818: &cat_header($r,$codedom,$js,\%add_entries,$catlinks,$numtitles,$cattype);
819: my $cat_maxdepth = $env{'form.catalog_maxdepth'};
820: $r->print('<form name="'.$formname.'" method="post" action="/adm/coursecatalog">'.
821: '<input type="hidden" name="catalog_maxdepth" value="'.$cat_maxdepth.'" />'.
822: '<input type="hidden" name="showdom" value="'.$env{'form.showdom'}.'" />'.
823: '<input type="hidden" name="currcat_0" value="instcode::0" />');
824: $r->print('<br />'.&mt('No official courses to display for [_1].',$domdesc).'</form>');
825: }
826: return $numtitles;
827: }
828:
829: sub cat_header {
830: my ($r,$codedom,$js,$add_entries,$catlinks,$numtitles,$cattype) = @_;
831: my $start_page =
832: &Apache::loncommon::start_page('Course/Community Catalog',$js,
833: { 'add_entries' => $add_entries, });
834: $r->print($start_page);
835: my $brtext = 'Course listing';
836: if ($env{'form.currcat_0'} eq 'communities::0') {
837: $brtext = 'Community listing';
838: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
839: $brtext = 'Placement test listing';
840: }
841: if ($env{'form.state'} eq 'listing') {
842: if ($numtitles > 0) {
843: &Apache::lonhtmlcommon::add_breadcrumb
844: ({href=>"/adm/coursecatalog",
845: text=>"Course/Community Catalog"},
846: {text=>$brtext});
847: } else {
848: &Apache::lonhtmlcommon::add_breadcrumb
849: ({text=>$brtext});
850: }
851: } else {
852: &Apache::lonhtmlcommon::add_breadcrumb
853: ({href=>"/adm/coursecatalog",
854: text=>"Course/Community Catalog"});
855: }
856: $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog'));
857: if ($cattype eq 'std') {
858: my $onchange = 'this.form.submit()';
859: $r->print('<form name="coursecatdom" method="post" action="/adm/coursecatalog">'.
860: '<table border="0"><tr><td><b>'.&mt('Domain:').'</b></td><td>'.
861: &Apache::loncommon::select_dom_form($codedom,'showdom','',1,$onchange));
862: if (!$onchange) {
863: $r->print(' <input type="submit" name="godom" value="'.&mt('Change').'" />');
864: }
865: $r->print('</td></tr></table></form>');
866: }
867: $r->print('<form name="coursecats" method="post" action="/adm/coursecatalog"'.
868: ' onsubmit="return check_selected();">'.
869: '<table border="0"><tr>'.$catlinks.'</tr></table></form>');
870: return;
871: }
872:
873: sub category_breadcrumbs {
874: my ($dom,@cats) = @_;
875: my $crumbsymbol = ' ▶ ';
876: my ($currdepth,$deeper) = &get_depth_values();
877: my $currcat_str =
878: '<input type="hidden" name="catalog_maxdepth" value="'.$deeper.'" />'.
879: '<input type="hidden" name="showdom" value="'.$dom.'" />';
880: my $catlinks = '<td valign="top"><b>'.&mt('Catalog:').'</b></td><td><table><tr><td>';
881: my $has_subcats;
882: my $selitem;
883: if (ref($cats[0]) eq 'ARRAY') {
884: if (@{$cats[0]} == 0) {
885: $catlinks .= &mt('No categories defined in this domain');
886: } elsif (@{$cats[0]} == 1) {
887: if ($cats[0][0] eq 'instcode') {
888: $catlinks .= &mt('Official courses (with institutional codes)');
889: $env{'form.currcat_0'} = 'instcode::0';
890: } elsif ($cats[0][0] eq 'communities') {
891: $catlinks .= &mt('Communities');
892: $env{'form.currcat_0'} = 'communities::0';
893: } elsif ($cats[0][0] eq 'placement') {
894: $catlinks .= &mt('Placement Tests');
895: $env{'form.currcat_0'} = 'placement::0';
896: } else {
897: my $name = $cats[0][0];
898: my $item = &escape($name).'::0';
899: $catlinks .= $name;
900: $env{'form.currcat_0'} = $item;
901: }
902: $currcat_str .= '<input type="hidden" name="currcat_0" value="'.$env{'form.currcat_0'}.'" />';
903: } else {
904: $catlinks .= &main_category_selector(@cats);
905: if (($env{'form.currcat_0'} ne '') &&
906: ($env{'form.currcat_0'} ne 'instcode::0')) {
907: $catlinks .= $crumbsymbol;
908: }
909: }
910: } else {
911: $catlinks .= &mt('Official courses (with institutional codes)');
912: $env{'form.currcat_0'} = 'instcode::0';
913: $currcat_str .= '<input type="hidden" name="currcat_0" value="'.$env{'form.currcat_0'}.'" />';
914: }
915: if ($deeper) {
916: for (my $i=1; $i<=$deeper; $i++) {
917: my $shallower = $i-1;
918: next if ($shallower == 0);
919: my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$env{'form.currcat_'.$shallower});
920: if ($cat ne '') {
921: $catlinks .= '<td valign="top">'.
922: '<select name="currcat_'.$shallower.'" onchange="'.
923: 'setCatDepth('."'$shallower'".');this.form.submit();">';
924: if (ref($cats[$shallower]{$container}) eq 'ARRAY') {
925: $catlinks .= '<option value="">'.&mt('De-select').'</option>';
926: for (my $j=0; $j<@{$cats[$shallower]{$container}}; $j++) {
927: my $name = $cats[$shallower]{$container}[$j];
928: my $item = &escape($name).':'.&escape($container).':'.$shallower;
929: my $selected = '';
930: if ($item eq $env{'form.currcat_'.$shallower}) {
931: $selected = ' selected="selected"';
932: }
933: $catlinks .=
934: '<option value="'.$item.'"'.$selected.'>'.$name.'</option>';
935: }
936: }
937: $catlinks .= '</select>';
938: }
939: unless ($i == $deeper) {
940: $catlinks .= $crumbsymbol;
941: }
942: }
943: my ($cat,$container,$depth);
944: if ($env{'form.currcat_'.$currdepth} eq '') {
945: my $shallower = $currdepth - 1;
946: ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$env{'form.currcat_'.$shallower});
947: } else {
948: ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$env{'form.currcat_'.$currdepth});
949: }
950: my $deeperlevel = $depth +1;
951: if (ref($cats[$deeperlevel]{$cat}) eq 'ARRAY') {
952: $has_subcats = 1;
953: my $buttontext = &mt('Show subcategories');
954: my $selitem = 'currcat_'.$deeperlevel;
955: $catlinks .= ' <select name="'.$selitem.'" onchange="this.form.submit()">';
956: if (@{$cats[$deeperlevel]{$cat}}) {
957: $catlinks .= '<option value="" selected="selected">'.
958: &mt('Subcategory ...').'</option>';
959: }
960: for (my $k=0; $k<@{$cats[$deeperlevel]{$cat}}; $k++) {
961: my $name = $cats[$deeperlevel]{$cat}[$k];
962: my $item = &escape($name).':'.&escape($cat).':'.$deeperlevel;
963: $catlinks .= '<option value="'.$item.'">'.$name.'</option>'."\n";
964: }
965: $catlinks .= '</select>'."\n";
966: } elsif ($cat ne 'instcode') {
967: $catlinks .= ' '.&mt('(No subcategories)');
968: }
969: } else {
970: $selitem = 'currcat_0';
971: }
972: $catlinks .= $currcat_str.'</td></tr></table></td>';
973: return ($catlinks,$has_subcats,$selitem);
974: }
975:
976: sub main_category_selector {
977: my (@cats) = @_;
978: my $maincatlinks = '<select name="currcat_0" onchange="setCatDepth('."'0'".');this.form.submit();">'."\n";
979: if (ref($cats[0]) eq 'ARRAY') {
980: if (@{$cats[0]} > 1) {
981: my $selected = '';
982: if ($env{'form.currcat_0'} eq '') {
983: $selected = ' selected="selected"';
984: }
985: $maincatlinks .=
986: '<option value=""'.$selected.'>'.&mt('Select').'</option>'."\n";
987: }
988: for (my $i=0; $i<@{$cats[0]}; $i++) {
989: my $name = $cats[0][$i];
990: my $item = &escape($name).'::0';
991: my $selected;
992: if ($env{'form.currcat_0'} eq $item) {
993: $selected = ' selected="selected"';
994: }
995: $maincatlinks .= '<option value="'.$item.'"'.$selected.'>';
996: if ($name eq 'instcode') {
997: $maincatlinks .= &mt('Official courses (with institutional codes)');
998: } elsif ($name eq 'communities') {
999: $maincatlinks .= &mt('Communities');
1000: } elsif ($name eq 'placement') {
1001: $maincatlinks .= &mt('Placement Tests');
1002: } else {
1003: $maincatlinks .= $name;
1004: }
1005: $maincatlinks .= '</option>'."\n";
1006: }
1007: $maincatlinks .= '</select>'."\n";
1008: }
1009: return $maincatlinks;
1010: }
1011:
1012: sub get_depth_values {
1013: my $currdepth = 0;
1014: my $deeper = 0;
1015: if ($env{'form.catalog_maxdepth'} ne '') {
1016: $currdepth = $env{'form.catalog_maxdepth'};
1017: if ($env{'form.currcat_'.$currdepth} eq '') {
1018: $deeper = $currdepth;
1019: } else {
1020: $deeper = $currdepth + 1;
1021: }
1022: }
1023: return ($currdepth,$deeper);
1024: }
1025:
1026: sub additional_filters {
1027: my ($codedom,$has_subcats,$canviewall) = @_;
1028: my $is_dc = &user_is_dc($codedom);
1029: my $output = '<div class="LC_left_float">';
1030: if ($is_dc || $canviewall) {
1031: $output .= '<fieldset><legend>'.&mt('Options').'</legend>';
1032: }
1033: $output .= '<table><tr><td valign="top">';
1034: if (($env{'form.currcat_0'} ne 'instcode::0') &&
1035: ($env{'form.currcat_0'} ne '') && ($has_subcats)) {
1036: my $include_subcat_status;
1037: if ($env{'form.withsubcats'}) {
1038: $include_subcat_status = 'checked="checked" ';
1039: }
1040: my $counter = $env{'form.catalog_maxdepth'};
1041: if ($counter > 0) {
1042: if ($env{'form.state'} eq 'listing') {
1043: $counter --;
1044: } elsif ($env{'form.currcat_'.$counter} eq '') {
1045: $counter --;
1046: }
1047: }
1048: my ($catname) = split(/:/,$env{'form.currcat_'.$counter});
1049: if ($catname ne '') {
1050: $output .= '<span class="LC_nobreak"><label>'.
1051: '<input type="checkbox" name="withsubcats" value="1" '.
1052: $include_subcat_status.'/>'.
1053: &mt('Include subcategories within "[_1]"',
1054: &unescape($catname)).'</label></span><br />';
1055: }
1056: }
1057: my $show_selfenroll_status;
1058: if ($env{'form.showselfenroll'}) {
1059: $show_selfenroll_status = 'checked="checked" ';
1060: }
1061: my $selfenroll_text;
1062: if ($env{'form.currcat_0'} eq 'communities::0') {
1063: $selfenroll_text = &mt('Only show communities which currently allow self-enrollment (or will allow it in the future)');
1064: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1065: $selfenroll_text = &mt('Only show placement tests which currently allow self-enrollment (or will allow it in the future)');
1066: } else {
1067: $selfenroll_text = &mt('Only show courses which currently allow self-enrollment (or will allow it in the future)');
1068: }
1069: $output .= '<span class="LC_nobreak">'.
1070: '<label><input type="checkbox" name="showselfenroll" value="1" '.
1071: $show_selfenroll_status.'/>'.$selfenroll_text.
1072: '</label></span><br />';
1073: if ($is_dc || $canviewall) {
1074: my ($titlesref,$orderref) = &get_statustitles('filters');
1075: my $showdetails_status;
1076: if ($env{'form.showdetails'}) {
1077: $showdetails_status = 'checked="checked" ';
1078: }
1079: my $showhidden_status;
1080: if ($env{'form.showhidden'}) {
1081: $showhidden_status = 'checked="checked" ';
1082: }
1083: my @currstatuses = &Apache::loncommon::get_env_multiple('form.showcounts');
1084: my ($details_text,$hidden_text,$statusdisplay,$cellborder);
1085: my $wasactivedisplay = 'none';
1086: if ($env{'form.showdetails'}) {
1087: $statusdisplay = 'block';
1088: $cellborder = 'border-left: 1px solid;';
1089: if (grep(/^Previous$/,@currstatuses)) {
1090: $wasactivedisplay = 'block';
1091: }
1092: } else {
1093: $statusdisplay = 'none';
1094: $cellborder = 'border-left: 0px';
1095: }
1096: if ($env{'form.currcat_0'} eq 'communities::0') {
1097: $details_text = &mt('Show full details for each community (domain staff only)');
1098: $hidden_text = &mt('Include communities set to be hidden from catalog (domain staff only)');
1099: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1100: $details_text = &mt('Show full details for each placement test (domain staff only)');
1101: $hidden_text = &mt('Include placement tests set to be hidden from catalog (domain staff only)');
1102: } else {
1103: $details_text = &mt('Show full details for each course (domain staff only)');
1104: $hidden_text = &mt('Include courses set to be hidden from catalog (domain staff only)');
1105: }
1106: if ($is_dc) {
1107: $output .= '<span class="LC_nobreak">'.
1108: '<label><input type="checkbox" name="showhidden" value="1" '.
1109: $showhidden_status.'/>'.$hidden_text.
1110: '</label></span><br />'."\n";
1111: }
1112: $output .= '<span class="LC_nobreak">'.
1113: '<label><input type="checkbox" name="showdetails" value="1" '.
1114: $showdetails_status.'onclick="toggleStatuses();" />'.
1115: $details_text.'</label></span></td>'."\n".
1116: '<td id="statuscell" valign="top" style="'.$cellborder.'">'.
1117: '<div id="statuschoice" style="display:'.$statusdisplay.'">';
1118: if (ref($orderref) eq 'ARRAY') {
1119: if (@{$orderref} > 0) {
1120: foreach my $type (@{$orderref}) {
1121: my $checked;
1122: if (grep(/^\Q$type\E$/,@currstatuses)) {
1123: $checked = ' checked="checked"';
1124: }
1125: my $title;
1126: if (ref($titlesref) eq 'HASH') {
1127: $title = $titlesref->{$type};
1128: }
1129: unless ($title) {
1130: $title = &mt($type);
1131: }
1132: my $onclick;
1133: if ($type eq 'Previous') {
1134: $onclick = ' onclick="toggleWasActive();"';
1135: }
1136: $output .= '<span class="LC_nobreak">'.
1137: '<label><input type="checkbox" id="counts_'.$type.'"'.
1138: ' name="showcounts" value="'.$type.'"'.$checked.$onclick.
1139: ' />'.$title.'</label></span>';
1140: if ($type eq 'Previous') {
1141: my %milestonetext = &Apache::lonlocal::texthash (
1142: accessend => 'immediately prior to default end access date',
1143: enrollend => 'immediately prior to end date for auto-enrollment',
1144: date => 'immediately prior to specific date:',
1145: );
1146: my @statuses = &Apache::loncommon::get_env_multiple('form.showcounts');
1147: $output .= '<span id="choosewasacctext" class="LC_nobreak">';
1148: if ($checked) {
1149: $output .= &get_wasactive_text();
1150: }
1151: $output .= '</span>'.
1152: '<div id="choosewasactive" style="display:'.$wasactivedisplay.'">'.
1153: '<table>';
1154: my @milestones = ('accessend');
1155: if (&Apache::lonnet::auto_run(undef,$codedom)) {
1156: push(@milestones,'enrollend');
1157: }
1158: push(@milestones,'date');
1159: foreach my $item (@milestones) {
1160: my $checked;
1161: if ($env{'form.state'} eq 'listing') {
1162: if ($env{'form.wasactive'} eq $item) {
1163: $checked = ' checked="checked"';
1164: }
1165: } elsif ($item eq 'accessend') {
1166: $checked = ' checked="checked"';
1167: }
1168: $output .=
1169: '<tr><td width="10"> </td><td>'.
1170: '<span class="LC_nobreak"><label>'.
1171: '<input type="radio" value="'.$item.'" name="wasactive"'.$checked.' />'.
1172: $milestonetext{$item}.'</label></span>';
1173: if ($item eq 'date') {
1174: my $wasactiveon;
1175: if (grep(/^Previous$/,@currstatuses)) {
1176: $wasactiveon =
1177: &Apache::lonhtmlcommon::get_date_from_form('wasactiveon');
1178: } else {
1179: $wasactiveon = 'now';
1180: }
1181: $output .= ' '.
1182: &Apache::lonhtmlcommon::date_setter('coursecatalog',
1183: 'wasactiveon',
1184: $wasactiveon,
1185: '','','',1,'',
1186: '','',1);
1187: }
1188: $output .= '</td></tr>';
1189: }
1190: $output .= '</table></div>';
1191: }
1192: $output .= '<br />';
1193: }
1194: }
1195: }
1196: $output .= '</div></td>';
1197: } else {
1198: $output .= '</td>';
1199: }
1200: $output .= '</tr></table></fieldset></div>'.
1201: '<div style="clear:both;margin:0;"></div>';
1202: return $output;
1203: }
1204:
1205: sub user_is_dc {
1206: my ($codedom) = @_;
1207: if (exists($env{'user.role.dc./'.$codedom.'/'})) {
1208: my $livedc = 1;
1209: my $now = time;
1210: my ($start,$end)=split(/\./,$env{'user.role.dc./'.$codedom.'/'});
1211: if ($start && $start>$now) { $livedc = 0; }
1212: if ($end && $end <$now) { $livedc = 0; }
1213: return $livedc;
1214: }
1215: return;
1216: }
1217:
1218: sub canview_all {
1219: my ($knownuser,$codedom) = @_;
1220: my $canviewall = 0;
1221: my $page = 'coursecatalog';
1222: if (&LONCAPA::lonauthcgi::can_view($page)) {
1223: $canviewall = 1;
1224: } elsif (&LONCAPA::lonauthcgi::check_ipbased_access($page)) {
1225: $canviewall= 1;
1226: } elsif (($knownuser) && ($codedom ne '')) {
1227: if (&Apache::lonnet::allowed('dcd',$codedom)) {
1228: $canviewall = 1;
1229: }
1230: }
1231: return $canviewall;
1232: }
1233:
1234: sub get_statustitles {
1235: my ($caller) = @_;
1236: my @status_order = ('Active','Future','Previous');
1237: my %status_title;
1238: if ($caller eq 'filters') {
1239: %status_title = &Apache::lonlocal::texthash(
1240: Previous => 'Show count for past access',
1241: Active => 'Show count for current student access',
1242: Future => 'Show count for future student access',
1243: );
1244: if ($env{'form.currcat_0'} eq 'communities::0') {
1245: $status_title{'Active'} = 'Show count for current member access';
1246: $status_title{'Future'} = 'Show count for future member access';
1247: }
1248: } else {
1249: %status_title = &Apache::lonlocal::texthash(
1250: Previous => 'Previous access',
1251: Active => 'Current access',
1252: Future => 'Future access',
1253: );
1254: }
1255: return (\%status_title,\@status_order);
1256: }
1257:
1258: sub get_wasactive_text {
1259: my $wasacctext = ' -- ';
1260: if ($env{'form.currcat_0'} eq 'communities::0') {
1261: $wasacctext .= &mt('where member access status was current ...');
1262: } else {
1263: $wasacctext .= &mt('where student access status was current ...');
1264: }
1265: return $wasacctext;
1266: }
1267:
1268: sub search_official_courselist {
1269: my ($domain,$numtitles,$codetitles) = @_;
1270: my $instcode = &Apache::courseclassifier::instcode_search_str($domain,$numtitles,$codetitles);
1271: my $showhidden;
1272: if (&user_is_dc($domain)) {
1273: $showhidden = $env{'form.showhidden'};
1274: }
1275: my %courses =
1276: &Apache::lonnet::courseiddump($domain,'.',1,$instcode,'.','.',undef,undef,
1277: 'Course',1,$env{'form.showselfenroll'},undef,
1278: $showhidden,'coursecatalog');
1279: return %courses;
1280: }
1281:
1282: sub search_courselist {
1283: my ($domain,$subcats) = @_;
1284: my $cat_maxdepth = $env{'form.catalog_maxdepth'};
1285: my $filter = $env{'form.currcat_'.$cat_maxdepth};
1286: if (($filter eq '') && ($cat_maxdepth > 0)) {
1287: my $shallower = $cat_maxdepth - 1;
1288: $filter = $env{'form.currcat_'.$shallower};
1289: }
1290: my %courses;
1291: my $filterstr;
1292: if ($filter ne '') {
1293: if ($env{'form.withsubcats'}) {
1294: if (ref($subcats) eq 'HASH') {
1295: if (ref($subcats->{$filter}) eq 'ARRAY') {
1296: $filterstr = join('&',@{$subcats->{$filter}});
1297: if ($filterstr ne '') {
1298: $filterstr = $filter.'&'.$filterstr;
1299: }
1300: } else {
1301: $filterstr = $filter;
1302: }
1303: } else {
1304: $filterstr = $filter;
1305: }
1306: } else {
1307: $filterstr = $filter;
1308: }
1309: my ($showhidden,$typefilter);
1310: if (&user_is_dc($domain)) {
1311: $showhidden = $env{'form.showhidden'};
1312: }
1313: if ($env{'form.currcat_0'} eq 'communities::0') {
1314: $typefilter = 'Community';
1315: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1316: $typefilter = 'Placement';
1317: } else {
1318: $typefilter = '.';
1319: }
1320: %courses =
1321: &Apache::lonnet::courseiddump($domain,'.',1,'.','.','.',undef,undef,
1322: $typefilter,1,$env{'form.showselfenroll'},
1323: $filterstr,$showhidden,'coursecatalog');
1324: }
1325: return %courses;
1326: }
1327:
1328: sub print_course_listing {
1329: my ($domain,$numtitles,$trails,$allitems,$subcats,$codetitles,$canviewall,$hostname) = @_;
1330: my $output;
1331: my %courses;
1332: my $knownuser = &user_is_known();
1333: my $canviewall = &canview_all();
1334: my $details = $env{'form.coursenum'};
1335: if (&user_is_dc($domain) || $canviewall) {
1336: if ($env{'form.showdetails'}) {
1337: $details = 1;
1338: }
1339: }
1340: if ($env{'form.coursenum'} ne '') {
1341: %courses = &Apache::lonnet::courseiddump($domain,'.',1,'.','.',
1342: $env{'form.coursenum'},
1343: undef,undef,'.',1);
1344: if (keys(%courses) == 0) {
1345: $output = '<p class="LC_error">';
1346: if ($env{'form.currcat_0'} eq 'communities::0') {
1347: $output .= &mt('The courseID provided does not match a community in this domain.');
1348: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1349: $output .= &mt('The courseID provided does not match a placement test in this domain.');
1350: } else {
1351: $output .= &mt('The courseID provided does not match a course in this domain.');
1352: }
1353: $output .= '</p>';
1354: return $output;
1355: }
1356: } else {
1357: if ($env{'form.currcat_0'} eq 'instcode::0') {
1358: %courses = &search_official_courselist($domain,$numtitles,$codetitles);
1359: } else {
1360: %courses = &search_courselist($domain,$subcats);
1361: }
1362: if (keys(%courses) == 0) {
1363: $output = '<p class="LC_info">';
1364: if ($env{'form.currcat_0'} eq 'communities::0') {
1365: $output .= &mt('No communities match the criteria you selected.');
1366: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1367: $output .= &mt('No placement tests match the criteria you selected.');
1368: } else {
1369: $output .= &mt('No courses match the criteria you selected.');
1370: }
1371: $output .= '</p>';
1372: return $output;
1373: }
1374: if (($knownuser) && (!$env{'form.showdetails'}) && (!&user_is_dc($domain)) && (!$canviewall)) {
1375: $output = '<b>'.&mt('Note for students:').'</b> '
1376: .&mt('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.')
1377: .'<br /><br />';
1378: }
1379: }
1380: my $now = time;
1381: $output .= &construct_data_table($knownuser,$domain,\%courses,$details,undef,
1382: $now,$trails,$allitems,$canviewall,$hostname);
1383: $output .= "\n".'<form name="linklaunch" method="post" action="">'.
1384: '<input type="hidden" name="backto" value="coursecatalog" />'.
1385: '<input type="hidden" name="courseid" value="" />'.
1386: &Apache::lonhtmlcommon::echo_form_input(['catalogfilter','courseid']).'</form>';
1387: return $output;
1388: }
1389:
1390: sub construct_data_table {
1391: my ($knownuser,$domain,$courses,$details,$usersections,$now,
1392: $trails,$allitems,$canviewall,$hostname) = @_;
1393: my %sortname;
1394: if (($details eq '') || ($env{'form.showdetails'})) {
1395: $sortname{'Code'} = 'code';
1396: $sortname{'Categories'} = 'cats';
1397: $sortname{'Title'} = 'title';
1398: $sortname{'Owner & Co-owner(s)'} = 'owner';
1399: }
1400: my $output = &Apache::loncommon::start_data_table().
1401: &Apache::loncommon::start_data_table_header_row();
1402: my @coltitles = ('Count');
1403: if ($env{'form.currcat_0'} eq 'instcode::0') {
1404: push(@coltitles,'Code');
1405: } else {
1406: push(@coltitles,'Categories');
1407: }
1408: push(@coltitles,('Sections','Crosslisted','Title','Owner & Co-owner(s)'));
1409: if (ref($usersections) eq 'HASH') {
1410: $coltitles[1] = 'Your Section';
1411: }
1412: foreach my $item (@coltitles) {
1413: $output .= '<th>';
1414: if (defined($sortname{$item})) {
1415: $output .= '<a href="javascript:changeSort('."'$sortname{$item}'".')">'.&mt($item).'</a>';
1416: } elsif ($item eq 'Count') {
1417: $output .= ' ';
1418: } else {
1419: $output .= &mt($item);
1420: }
1421: $output .= '</th>';
1422: }
1423: my (@fields,%fieldtitles,$wasactiveon);
1424: if ($knownuser || ($canviewall && $details)) {
1425: if ($details) {
1426: if ($env{'form.currcat_0'} eq 'communities::0') {
1427: $output .= '<th>'.&mt('Default Access Dates for Members').'</th>'.
1428: '<th>'.&mt('Member Counts').'</th>';
1429: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1430: $output .=
1431: '<th>'.&mt('Default Access Dates for Students').'</th>'.
1432: '<th>'.&mt('Student Counts').'</th>';
1433: } else {
1434: $output .=
1435: '<th>'.&mt('Default Access Dates for Students').'</th>'.
1436: '<th>'.&mt('Student Counts').'</th>'.
1437: '<th>'.&mt('Auto-enrollment of[_1]registered students','<br />').'</th>';
1438: }
1439: my ($titlesref,$orderref) = &get_statustitles();
1440: my @statuses;
1441: if (&user_is_dc($domain) || $canviewall) {
1442: @statuses = &Apache::loncommon::get_env_multiple('form.showcounts');
1443: if (grep(/^Previous$/,@statuses)) {
1444: if ($env{'form.wasactive'} eq 'date') {
1445: $wasactiveon =
1446: &Apache::lonhtmlcommon::get_date_from_form('wasactiveon');
1447: } else {
1448: $wasactiveon = $env{'form.wasactive'};
1449: }
1450: }
1451: if (ref($orderref) eq 'ARRAY') {
1452: foreach my $status (@{$orderref}) {
1453: if (grep(/^\Q$status\E$/,@statuses)) {
1454: push(@fields,$status);
1455: }
1456: }
1457: }
1458: } else {
1459: @fields = ('Active','Future');
1460: }
1461: foreach my $status (@fields) {
1462: my $title;
1463: if (ref($titlesref) eq 'HASH') {
1464: $title = $titlesref->{$status};
1465: }
1466: unless ($title) {
1467: $title = &mt($status);
1468: }
1469: $fieldtitles{$status} = $title;
1470: }
1471: } else {
1472: $output .= '<th>'.&mt('Details').'</th>';
1473: }
1474: }
1475: $output .= '<th>'.&mt('Self-enroll (if permitted)').'</th>';
1476: &Apache::loncommon::end_data_table_header_row();
1477: my (%numbers,%creditsum);
1478: my ($showcredits,$defofficial,$defunofficial,$deftextbook);
1479: my %domdefaults = &Apache::lonnet::get_domain_defaults($domain);
1480: unless (($env{'form.currcat_0'} eq 'communities::0') || ($env{'form.currcat_0'} eq 'placement::0')) {
1481: if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) {
1482: $showcredits = 1;
1483: $defofficial = $domdefaults{'officialcredits'};
1484: $defunofficial = $domdefaults{'unofficialcredits'};
1485: $deftextbook = $domdefaults{'textbookcredits'};
1486: }
1487: }
1488: my %courseinfo = &build_courseinfo_hash($courses,$knownuser,$domain,$canviewall,$details,
1489: $usersections,\@fields,\%fieldtitles,
1490: $wasactiveon,\%numbers,\%creditsum,
1491: $showcredits,$defofficial,$defunofficial,$deftextbook);
1492: my %Sortby;
1493: foreach my $course (sort(keys(%{$courses}))) {
1494: if ($env{'form.sortby'} eq 'code') {
1495: push(@{$Sortby{$courseinfo{$course}{'code'}}},$course);
1496: } elsif ($env{'form.sortby'} eq 'cats') {
1497: push(@{$Sortby{$courseinfo{$course}{'categories'}}},$course);
1498: } elsif ($env{'form.sortby'} eq 'owner') {
1499: push(@{$Sortby{$courseinfo{$course}{'ownerlastnames'}}},$course);
1500: } else {
1501: my $clean_title = $courseinfo{$course}{'title'};
1502: $clean_title =~ s/\W+//g;
1503: if ($clean_title eq '') {
1504: $clean_title = $courseinfo{$course}{'title'};
1505: }
1506: push(@{$Sortby{$clean_title}},$course);
1507: }
1508: }
1509: my @sorted_courses;
1510: if (($env{'form.sortby'} eq 'code') || ($env{'form.sortby'} eq 'owner') ||
1511: ($env{'form.sortby'} eq 'cats')) {
1512: @sorted_courses = sort(keys(%Sortby));
1513: } else {
1514: @sorted_courses = sort { lc($a) cmp lc($b) } (keys(%Sortby));
1515: }
1516: my $count = 1;
1517: my $totalsec = 0;
1518: my %clutteredxlists;
1519: foreach my $course (keys(%courseinfo)) {
1520: if (ref($courseinfo{$course}) eq 'HASH') {
1521: if ($courseinfo{$course}{'xlist'} ne '') {
1522: my $crskey = $courseinfo{$course}{'cnum'}.':'.$courseinfo{$course}{'code'};
1523: my @xlists = split(/,\s/,$courseinfo{$course}{'xlist'});
1524: $clutteredxlists{$crskey} = \@xlists;
1525: }
1526: }
1527: }
1528: if (keys(%clutteredxlists)) {
1529: my %reformattedxlists = &Apache::lonnet::auto_instsec_reformat($domain,'declutter',\%clutteredxlists);
1530: foreach my $crskey (keys(%reformattedxlists)) {
1531: if (ref($reformattedxlists{$crskey}) eq 'ARRAY') {
1532: my $course = $domain.'_'.(split(/:/,$crskey))[0];
1533: $courseinfo{$course}{'xlist'} = join(', ',@{$reformattedxlists{$crskey}});
1534: }
1535: }
1536: }
1537: foreach my $item (@sorted_courses) {
1538: foreach my $course (@{$Sortby{$item}}) {
1539: $output.=&Apache::loncommon::start_data_table_row();
1540: $output.=&courseinfo_row($courseinfo{$course},$knownuser,$details,
1541: \$count,$now,$course,$trails,$allitems,
1542: \%numbers,$canviewall,$hostname);
1543: $output.=&Apache::loncommon::end_data_table_row();
1544: }
1545: }
1546: if (($knownuser || $canviewall) && ($count > 1) && $env{'form.showdetails'}) {
1547: if (&user_is_dc($domain) || $canviewall) {
1548: my %lt = &Apache::lonlocal::texthash (
1549: 'Active' => 'Total current students',
1550: 'Future' => 'Total future students',
1551: 'Previous' => 'Total previous students',
1552: 'courses' => 'Total unique codes and courses without codes',
1553: 'sections' => 'Total sections',
1554: 'xlists' => 'Total cross-listings',
1555: );
1556: if ($showcredits) {
1557: $lt{'cr_Active'} = &mt('Total current student credit hours');
1558: $lt{'cr_Future'} = &mt('Total future student credit hours');
1559: $lt{'cr_Previous'} = &mt('Total previous student credit hours');
1560: }
1561: if ($env{'form.currcat_0'} eq 'communities::0') {
1562: $lt{'courses'} = &mt('Total communities');
1563: $lt{'Active'} = &mt('Total current members');
1564: $lt{'Future'} = &mt('Total future members');
1565: $lt{'Previous'} = &mt('Total previous members');
1566: } elsif ($env{'form.currcat_0'} eq 'placement::0') {
1567: $lt{'courses'} = &mt('Total placement tests');
1568: }
1569: my $colspan = 8;
1570: if ($showcredits) {
1571: $colspan = 4;
1572: }
1573: $output .= '<tr class="LC_footer_row">'.
1574: '<td colspan="2"> </td>'.
1575: '<td colspan="'.$colspan.'">'.
1576: '<table border="0">';
1577: foreach my $item ('courses','sections','xlists') {
1578: $output .= '<tr>'.
1579: '<td>'.$lt{$item}.'</td><td> </td>'.
1580: '<td align="right">'.$numbers{$item}.'</td>'.
1581: '</tr>'."\n";
1582: }
1583: if (@fields > 0) {
1584: foreach my $status (@fields) {
1585: $output .= '<tr>'.
1586: '<td>'.$lt{$status}.'</td><td> </td>'.
1587: '<td align="right">'.$numbers{$status}.'</td>'.
1588: '</tr>'."\n";
1589: }
1590: }
1591: $output .= '</table></td>';
1592: if ($showcredits) {
1593: $output .= '<td colspan="'.$colspan.'" valign="bottom"><table>';
1594: foreach my $status (@fields) {
1595: $output .= '<tr>'.
1596: '<td>'.$lt{'cr_'.$status}.'</td><td> </td>'.
1597: '<td align="right">'.$creditsum{$status}.'</td></tr>';
1598: }
1599: $output .= '</table></td></tr>';
1600: }
1601: }
1602: }
1603: $output .= &Apache::loncommon::end_data_table();
1604: return $output;
1605: }
1606:
1607: sub build_courseinfo_hash {
1608: my ($courses,$knownuser,$domain,$canviewall,$details,$usersections,$fields,$fieldtitles,
1609: $wasactiveon,$numbers,$creditsum,$showcredits,$defofficial,$defunofficial) = @_;
1610: my %courseinfo;
1611: my $now = time;
1612: my $gettotals;
1613: if ((keys(%{$courses}) > 0) && (&user_is_dc($domain) || $canviewall) && ($details)) {
1614: $gettotals = 1;
1615: }
1616: my (%uniquecodes,$nocodes,$defcreds);
1617: foreach my $course (keys(%{$courses})) {
1618: my $descr;
1619: if (ref($courses->{$course}) eq 'HASH') {
1620: $descr = $courses->{$course}{'description'};
1621: }
1622: my $cleandesc=&HTML::Entities::encode($descr,'<>&"');
1623: $cleandesc=~s/'/\\'/g;
1624: $cleandesc =~ s/^\s+//;
1625: my ($cdom,$cnum)=split(/\_/,$course);
1626: my ($instcode,$singleowner,$ttype,$selfenroll_types,$extsyllplain,
1627: $selfenroll_start,$selfenroll_end,@owners,%ownernames,$categories);
1628: if (ref($courses->{$course}) eq 'HASH') {
1629: $descr = $courses->{$course}{'description'};
1630: $instcode = $courses->{$course}{'inst_code'};
1631: $singleowner = $courses->{$course}{'owner'};
1632: $ttype = $courses->{$course}{'type'};
1633: $selfenroll_types = $courses->{$course}{'selfenroll_types'};
1634: $selfenroll_start = $courses->{$course}{'selfenroll_start_date'};
1635: $selfenroll_end = $courses->{$course}{'selfenroll_end_date'};
1636: $categories = $courses->{$course}{'categories'};
1637: $extsyllplain = $courses->{$course}{'extsyllplain'};
1638: push(@owners,$singleowner);
1639: if ($courses->{$course}{'co-owners'} ne '') {
1640: foreach my $item (split(/,/,$courses->{$course}{'co-owners'})) {
1641: push(@owners,$item);
1642: }
1643: }
1644: }
1645: if ($instcode ne '') {
1646: $uniquecodes{$instcode} = 1;
1647: } else {
1648: $nocodes ++;
1649: }
1650: foreach my $owner (@owners) {
1651: my ($ownername,$ownerdom);
1652: if ($owner =~ /:/) {
1653: ($ownername,$ownerdom) = split(/:/,$owner);
1654: } else {
1655: $ownername = $owner;
1656: if ($owner ne '') {
1657: $ownerdom = $cdom;
1658: }
1659: }
1660: if ($ownername ne '' && $ownerdom ne '') {
1661: my %namehash=&Apache::loncommon::getnames($ownername,$ownerdom);
1662: $ownernames{$ownername.':'.$ownerdom} = \%namehash;
1663: }
1664: }
1665: $courseinfo{$course}{'cdom'} = $cdom;
1666: $courseinfo{$course}{'cnum'} = $cnum;
1667: $courseinfo{$course}{'code'} = $instcode;
1668: my @lastnames;
1669: foreach my $owner (keys(%ownernames)) {
1670: if (ref($ownernames{$owner}) eq 'HASH') {
1671: push(@lastnames,$ownernames{$owner}{'lastname'});
1672: }
1673: }
1674: $courseinfo{$course}{'ownerlastnames'} = join(', ',sort(@lastnames));
1675: $courseinfo{$course}{'title'} = $cleandesc;
1676: $courseinfo{$course}{'owner'} = $singleowner;
1677: $courseinfo{$course}{'selfenroll_types'} = $selfenroll_types;
1678: $courseinfo{$course}{'selfenroll_start'} = $selfenroll_start;
1679: $courseinfo{$course}{'selfenroll_end'} = $selfenroll_end;
1680: $courseinfo{$course}{'categories'} = $categories;
1681: $courseinfo{$course}{'extsyllplain'} = $extsyllplain;
1682:
1683: my %coursehash = &Apache::lonnet::dump('environment',$cdom,$cnum);
1684: my @classids;
1685: my @crosslistings;
1686: my ($seclist,$numsec) =
1687: &identify_sections($coursehash{'internal.sectionnums'});
1688: $courseinfo{$course}{'seclist'} = $seclist;
1689: my ($xlist_items,$numxlist) =
1690: &identify_sections($coursehash{'internal.crosslistings'});
1691: if (ref($numbers) eq 'HASH') {
1692: $numbers->{'sections'} += $numsec;
1693: $numbers->{'xlists'} += $numxlist;
1694: }
1695: my $showsyllabus = 1; # default is to include a syllabus link
1696: if (defined($coursehash{'showsyllabus'})) {
1697: $showsyllabus = $coursehash{'showsyllabus'};
1698: }
1699: $courseinfo{$course}{'showsyllabus'} = $showsyllabus;
1700: if ($showcredits) {
1701: if ($coursehash{'internal.defaultcredits'}) {
1702: $courseinfo{$course}{'defaultcredits'} = $coursehash{'internal.defaultcredits'};
1703: } elsif ($instcode ne '') {
1704: $courseinfo{$course}{'defaultcredits'} = $defofficial;
1705: } else {
1706: $courseinfo{$course}{'defaultcredits'} = $defunofficial;
1707: }
1708: $defcreds = $courseinfo{$course}{'defaultcredits'};
1709: }
1710: if (((defined($env{'form.coursenum'}) && ($cnum eq $env{'form.coursenum'}))) ||
1711: (($knownuser || $canviewall) && ($details == 1))) {
1712: my $milestone;
1713: if ($wasactiveon eq 'accessend') {
1714: if ($coursehash{'default_enrollment_end_date'}) {
1715: $milestone = $coursehash{'default_enrollment_end_date'};
1716: } else {
1717: $milestone = time;
1718: }
1719: } elsif ($wasactiveon eq 'enrollend') {
1720: if ($coursehash{'internal.autoend'}) {
1721: $milestone = $coursehash{'internal.autoend'};
1722: } else {
1723: $milestone = time;
1724: }
1725: } else {
1726: $milestone = $wasactiveon;
1727: }
1728: $courseinfo{$course}{'counts'} =
1729: &count_students($cdom,$cnum,$numsec,$fields,$fieldtitles,$gettotals,
1730: $numbers,$creditsum,$showcredits,$defcreds,$milestone);
1731: if ($instcode ne '') {
1732: $courseinfo{$course}{'autoenrollment'} =
1733: &autoenroll_info(\%coursehash,$now,$seclist,$xlist_items,
1734: $instcode,\@owners,$cdom,$cnum);
1735: }
1736: my $startaccess = '';
1737: my $endaccess = '';
1738: my $accessdates;
1739: if ( defined($coursehash{'default_enrollment_start_date'}) ) {
1740: $startaccess = &Apache::lonlocal::locallocaltime($coursehash{'default_enrollment_start_date'});
1741: }
1742: if ( defined($coursehash{'default_enrollment_end_date'}) ) {
1743: $endaccess = &Apache::lonlocal::locallocaltime($coursehash{'default_enrollment_end_date'});
1744: if ($coursehash{'default_enrollment_end_date'} == 0) {
1745: $endaccess = &mt('No ending date');
1746: }
1747: }
1748: if ($startaccess) {
1749: $accessdates .= '<i>'.&mt('From:[_1]','</i> '.$startaccess).'<br />';
1750: }
1751: if ($endaccess) {
1752: $accessdates .= '<i>'.&mt('To:[_1]','</i> '.$endaccess).'<br />';
1753: }
1754: if (($selfenroll_types ne '') &&
1755: ($selfenroll_end > 0 && $selfenroll_end > $now)) {
1756: my ($selfenroll_start_access,$selfenroll_end_access);
1757: if (($coursehash{'default_enrollment_start_date'} ne
1758: $coursehash{'internal.selfenroll_start_access'}) ||
1759: ($coursehash{'default_enrollment_end_date'} ne
1760: $coursehash{'internal.selfenroll_end_access'})) {
1761: if ( defined($coursehash{'internal.selfenroll_start_access'}) ) {
1762: $selfenroll_start_access = &Apache::lonlocal::locallocaltime($coursehash{'internal.selfenroll_start_access'});
1763: }
1764: if ( defined($coursehash{'default_enrollment_end_date'}) ) {
1765: $selfenroll_end_access = &Apache::lonlocal::locallocaltime($coursehash{'internal.selfenroll_end_access'});
1766: if ($coursehash{'internal.selfenroll_end_access'} == 0) {
1767: $selfenroll_end_access = &mt('No ending date');
1768: }
1769: }
1770: if ($selfenroll_start_access || $selfenroll_end_access) {
1771: $accessdates .= '<br/><br /><i>'.&mt('Self-enrollers:').'</i><br />';
1772: if ($selfenroll_start_access) {
1773: $accessdates .= '<i>'.&mt('From:[_1]','</i> '.$selfenroll_start_access).'<br />';
1774: }
1775: if ($selfenroll_end_access) {
1776: $accessdates .= '<i>'.&mt('To:[_1]','</i> '.$selfenroll_end_access).'<br />';
1777: }
1778: }
1779: }
1780: }
1781: $courseinfo{$course}{'access'} = $accessdates;
1782: }
1783: if ($xlist_items eq '') {
1784: $xlist_items = &mt('No');
1785: }
1786: $courseinfo{$course}{'xlist'} = $xlist_items;
1787: }
1788: if (ref($numbers) eq 'HASH') {
1789: $numbers->{'courses'} = $nocodes + scalar(keys(%uniquecodes));
1790: }
1791: return %courseinfo;
1792: }
1793:
1794: sub count_students {
1795: my ($cdom,$cnum,$numsec,$fieldsref,$titlesref,$getcounts,$numbers,$creditsum,
1796: $showcredits,$defcreds,$wasactiveon) = @_;
1797: my $countslist = '<span class="LC_nobreak">'.
1798: &mt('[quant,_1,section,sections,No sections]',$numsec).'</span>';
1799: my (@fields,%titles,$showexpired);
1800: if ((ref($fieldsref) eq 'ARRAY') && (ref($titlesref) eq 'HASH') &&
1801: (ref($numbers) eq 'HASH')) {
1802: @fields = @{$fieldsref};
1803: %titles = %{$titlesref};
1804: if (grep(/^Previous$/,@fields)) {
1805: $showexpired = 1;
1806: }
1807: } else {
1808: return;
1809: }
1810: my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cnum);
1811: my (%student_count,%credit_count);
1812: %student_count = (
1813: Active => 0,
1814: Future => 0,
1815: Previous => 0,
1816: );
1817: if ($showcredits) {
1818: %credit_count = (
1819: Active => 0,
1820: Future => 0,
1821: Previous => 0,
1822: );
1823: }
1824: my %idx;
1825: $idx{'status'} = &Apache::loncoursedata::CL_STATUS();
1826: $idx{'end'} = &Apache::loncoursedata::CL_END();
1827: $idx{'credits'} = &Apache::loncoursedata::CL_CREDITS();
1828: while (my ($student,$data) = each(%$classlist)) {
1829: my $status = $data->[$idx{'status'}];
1830: my $credits = $data->[$idx{'credits'}];
1831: if ($credits eq '') {
1832: $credits = $defcreds;
1833: }
1834: if ($status eq 'Expired') {
1835: if (($showexpired) &&
1836: ($data->[$idx{'end'}] >= $wasactiveon)) {
1837: $student_count{'Previous'} ++;
1838: if ($showcredits) {
1839: $credit_count{'Previous'} += $credits;
1840: }
1841: }
1842: } else {
1843: $student_count{$status} ++;
1844: if ($showcredits) {
1845: $credit_count{$status} += $credits;
1846: }
1847: }
1848: }
1849: if (@fields) {
1850: $countslist .= ':<br />';
1851: foreach my $status (@fields) {
1852: $countslist .= '<span class="LC_nobreak">'.$titles{$status}.': '.
1853: $student_count{$status}.'</span><br />';
1854: $numbers->{$status} += $student_count{$status};
1855: if ($showcredits) {
1856: $creditsum->{$status} += $credit_count{$status};
1857: }
1858: }
1859: }
1860: return $countslist;
1861: }
1862:
1863: sub courseinfo_row {
1864: my ($info,$knownuser,$details,$countref,$now,$course,$trails,$allitems,
1865: $numbers,$canviewall,$hostname) = @_;
1866: my ($cdom,$cnum,$title,$ownerlast,$code,$owner,$seclist,$xlist_items,
1867: $accessdates,$showsyllabus,$counts,$autoenrollment,$output,$categories,
1868: $extsyllplain);
1869: if (ref($info) eq 'HASH') {
1870: $cdom = $info->{'cdom'};
1871: $cnum = $info->{'cnum'};
1872: $title = $info->{'title'};
1873: $ownerlast = $info->{'ownerlastnames'};
1874: $code = $info->{'code'};
1875: $owner = $info->{'owner'};
1876: $seclist = $info->{'seclist'};
1877: $xlist_items = $info->{'xlist'};
1878: $accessdates = $info->{'access'};
1879: $counts = $info->{'counts'};
1880: $autoenrollment = $info->{'autoenrollment'};
1881: $showsyllabus = $info->{'showsyllabus'};
1882: $extsyllplain = $info->{'extsyllplain'};
1883: $categories = $info->{'categories'};
1884: } else {
1885: $output = '<td colspan="8">'.&mt('No information available for [_1].',
1886: $code).'</td>';
1887: return $output;
1888: }
1889: $output .= '<td>'.$$countref.'</td>';
1890: if ($env{'form.currcat_0'} eq 'instcode::0') {
1891: $output .= '<td>'.$code.'</td>';
1892: } else {
1893: my ($categorylist,@cats);
1894: if ($categories ne '') {
1895: @cats = split('&',$categories);
1896: }
1897: if ((ref($trails) eq 'ARRAY') && (ref($allitems) eq 'HASH')) {
1898: my @categories = map { $trails->[$allitems->{$_}]; } @cats;
1899: $categorylist = join('<br />',@categories);
1900: }
1901: if ($categorylist eq '') {
1902: $categorylist = ' ';
1903: }
1904: $output .= '<td>'.$categorylist.'</td>';
1905: }
1906: $output .= '<td>'.$seclist.'</td>'.
1907: '<td>'.$xlist_items.'</td>'.
1908: '<td>'.$title.' <font size="-2">';
1909: if ($showsyllabus) {
1910: my $usehttp = 0;
1911: if (($ENV{'SERVER_PORT'} == 443) && ($extsyllplain)) {
1912: unless ((&Apache::lonnet::uses_sts()) ||
1913: (&Apache::lonnet::waf_allssl($hostname))) {
1914: $usehttp = 1;
1915: }
1916: }
1917: $output .= '<a href="javascript:ToSyllabus('."'$cdom','$cnum','$usehttp'".')">'.&mt('Syllabus').'</a>';
1918: } else {
1919: $output .= ' ';
1920: }
1921: $output .= '</font></td>'.
1922: '<td>'.$ownerlast.'</td>';
1923: if (($knownuser) || ($canviewall && $details)) {
1924: if ($details) {
1925: $output .=
1926: '<td>'.$accessdates.'</td>'.
1927: '<td>'.$counts.'</td>';
1928: unless (($env{'form.currcat_0'} eq 'communities::0') || ($env{'form.currcat_0'} eq 'placement::0')) {
1929: $output .= '<td>'.$autoenrollment.'</td>';
1930: }
1931: } else {
1932: $output .= "<td><a href=\"javascript:setCourseId('$cnum')\">".&mt('Show more details').'</a></td>';
1933: }
1934: }
1935: my $selfenroll = &selfenroll_status($info,$course);
1936: if ($selfenroll) {
1937: $output .= '<td>'.$selfenroll.'</td>';
1938: } else {
1939: $output .= '<td> </td>';
1940: }
1941: $$countref ++;
1942: return $output;
1943: }
1944:
1945: sub selfenroll_status {
1946: my ($info,$course) = @_;
1947: my $now = time;
1948: my $output;
1949: if (ref($info) eq 'HASH') {
1950: if ($info->{'selfenroll_types'}) {
1951: my $showstart = &Apache::lonlocal::locallocaltime($info->{'selfenroll_start'});
1952: my $showend = &Apache::lonlocal::locallocaltime($info->{'selfenroll_end'});
1953: if (($info->{'selfenroll_end'} > 0) && ($info->{'selfenroll_end'} > $now)) {
1954: if (($info->{'selfenroll_start'} > 0) && ($info->{'selfenroll_start'} > $now)) {
1955: $output = &mt('Starts: [_1]','<span class="LC_cusr_emph">'.$showstart.'</span>').'<br />'.&mt('Ends: [_1]','<span class="LC_cusr_emph">'.$showend.'</span>');
1956: } else {
1957: $output = '<a href="javascript:ToSelfenroll('."'$course'".')">'.
1958: &mt('Enroll in course').'</a><br />';
1959: if ($info->{'selfenroll_end'} == 0) {
1960: $output .= &mt('Available permanently');
1961: } elsif ($info->{'selfenroll_end'} > $now) {
1962: $output .= &mt('Self-enrollment ends: [_1]','<span class="LC_cusr_emph">'.$showend.'</span>');
1963: }
1964: }
1965: }
1966: }
1967: }
1968: return $output;
1969: }
1970:
1971: sub identify_sections {
1972: my ($seclist) = @_;
1973: my @secnums;
1974: if ($seclist =~ /,/) {
1975: my @sections = split(/,/,$seclist);
1976: foreach my $sec (@sections) {
1977: $sec =~ s/:[^:]*$//;
1978: push(@secnums,$sec);
1979: }
1980: } else {
1981: if ($seclist =~ m/^([^:]+):/) {
1982: my $sec = $1;
1983: if (!grep(/^\Q$sec\E$/,@secnums)) {
1984: push(@secnums,$sec);
1985: }
1986: }
1987: }
1988: @secnums = sort {$a <=> $b} @secnums;
1989: $seclist = join(', ',@secnums);
1990: my $numsec = @secnums;
1991: return ($seclist,$numsec);
1992: }
1993:
1994: sub get_valid_classes {
1995: my ($seclist,$xlist_items,$crscode,$owners,$cdom,$cnum) = @_;
1996: my $response;
1997: my (@sections,@format_sections,@xlists,%possclasses,%okclasses,%validations);
1998: @{$validations{'sections'}} = ();
1999: @{$validations{'xlists'}} = ();
2000: my $totalitems = 0;
2001: if ($seclist) {
2002: @sections = split(/,\s+/,$seclist);
2003: my $crskey = $cnum.':'.$crscode;
2004: my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',
2005: {$crskey => \@sections});
2006: if (ref($formattedsec{$crskey}) eq 'ARRAY') {
2007: @format_sections = @{$formattedsec{$crskey}};
2008: map { $possclasses{$crscode.$_} = 1; } @format_sections;
2009: }
2010: }
2011: if ($xlist_items) {
2012: @xlists = split(/,\s+/,$xlist_items);
2013: map { $possclasses{$_} = 1; } @xlists;
2014: }
2015: my %okclasses = &Apache::lonnet::auto_validate_instclasses($cdom,$cnum,$owners,
2016: \%possclasses);
2017: if (keys(%okclasses)) {
2018: for (my $i=0; $i<@sections; $i++) {
2019: if ($okclasses{$crscode.$format_sections[$i]}) {
2020: my $sec = $sections[$i];
2021: if (!grep(/^\Q$sec\E$/,@{$validations{'sections'}})) {
2022: push(@{$validations{'sections'}},$sec);
2023: $totalitems ++;
2024: }
2025: }
2026: }
2027: foreach my $item (@xlists) {
2028: if ($okclasses{$item}) {
2029: if (!grep(/^\Q$item\E$/,@{$validations{'xlists'}})) {
2030: push(@{$validations{'xlists'}},$item);
2031: $totalitems ++;
2032: }
2033: }
2034: }
2035: }
2036: if ($totalitems > 0) {
2037: if (@{$validations{'sections'}}) {
2038: $response = &mt('Sections:').' '.
2039: join(', ',@{$validations{'sections'}}).'<br />';
2040: }
2041: if (@{$validations{'xlists'}}) {
2042: my $crskey = $cnum.':'.$crscode;
2043: my %reformattedxlists =
2044: &Apache::lonnet::auto_instsec_reformat($cdom,'declutter',
2045: {$crskey => $validations{'xlists'}});
2046: if (ref($reformattedxlists{$crskey}) eq 'ARRAY') {
2047: $validations{'xlists'} = $reformattedxlists{$crskey};
2048: }
2049: $response .= &mt('Courses:').' '.
2050: join(', ',@{$validations{'xlists'}});
2051: }
2052: }
2053: return $response;
2054: }
2055:
2056: sub autoenroll_info {
2057: my ($coursehash,$now,$seclist,$xlist_items,$code,$owners,$cdom,$cnum) = @_;
2058: my $autoenrolldates = &mt('Not enabled');
2059: if (defined($coursehash->{'internal.autoadds'}) && $coursehash->{'internal.autoadds'} == 1) {
2060: my ($autostart,$autoend);
2061: if ( defined($coursehash->{'internal.autostart'}) ) {
2062: $autostart = &Apache::lonlocal::locallocaltime($coursehash->{'internal.autostart'});
2063: }
2064: if ( defined($coursehash->{'internal.autoend'}) ) {
2065: $autoend = &Apache::lonlocal::locallocaltime($coursehash->{'internal.autoend'});
2066: }
2067: if ($coursehash->{'internal.autostart'} > $now) {
2068: if ($coursehash->{'internal.autoend'} && $coursehash->{'internal.autoend'} < $now) {
2069: $autoenrolldates = &mt('Not enabled');
2070: } else {
2071: my $valid_classes =
2072: &get_valid_classes($seclist,$xlist_items,$code,
2073: $owners,$cdom,$cnum);
2074: if ($valid_classes ne '') {
2075: $autoenrolldates = &mt('Not enabled').'<br />'
2076: .&mt('Starts: [_1]',$autostart)
2077: .'<br />'.$valid_classes;
2078: }
2079: }
2080: } else {
2081: if ($coursehash->{'internal.autoend'} && $coursehash->{'internal.autoend'} < $now) {
2082: $autoenrolldates = &mt('Not enabled').'<br />'
2083: .&mt('Ended: [_1]',$autoend);
2084: } else {
2085: my $valid_classes = &get_valid_classes($seclist,$xlist_items,
2086: $code,$owners,$cdom,$cnum);
2087: if ($valid_classes ne '') {
2088: $autoenrolldates = &mt('Currently enabled').'<br />'.
2089: $valid_classes;
2090: }
2091: }
2092: }
2093: }
2094: return $autoenrolldates;
2095: }
2096:
2097: sub user_is_known {
2098: my $known = 0;
2099: if ($env{'user.name'} ne '' && $env{'user.name'} ne 'public'
2100: && $env{'user.domain'} ne '' && $env{'user.domain'} ne 'public') {
2101: $known = 1;
2102: }
2103: return $known;
2104: }
2105:
2106: 1;
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>