--- loncom/interface/coursecatalog.pm 2010/09/07 03:00:38 1.64 +++ loncom/interface/coursecatalog.pm 2017/02/20 18:29:22 1.92 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler for displaying the course catalog interface # -# $Id: coursecatalog.pm,v 1.64 2010/09/07 03:00:38 raeburn Exp $ +# $Id: coursecatalog.pm,v 1.92 2017/02/20 18:29:22 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -38,6 +38,7 @@ use Apache::lonlocal; use Apache::courseclassifier; use Apache::lonacc; use LONCAPA; +use LONCAPA::lonauthcgi; sub handler { my ($r) = @_; @@ -66,8 +67,11 @@ sub handler { } my $formname = 'coursecatalog'; if ($env{'form.showdom'} ne '') { + $env{'form.showdom'} = &LONCAPA::clean_domain($env{'form.showdom'}); if (&Apache::lonnet::domain($env{'form.showdom'}) ne '') { $codedom = $env{'form.showdom'}; + } else { + $env{'form.showdom'} = ''; } } my $domdesc = &Apache::lonnet::domain($codedom,'description'); @@ -75,23 +79,159 @@ sub handler { my %domconfig = &Apache::lonnet::get_dom('configuration',['coursecategories'],$codedom); - my (@cats,@trails,%allitems,%idx,@jsarray,%subcathash,$cathash); + my $knownuser = &user_is_known(); + my $canviewall = &canview_all($knownuser,$codedom); + + my ($cathash,$cattype); if (ref($domconfig{'coursecategories'}) eq 'HASH') { $cathash = $domconfig{'coursecategories'}{'cats'}; + if ($knownuser || $canviewall) { + $cattype = $domconfig{'coursecategories'}{'auth'}; + } else { + $cattype = $domconfig{'coursecategories'}{'unauth'}; + } + if ($cattype eq '') { + $cattype = 'std'; + } } else { $cathash = {}; + $cattype = 'std'; + } + if ($cattype eq 'none') { + $r->print(&Apache::loncommon::start_page('Course/Community Catalog')); + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/coursecatalog", + text=>"Course/Community Catalog"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog')); + if ($knownuser || $canviewall) { + $r->print('
'.&mt('No catalog of LON-CAPA courses/communities is provided for: [_1]',$domdesc).'
'); + } else { + if ($domconfig{'coursecategories'}{'auth'} eq 'none') { + $r->print('
'.&mt('No catalog of LON-CAPA courses/communities is provided for: [_1]',$domdesc).'
'); + } else { + $r->print('
'.&mt('The catalog of LON-CAPA courses/communities provided for: "[_1]" is only available to users who are logged in.',$domdesc).'
'); + } + } + $r->print(&Apache::loncommon::end_page()); + return OK; + } + + my $cnum; + if ($cattype eq 'codesrch') { + my ($uniquecode,$codemsg,$brtext); + if ($env{'form.uniquecode'}) { + $uniquecode = $env{'form.uniquecode'}; + $uniquecode =~ s/^\s+|\s+$//g; + } + my $js = ''."\n"; + $r->print(&Apache::loncommon::start_page('Search for a Course/Community',$js)); + if ($uniquecode =~ /^\w{6}$/) { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/coursecatalog", + text=>"Course/Community Catalog"}); + $brtext = 'Search Result'; + } else { + $brtext = 'Course/Community Catalog'; + } + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/coursecatalog", + text=>"$brtext"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog')); + $r->print(&coursesearch($codedom,$domdesc,$uniquecode)); + if ($uniquecode =~ /^\w{6}$/) { + $r->print('
'); + my $confname = $codedom.'-domainconfig'; + my %codes = &Apache::lonnet::get('uniquecodes',[$uniquecode],$codedom,$confname); + if ($codes{$uniquecode}) { + $cnum = $codes{$uniquecode}; + my %courses = &Apache::lonnet::courseiddump($codedom,'.',1,'.','.', + $cnum,undef,undef,'.',1); + if (keys(%courses)) { + $env{'form.coursenum'} = $cnum; + my %courseinfo = &build_courseinfo_hash(\%courses,$knownuser,$codedom,$canviewall); + undef($env{'form.coursenum'}); + if (ref($courseinfo{$codedom.'_'.$cnum}) eq 'HASH') { + $r->print(&Apache::lonhtmlcommon::start_pick_box()); + my @cols = ('title','ownerlastnames','seclist','access'); + my %lt = &Apache::lonlocal::texthash( + title => 'Title', + ownerlastnames => 'Owner & Co-owner(s)', + seclist => 'Sections', + access => 'Default Access Dates for Students', + ); + my @shown; + foreach my $item (@cols) { + if ($courseinfo{$codedom.'_'.$cnum}{$item}) { + push(@shown,$item); + } + } + my $num = 0; + foreach my $item (@shown) { + $num ++; + $r->print(&Apache::lonhtmlcommon::row_title($lt{$item}). + $courseinfo{$codedom.'_'.$cnum}{$item}); + if ($item eq 'title') { + if ($courseinfo{$codedom.'_'.$cnum}{'showsyllabus'}) { + my $usehttp = 0; + if (($ENV{'SERVER_PORT'} == 443) && ($courseinfo{$codedom.'_'.$cnum}{'extsyllplain'})) { + $usehttp = 1; + } + $r->print(' '. + ''. + &mt('Syllabus').''); + } + } + my $arg = ( $num == scalar(@shown) ? 1 : '' ); + $r->print(&Apache::lonhtmlcommon::row_closure($arg)); + } + $r->print(&Apache::lonhtmlcommon::end_pick_box()); + my $selfenroll = &selfenroll_status($courseinfo{$codedom.'_'.$cnum},$codedom.'_'.$cnum); + if ($selfenroll) { + $r->print('
'.$selfenroll); + } + $r->print('
'."\n". + ''."\n". + ''."\n". + '
'."\n"); + + } else { + $codemsg = &mt('Code matched, but course ID to which this mapped is invalid.'); + } + } else { + $codemsg = &mt('Code matched, but course ID to which this mapped is invalid.'); + } + } else { + $codemsg = &mt('No match'); + } + } + $r->print('
'.&Apache::loncommon::end_page()); + return OK; + } else { + if ($env{'form.coursenum'}) { + $cnum = $env{'form.coursenum'}; + } + } + + if ($env{'form.catalog_maxdepth'} ne '') { + $env{'form.catalog_maxdepth'} =~ s{\D}{}g; } - my $subcats; + + my (@cats,@trails,%allitems,%idx,@jsarray,%subcathash,$subcats); if ($env{'form.withsubcats'}) { $subcats = \%subcathash; } &Apache::loncommon::extract_categories($cathash,\@cats,\@trails,\%allitems, \%idx,\@jsarray,$subcats); my ($numtitles,@codetitles); - if ($env{'form.coursenum'} ne '' && &user_is_known()) { + if (($env{'form.coursenum'} ne '') && ($knownuser)) { &course_details($r,$codedom,$formname,$domdesc,\@trails,\%allitems,\@codetitles); } else { my ($catlinks,$has_subcats,$selitem) = &category_breadcrumbs($codedom,@cats); + my $wasacctext = &get_wasactive_text(); my $catjs = <<"ENDSCRIPT"; function setCatDepth(depth) { @@ -114,13 +254,42 @@ function setCourseId(caller) { } ENDSCRIPT - $catjs .= &courselink_javascript(); + $catjs .= &courselink_javascript($r); + if (&user_is_dc($codedom) || $canviewall) { + $catjs .= <print(&print_course_listing($codedom,$numtitles,undef,undef,undef, - \@codetitles)); + \@codetitles,$canviewall)); } } else { my (%add_entries); @@ -130,6 +299,7 @@ ENDSCRIPT if (!$deeper) { $alert = &mt('Choose a category to display'); } + &js_escape(\$alert); $catjs .= <'; - &cat_header($r,$codedom,$catjs,\%add_entries,$catlinks); + &cat_header($r,$codedom,$catjs,\%add_entries,$catlinks,undef,$cattype); if ($env{'form.currcat_0'} ne '') { $r->print('
'. - &additional_filters($codedom,$has_subcats)."\n"); + &additional_filters($codedom,$has_subcats,$canviewall)."\n"); $r->print(''."\n"); for (my $i=0; $i<$deeper; $i++) { @@ -153,6 +323,8 @@ ENDJS my $display_button; if ($env{'form.currcat_0'} eq 'communities::0') { $display_button = &mt('Display communities'); + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $display_button = &mt('Display placement tests'); } else { $display_button = &mt('Display courses'); } @@ -165,7 +337,8 @@ ENDJS $display_button.'" />


'); } if ($env{'form.state'} eq 'listing') { - $r->print(&print_course_listing($codedom,undef,\@trails,\%allitems,$subcats,\@codetitles)); + $r->print(&print_course_listing($codedom,undef,\@trails,\%allitems,$subcats,\@codetitles, + $canviewall)); } } } @@ -179,10 +352,10 @@ sub course_details { my %add_entries = (topmargin => "0", marginheight => "0",); my $js = ''."\n"; + &courselink_javascript($r).''."\n"; my $start_page = &Apache::loncommon::start_page('Course/Community Catalog',$js, - {'add_entries' => \%add_entries, }); + {'add_entries' => \%add_entries, }); $r->print($start_page); if ($env{'form.numtitles'} > 0) { &Apache::lonhtmlcommon::add_breadcrumb @@ -191,41 +364,63 @@ sub course_details { } my $brtextone = 'Course listing'; my $brtexttwo = 'Course details'; + my $textthree = &mt('Detailed course information:'); + my $textfour = &mt('Back to course listing'); if ($env{'form.currcat_0'} eq 'communities::0') { $brtextone = 'Community listing'; $brtexttwo = 'Community details'; + $textthree = &mt('Detailed community information:'); + $textfour = &mt('Back to community listing'); + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $brtextone = 'Placement test listing'; + $brtexttwo = 'Placement test details'; + $textthree = &mt('Detailed placement test information:'); + $textfour = &mt('Back to placement test listing'); } &Apache::lonhtmlcommon::add_breadcrumb ({href=>"javascript:document.$formname.submit()", text=>$brtextone}, {text=>$brtexttwo}); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog')); - $r->print('
'); - if ($env{'form.currcat_0'} eq 'communities::0') { - $r->print(&mt('Detailed community information:')); - } else { - $r->print(&mt('Detailed course information:')); - } - $r->print('

'. - &print_course_listing($codedom,undef,$trails,$allitems,undef,$codetitles). - '

'); - $r->print('
'. - ''); - if ($env{'form.currcat_0'} eq 'communities::0') { - $r->print(&mt('Back to community listing')); - } else { - $r->print(&mt('Back to course listing')); - } - $r->print(''. - &Apache::lonhtmlcommon::echo_form_input(['coursenum','catalogfilter', - 'showdetails','courseid']).'
'); + $r->print( + &Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog'). + '

'.$textthree.'

'. + &print_course_listing($codedom,undef,$trails,$allitems,undef,$codetitles). + '
'. + '
'. + &Apache::lonhtmlcommon::actionbox([ + ''.$textfour.'']). + &Apache::lonhtmlcommon::echo_form_input(['coursenum','catalogfilter', + 'showdetails','courseid']). + '
'); return; } +sub coursesearch { + my ($codedom,$domdesc,$uniquecode) = @_; + my %lt = &Apache::lonlocal::texthash ( + crlk => 'Course look-up', + code => 'Code', + ifyo => 'Enter the course code (six letters and numbers)', + srch => 'Find course', + ); + return <<"END"; +

$lt{'crlk'} ($domdesc)

+$lt{'ifyo'} +
+ +  +
+
+
+END +} + sub courselink_javascript { + my ($r) = @_; + my $hostname = $r->hostname(); return <<"END"; -function ToSyllabus(cdom,cnum) { +function ToSyllabus(cdom,cnum,usehttp) { if (cdom == '' || cdom == null) { return; } @@ -233,6 +428,13 @@ function ToSyllabus(cdom,cnum) { return; } document.linklaunch.action = "/public/"+cdom+"/"+cnum+"/syllabus"; + if (usehttp == 1) { + var hostname = '$hostname'; + if (hostname != '') { + document.linklaunch.action = 'http://'+hostname+document.linklaunch.action; + } + document.linklaunch.action += '?usehttp=1'; + } document.linklaunch.submit(); } @@ -249,7 +451,7 @@ END } sub instcode_course_selector { - my ($r,$codedom,$formname,$domdesc,$catlinks,$catjs,$codetitles) = @_; + my ($r,$codedom,$formname,$domdesc,$catlinks,$catjs,$codetitles,$cattype,$canviewall) = @_; my %coursecodes = (); my %codes = (); my %cat_titles = (); @@ -262,19 +464,25 @@ sub instcode_course_selector { my ($jscript,$totcodes,$numtitles,$lasttitle) = &Apache::courseclassifier::instcode_selectors_data($codedom,$formname, \%cat_items,$codetitles,\%cat_titles,\%cat_order); - my $js = ''; + my $js = ''; if ($totcodes) { if (($env{'form.state'} eq 'listing') && ($numtitles > 0)) { - $add_entries{'onLoad'} = 'setElements()'; + $add_entries{'onload'} = 'setElements();'; } - &cat_header($r,$codedom,$js,\%add_entries,$catlinks,$numtitles); + if (&user_is_dc($codedom) || $canviewall) { + $add_entries{'onload'} .= ' toggleStatuses();toggleWasActive();' + } + &cat_header($r,$codedom,$js,\%add_entries,$catlinks,$numtitles,$cattype); my $cat_maxdepth = $env{'form.catalog_maxdepth'}; $r->print('
'. ''."\n". ''."\n". ''. - &additional_filters($codedom)); + &additional_filters($codedom,undef,$canviewall)); if ($numtitles > 0) { $r->print(''.&mt('Choose which course(s) to list.').'
'. &Apache::courseclassifier::build_instcode_selectors($numtitles, @@ -283,14 +491,17 @@ sub instcode_course_selector { $r->print(''."\n". ''."\n". ''."\n". - ''."\n". ''. '


'); } else { - $js = ''; - &cat_header($r,$codedom,$js,\%add_entries,$catlinks,$numtitles); + $js = ''; + &cat_header($r,$codedom,$js,\%add_entries,$catlinks,$numtitles,$cattype); my $cat_maxdepth = $env{'form.catalog_maxdepth'}; $r->print('
'. ''. @@ -302,14 +513,16 @@ sub instcode_course_selector { } sub cat_header { - my ($r,$codedom,$js,$add_entries,$catlinks,$numtitles) = @_; + my ($r,$codedom,$js,$add_entries,$catlinks,$numtitles,$cattype) = @_; my $start_page = - &Apache::loncommon::start_page('Other',$js, + &Apache::loncommon::start_page('Course/Community Catalog',$js, { 'add_entries' => $add_entries, }); $r->print($start_page); my $brtext = 'Course listing'; if ($env{'form.currcat_0'} eq 'communities::0') { $brtext = 'Community listing'; + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $brtext = 'Placement test listing'; } if ($env{'form.state'} eq 'listing') { if ($numtitles > 0) { @@ -327,15 +540,17 @@ sub cat_header { text=>"Course/Community Catalog"}); } $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course/Community Catalog')); - my $onchange = 'this.form.submit()'; - $r->print(''. - '
'.&mt('Domain:').''. - &Apache::loncommon::select_dom_form($codedom,'showdom','',1,$onchange)); - if (!$onchange) { + if ($cattype eq 'std') { + my $onchange = 'this.form.submit()'; + $r->print(''. + '
'.&mt('Domain:').''. + &Apache::loncommon::select_dom_form($codedom,'showdom','',1,$onchange)); + if (!$onchange) { $r->print(' '); + } + $r->print('
'); } - $r->print('
'. - '
print(''. ''.$catlinks.'
'); return; @@ -361,6 +576,9 @@ sub category_breadcrumbs { } elsif ($cats[0][0] eq 'communities') { $catlinks .= &mt('Communities'); $env{'form.currcat_0'} = 'communities::0'; + } elsif ($cats[0][0] eq 'placement') { + $catlinks .= &mt('Placement Tests'); + $env{'form.currcat_0'} = 'placement::0'; } else { my $name = $cats[0][0]; my $item = &escape($name).'::0'; @@ -373,8 +591,6 @@ sub category_breadcrumbs { if (($env{'form.currcat_0'} ne '') && ($env{'form.currcat_0'} ne 'instcode::0')) { $catlinks .= $crumbsymbol; - } else { - $catlinks .= ''; } } } else { @@ -395,7 +611,7 @@ sub category_breadcrumbs { $catlinks .= ''; for (my $j=0; $j<@{$cats[$shallower]{$container}}; $j++) { my $name = $cats[$shallower]{$container}[$j]; - my $item = &escape($name).':'.$container.':'.$shallower; + my $item = &escape($name).':'.&escape($container).':'.$shallower; my $selected = ''; if ($item eq $env{'form.currcat_'.$shallower}) { $selected = ' selected="selected"'; @@ -467,6 +683,8 @@ sub main_category_selector { $maincatlinks .= &mt('Official courses (with institutional codes)'); } elsif ($name eq 'communities') { $maincatlinks .= &mt('Communities'); + } elsif ($name eq 'placement') { + $maincatlinks .= &mt('Placement Tests'); } else { $maincatlinks .= $name; } @@ -492,9 +710,14 @@ sub get_depth_values { } sub additional_filters { - my ($codedom,$has_subcats) = @_; - my $output = ''; - if (($env{'form.currcat_0'} ne 'instcode::0') && + my ($codedom,$has_subcats,$canviewall) = @_; + my $is_dc = &user_is_dc($codedom); + my $output = '
'; + if ($is_dc || $canviewall) { + $output .= '
'.&mt('Options').''; + } + $output .= '
'; + &unescape($catname)).'
'; } } my $show_selfenroll_status; @@ -523,41 +746,145 @@ sub additional_filters { } my $selfenroll_text; if ($env{'form.currcat_0'} eq 'communities::0') { - $selfenroll_text = &mt('Only show communities which allow self-enrollment'); + $selfenroll_text = &mt('Only show communities which currently allow self-enrollment (or will allow it in the future)'); + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $selfenroll_text = &mt('Only show placement tests which currently allow self-enrollment (or will allow it in the future)'); } else { - $selfenroll_text = &mt('Only show courses which allow self-enrollment'); + $selfenroll_text = &mt('Only show courses which currently allow self-enrollment (or will allow it in the future)'); } - $output .= ''; - if (&user_is_dc($codedom)) { + '
'; + if ($is_dc || $canviewall) { + my ($titlesref,$orderref) = &get_statustitles('filters'); my $showdetails_status; if ($env{'form.showdetails'}) { $showdetails_status = 'checked="checked" '; } my $showhidden_status; if ($env{'form.showhidden'}) { - $showhidden_status = 'checked="checked" '; + $showhidden_status = 'checked="checked" '; + } + my @currstatuses = &Apache::loncommon::get_env_multiple('form.showcounts'); + my ($details_text,$hidden_text,$statusdisplay,$cellborder); + my $wasactivedisplay = 'none'; + if ($env{'form.showdetails'}) { + $statusdisplay = 'block'; + $cellborder = 'border-left: 1px solid;'; + if (grep(/^Previous$/,@currstatuses)) { + $wasactivedisplay = 'block'; + } + } else { + $statusdisplay = 'none'; + $cellborder = 'border-left: 0px'; } - my $dc_title = &Apache::lonnet::plaintext('dc'); - my ($details_text,$hidden_text); if ($env{'form.currcat_0'} eq 'communities::0') { - $details_text = &mt('Show full details for each community ([_1] only)',$dc_title); - $hidden_text = &mt('Include communities set to be hidden from catalog ([_1] only)',$dc_title); + $details_text = &mt('Show full details for each community (domain staff only)'); + $hidden_text = &mt('Include communities set to be hidden from catalog (domain staff only)'); + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $details_text = &mt('Show full details for each placement test (domain staff only)'); + $hidden_text = &mt('Include placement tests set to be hidden from catalog (domain staff only)'); } else { - $details_text = &mt('Show full details for each course ([_1] only)',$dc_title); - $hidden_text = &mt('Include courses set to be hidden from catalog ([_1] only)',$dc_title); + $details_text = &mt('Show full details for each course (domain staff only)'); + $hidden_text = &mt('Include courses set to be hidden from catalog (domain staff only)'); + } + if ($is_dc) { + $output .= ''. + '
'."\n"; } - $output .= ''; + $showdetails_status.'onclick="toggleStatuses();" />'. + $details_text.''."\n". + ''; + } else { + $output .= ''; } - $output .= '
'; + if (($env{'form.currcat_0'} ne 'instcode::0') && ($env{'form.currcat_0'} ne '') && ($has_subcats)) { my $include_subcat_status; if ($env{'form.withsubcats'}) { @@ -510,11 +733,11 @@ sub additional_filters { } my ($catname) = split(/:/,$env{'form.currcat_'.$counter}); if ($catname ne '') { - $output .= '
'. + $output .= ''. '
'."\n". + $output .= ''. ''."\n".'
'. - ''."\n".'
'. + '
'; + if (ref($orderref) eq 'ARRAY') { + if (@{$orderref} > 0) { + foreach my $type (@{$orderref}) { + my $checked; + if (grep(/^\Q$type\E$/,@currstatuses)) { + $checked = ' checked="checked"'; + } + my $title; + if (ref($titlesref) eq 'HASH') { + $title = $titlesref->{$type}; + } + unless ($title) { + $title = &mt($type); + } + my $onclick; + if ($type eq 'Previous') { + $onclick = ' onclick="toggleWasActive();"'; + } + $output .= ''. + ''; + if ($type eq 'Previous') { + my %milestonetext = &Apache::lonlocal::texthash ( + accessend => 'immediately prior to default end access date', + enrollend => 'immediately prior to end date for auto-enrollment', + date => 'immediately prior to specific date:', + ); + my @statuses = &Apache::loncommon::get_env_multiple('form.showcounts'); + $output .= ''; + if ($checked) { + $output .= &get_wasactive_text(); + } + $output .= ''. + '
'. + ''; + my @milestones = ('accessend'); + if (&Apache::lonnet::auto_run(undef,$codedom)) { + push(@milestones,'enrollend'); + } + push(@milestones,'date'); + foreach my $item (@milestones) { + my $checked; + if ($env{'form.state'} eq 'listing') { + if ($env{'form.wasactive'} eq $item) { + $checked = ' checked="checked"'; + } + } elsif ($item eq 'accessend') { + $checked = ' checked="checked"'; + } + $output .= + ''; + } + $output .= '
 '. + ''; + if ($item eq 'date') { + my $wasactiveon; + if (grep(/^Previous$/,@currstatuses)) { + $wasactiveon = + &Apache::lonhtmlcommon::get_date_from_form('wasactiveon'); + } else { + $wasactiveon = 'now'; + } + $output .= ' '. + &Apache::lonhtmlcommon::date_setter('coursecatalog', + 'wasactiveon', + $wasactiveon, + '','','',1,'', + '','',1); + } + $output .= '
'; + } + $output .= '
'; + } + } + } + $output .= '

'; + $output .= ''. + '
'; return $output; } @@ -574,6 +901,56 @@ sub user_is_dc { return; } +sub canview_all { + my ($knownuser,$codedom) = @_; + my $canviewall = 0; + my $page = 'coursecatalog'; + if (&LONCAPA::lonauthcgi::can_view($page)) { + $canviewall = 1; + } elsif (&LONCAPA::lonauthcgi::check_ipbased_access($page)) { + $canviewall= 1; + } elsif (($knownuser) && ($codedom ne '')) { + if (&Apache::lonnet::allowed('dcd',$codedom)) { + $canviewall = 1; + } + } + return $canviewall; +} + +sub get_statustitles { + my ($caller) = @_; + my @status_order = ('Active','Future','Previous'); + my %status_title; + if ($caller eq 'filters') { + %status_title = &Apache::lonlocal::texthash( + Previous => 'Show count for past access', + Active => 'Show count for current student access', + Future => 'Show count for future student access', + ); + if ($env{'form.currcat_0'} eq 'communities::0') { + $status_title{'Active'} = 'Show count for current member access'; + $status_title{'Future'} = 'Show count for future member access'; + } + } else { + %status_title = &Apache::lonlocal::texthash( + Previous => 'Previous access', + Active => 'Current access', + Future => 'Future access', + ); + } + return (\%status_title,\@status_order); +} + +sub get_wasactive_text { + my $wasacctext = ' -- '; + if ($env{'form.currcat_0'} eq 'communities::0') { + $wasacctext .= &mt('where member access status was current ...'); + } else { + $wasacctext .= &mt('where student access status was current ...'); + } + return $wasacctext; +} + sub search_official_courselist { my ($domain,$numtitles,$codetitles) = @_; my $instcode = &Apache::courseclassifier::instcode_search_str($domain,$numtitles,$codetitles); @@ -621,6 +998,8 @@ sub search_courselist { } if ($env{'form.currcat_0'} eq 'communities::0') { $typefilter = 'Community'; + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $typefilter = 'Placement'; } else { $typefilter = '.'; } @@ -633,12 +1012,13 @@ sub search_courselist { } sub print_course_listing { - my ($domain,$numtitles,$trails,$allitems,$subcats,$codetitles) = @_; + my ($domain,$numtitles,$trails,$allitems,$subcats,$codetitles,$canviewall) = @_; my $output; my %courses; my $knownuser = &user_is_known(); + my $canviewall = &canview_all(); my $details = $env{'form.coursenum'}; - if (&user_is_dc($domain)) { + if (&user_is_dc($domain) || $canviewall) { if ($env{'form.showdetails'}) { $details = 1; } @@ -648,11 +1028,15 @@ sub print_course_listing { $env{'form.coursenum'}, undef,undef,'.',1); if (keys(%courses) == 0) { + $output = '

'; if ($env{'form.currcat_0'} eq 'communities::0') { $output .= &mt('The courseID provided does not match a community in this domain.'); - } else { + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $output .= &mt('The courseID provided does not match a placement test in this domain.'); + } else { $output .= &mt('The courseID provided does not match a course in this domain.'); } + $output .= '

'; return $output; } } else { @@ -662,23 +1046,26 @@ sub print_course_listing { %courses = &search_courselist($domain,$subcats); } if (keys(%courses) == 0) { + $output = '

'; if ($env{'form.currcat_0'} eq 'communities::0') { - $output = &mt('No communities match the criteria you selected.'); + $output .= &mt('No communities match the criteria you selected.'); + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $output .= &mt('No placement tests match the criteria you selected.'); } else { - $output = &mt('No courses match the criteria you selected.'); + $output .= &mt('No courses match the criteria you selected.'); } + $output .= '

'; return $output; } - if (($knownuser) && (!$env{'form.showdetails'}) && (!&user_is_dc($domain))) { + if (($knownuser) && (!$env{'form.showdetails'}) && (!&user_is_dc($domain)) && (!$canviewall)) { $output = ''.&mt('Note for students:').' ' .&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.') .'

'; } } my $now = time; - my %domconfig = - &Apache::lonnet::get_dom('configuration',['usercreation'],$domain); - $output .= &construct_data_table($knownuser,\%courses,$details,undef,$now,\%domconfig,$trails,$allitems); + $output .= &construct_data_table($knownuser,$domain,\%courses,$details,undef, + $now,$trails,$allitems,$canviewall); $output .= "\n".'
'. ''. ''. @@ -687,14 +1074,13 @@ sub print_course_listing { } sub construct_data_table { - my ($knownuser,$courses,$details,$usersections,$now,$domconfig,$trails, - $allitems) = @_; + my ($knownuser,$domain,$courses,$details,$usersections,$now,$trails,$allitems,$canviewall) = @_; my %sortname; if (($details eq '') || ($env{'form.showdetails'})) { $sortname{'Code'} = 'code'; $sortname{'Categories'} = 'cats'; $sortname{'Title'} = 'title'; - $sortname{'Owner(s)'} = 'owner'; + $sortname{'Owner & Co-owner(s)'} = 'owner'; } my $output = &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); @@ -704,7 +1090,7 @@ sub construct_data_table { } else { push(@coltitles,'Categories'); } - push(@coltitles,('Sections','Crosslisted','Title','Owner(s)')); + push(@coltitles,('Sections','Crosslisted','Title','Owner & Co-owner(s)')); if (ref($usersections) eq 'HASH') { $coltitles[1] = 'Your Section'; } @@ -719,24 +1105,75 @@ sub construct_data_table { } $output .= ''; } - if ($knownuser) { + my (@fields,%fieldtitles,$wasactiveon); + if ($knownuser || ($canviewall && $details)) { if ($details) { if ($env{'form.currcat_0'} eq 'communities::0') { - $output .= ''.&mt('Default Access Dates for Members').''; + $output .= ''.&mt('Default Access Dates for Members').''. + ''.&mt('Member Counts').''; + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $output .= + ''.&mt('Default Access Dates for Students').''. + ''.&mt('Student Counts').''; } else { $output .= ''.&mt('Default Access Dates for Students').''. ''.&mt('Student Counts').''. ''.&mt('Auto-enrollment of[_1]registered students','
').''; } + my ($titlesref,$orderref) = &get_statustitles(); + my @statuses; + if (&user_is_dc($domain) || $canviewall) { + @statuses = &Apache::loncommon::get_env_multiple('form.showcounts'); + if (grep(/^Previous$/,@statuses)) { + if ($env{'form.wasactive'} eq 'date') { + $wasactiveon = + &Apache::lonhtmlcommon::get_date_from_form('wasactiveon'); + } else { + $wasactiveon = $env{'form.wasactive'}; + } + } + if (ref($orderref) eq 'ARRAY') { + foreach my $status (@{$orderref}) { + if (grep(/^\Q$status\E$/,@statuses)) { + push(@fields,$status); + } + } + } + } else { + @fields = ('Active','Future'); + } + foreach my $status (@fields) { + my $title; + if (ref($titlesref) eq 'HASH') { + $title = $titlesref->{$status}; + } + unless ($title) { + $title = &mt($status); + } + $fieldtitles{$status} = $title; + } } else { $output .= ''.&mt('Details').''; } } $output .= ''.&mt('Self-enroll (if permitted)').''; &Apache::loncommon::end_data_table_header_row(); - my %courseinfo = &build_courseinfo_hash($courses,$knownuser,$details, - $usersections); + my (%numbers,%creditsum); + my ($showcredits,$defofficial,$defunofficial,$deftextbook); + my %domdefaults = &Apache::lonnet::get_domain_defaults($domain); + unless (($env{'form.currcat_0'} eq 'communities::0') || ($env{'form.currcat_0'} eq 'placement::0')) { + if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) { + $showcredits = 1; + $defofficial = $domdefaults{'officialcredits'}; + $defunofficial = $domdefaults{'unofficialcredits'}; + $deftextbook = $domdefaults{'textbookcredits'}; + } + } + my %courseinfo = &build_courseinfo_hash($courses,$knownuser,$domain,$canviewall,$details, + $usersections,\@fields,\%fieldtitles, + $wasactiveon,\%numbers,\%creditsum, + $showcredits,$defofficial,$defunofficial,$deftextbook); my %Sortby; foreach my $course (sort(keys(%{$courses}))) { if ($env{'form.sortby'} eq 'code') { @@ -762,22 +1199,86 @@ sub construct_data_table { @sorted_courses = sort { lc($a) cmp lc($b) } (keys(%Sortby)); } my $count = 1; + my $totalsec = 0; foreach my $item (@sorted_courses) { foreach my $course (@{$Sortby{$item}}) { $output.=&Apache::loncommon::start_data_table_row(); $output.=&courseinfo_row($courseinfo{$course},$knownuser,$details, - \$count,$now,$course,$trails,$allitems); + \$count,$now,$course,$trails,$allitems,\%numbers,$canviewall); $output.=&Apache::loncommon::end_data_table_row(); } } + if (($knownuser || $canviewall) && ($count > 1) && $env{'form.showdetails'}) { + if (&user_is_dc($domain) || $canviewall) { + my %lt = &Apache::lonlocal::texthash ( + 'Active' => 'Total current students', + 'Future' => 'Total future students', + 'Previous' => 'Total previous students', + 'courses' => 'Total unique codes and courses without codes', + 'sections' => 'Total sections', + 'xlists' => 'Total cross-listings', + ); + if ($showcredits) { + $lt{'cr_Active'} = &mt('Total current student credit hours'); + $lt{'cr_Future'} = &mt('Total future student credit hours'); + $lt{'cr_Previous'} = &mt('Total previous student credit hours'); + } + if ($env{'form.currcat_0'} eq 'communities::0') { + $lt{'courses'} = &mt('Total communities'); + $lt{'Active'} = &mt('Total current members'); + $lt{'Future'} = &mt('Total future members'); + $lt{'Previous'} = &mt('Total previous members'); + } elsif ($env{'form.currcat_0'} eq 'placement::0') { + $lt{'courses'} = &mt('Total placement tests'); + } + my $colspan = 8; + if ($showcredits) { + $colspan = 4; + } + $output .= ''. + ' '. + ''. + ''; + foreach my $item ('courses','sections','xlists') { + $output .= ''. + ''. + ''. + ''."\n"; + } + if (@fields > 0) { + foreach my $status (@fields) { + $output .= ''. + ''. + ''. + ''."\n"; + } + } + $output .= '
'.$lt{$item}.' '.$numbers{$item}.'
'.$lt{$status}.' '.$numbers{$status}.'
'; + if ($showcredits) { + $output .= ''; + foreach my $status (@fields) { + $output .= ''. + ''. + ''; + } + $output .= '
'.$lt{'cr_'.$status}.' '.$creditsum{$status}.'
'; + } + } + } $output .= &Apache::loncommon::end_data_table(); return $output; } sub build_courseinfo_hash { - my ($courses,$knownuser,$details,$usersections) = @_; + my ($courses,$knownuser,$domain,$canviewall,$details,$usersections,$fields,$fieldtitles, + $wasactiveon,$numbers,$creditsum,$showcredits,$defofficial,$defunofficial) = @_; my %courseinfo; my $now = time; + my $gettotals; + if ((keys(%{$courses}) > 0) && (&user_is_dc($domain) || $canviewall) && ($details)) { + $gettotals = 1; + } + my (%uniquecodes,$nocodes,$defcreds); foreach my $course (keys(%{$courses})) { my $descr; if (ref($courses->{$course}) eq 'HASH') { @@ -787,7 +1288,7 @@ sub build_courseinfo_hash { $cleandesc=~s/'/\\'/g; $cleandesc =~ s/^\s+//; my ($cdom,$cnum)=split(/\_/,$course); - my ($instcode,$singleowner,$ttype,$selfenroll_types, + my ($instcode,$singleowner,$ttype,$selfenroll_types,$extsyllplain, $selfenroll_start,$selfenroll_end,@owners,%ownernames,$categories); if (ref($courses->{$course}) eq 'HASH') { $descr = $courses->{$course}{'description'}; @@ -798,13 +1299,19 @@ sub build_courseinfo_hash { $selfenroll_start = $courses->{$course}{'selfenroll_start_date'}; $selfenroll_end = $courses->{$course}{'selfenroll_end_date'}; $categories = $courses->{$course}{'categories'}; + $extsyllplain = $courses->{$course}{'extsyllplain'}; push(@owners,$singleowner); - if (ref($courses->{$course}{'co-owners'}) eq 'ARRAY') { - foreach my $item (@{$courses->{$course}{'co-owners'}}) { + if ($courses->{$course}{'co-owners'} ne '') { + foreach my $item (split(/,/,$courses->{$course}{'co-owners'})) { push(@owners,$item); } } } + if ($instcode ne '') { + $uniquecodes{$instcode} = 1; + } else { + $nocodes ++; + } foreach my $owner (@owners) { my ($ownername,$ownerdom); if ($owner =~ /:/) { @@ -836,32 +1343,61 @@ sub build_courseinfo_hash { $courseinfo{$course}{'selfenroll_start'} = $selfenroll_start; $courseinfo{$course}{'selfenroll_end'} = $selfenroll_end; $courseinfo{$course}{'categories'} = $categories; + $courseinfo{$course}{'extsyllplain'} = $extsyllplain; my %coursehash = &Apache::lonnet::dump('environment',$cdom,$cnum); my @classids; my @crosslistings; my ($seclist,$numsec) = &identify_sections($coursehash{'internal.sectionnums'}); - if (ref($usersections) eq 'HASH') { - if (ref($usersections->{$course}) eq 'ARRAY') { - $seclist = join(', ',@{$usersections->{$course}}); - } - } $courseinfo{$course}{'seclist'} = $seclist; my ($xlist_items,$numxlist) = &identify_sections($coursehash{'internal.crosslistings'}); + if (ref($numbers) eq 'HASH') { + $numbers->{'sections'} += $numsec; + $numbers->{'xlists'} += $numxlist; + } my $showsyllabus = 1; # default is to include a syllabus link if (defined($coursehash{'showsyllabus'})) { $showsyllabus = $coursehash{'showsyllabus'}; } $courseinfo{$course}{'showsyllabus'} = $showsyllabus; + if ($showcredits) { + if ($coursehash{'internal.defaultcredits'}) { + $courseinfo{$course}{'defaultcredits'} = $coursehash{'internal.defaultcredits'}; + } elsif ($instcode ne '') { + $courseinfo{$course}{'defaultcredits'} = $defofficial; + } else { + $courseinfo{$course}{'defaultcredits'} = $defunofficial; + } + $defcreds = $courseinfo{$course}{'defaultcredits'}; + } if (((defined($env{'form.coursenum'}) && ($cnum eq $env{'form.coursenum'}))) || - ($knownuser && ($details == 1))) { - $courseinfo{$course}{'counts'} = &count_students($cdom,$cnum,$numsec); - $courseinfo{$course}{'autoenrollment'} = - &autoenroll_info(\%coursehash,$now,$seclist,$xlist_items, - $instcode,\@owners,$cdom,$cnum); - + (($knownuser || $canviewall) && ($details == 1))) { + my $milestone; + if ($wasactiveon eq 'accessend') { + if ($coursehash{'default_enrollment_end_date'}) { + $milestone = $coursehash{'default_enrollment_end_date'}; + } else { + $milestone = time; + } + } elsif ($wasactiveon eq 'enrollend') { + if ($coursehash{'internal.autoend'}) { + $milestone = $coursehash{'internal.autoend'}; + } else { + $milestone = time; + } + } else { + $milestone = $wasactiveon; + } + $courseinfo{$course}{'counts'} = + &count_students($cdom,$cnum,$numsec,$fields,$fieldtitles,$gettotals, + $numbers,$creditsum,$showcredits,$defcreds,$milestone); + if ($instcode ne '') { + $courseinfo{$course}{'autoenrollment'} = + &autoenroll_info(\%coursehash,$now,$seclist,$xlist_items, + $instcode,\@owners,$cdom,$cnum); + } my $startaccess = ''; my $endaccess = ''; my $accessdates; @@ -914,41 +1450,86 @@ sub build_courseinfo_hash { } $courseinfo{$course}{'xlist'} = $xlist_items; } + if (ref($numbers) eq 'HASH') { + $numbers->{'courses'} = $nocodes + scalar(keys(%uniquecodes)); + } return %courseinfo; } sub count_students { - my ($cdom,$cnum,$numsec) = @_; + my ($cdom,$cnum,$numsec,$fieldsref,$titlesref,$getcounts,$numbers,$creditsum, + $showcredits,$defcreds,$wasactiveon) = @_; + my $countslist = ''. + &mt('[quant,_1,section,sections,No sections]',$numsec).''; + my (@fields,%titles,$showexpired); + if ((ref($fieldsref) eq 'ARRAY') && (ref($titlesref) eq 'HASH') && + (ref($numbers) eq 'HASH')) { + @fields = @{$fieldsref}; + %titles = %{$titlesref}; + if (grep(/^Previous$/,@fields)) { + $showexpired = 1; + } + } else { + return; + } my $classlist = &Apache::loncoursedata::get_classlist($cdom,$cnum); - my %student_count = ( - Active => 0, - Future => 0, - Expired => 0, - ); + my (%student_count,%credit_count); + %student_count = ( + Active => 0, + Future => 0, + Previous => 0, + ); + if ($showcredits) { + %credit_count = ( + Active => 0, + Future => 0, + Previous => 0, + ); + } my %idx; $idx{'status'} = &Apache::loncoursedata::CL_STATUS(); - my %status_title = &Apache::lonlocal::texthash( - Expired => 'Previous access', - Active => 'Current access', - Future => 'Future access', - ); - + $idx{'end'} = &Apache::loncoursedata::CL_END(); + $idx{'credits'} = &Apache::loncoursedata::CL_CREDITS(); while (my ($student,$data) = each(%$classlist)) { - $student_count{$data->[$idx{'status'}]} ++; + my $status = $data->[$idx{'status'}]; + my $credits = $data->[$idx{'credits'}]; + if ($credits eq '') { + $credits = $defcreds; + } + if ($status eq 'Expired') { + if (($showexpired) && + ($data->[$idx{'end'}] >= $wasactiveon)) { + $student_count{'Previous'} ++; + if ($showcredits) { + $credit_count{'Previous'} += $credits; + } + } + } else { + $student_count{$status} ++; + if ($showcredits) { + $credit_count{$status} += $credits; + } + } } - - my $countslist = &mt('[quant,_1,section:,sections:,No sections]',$numsec).'
'; - foreach my $status ('Active','Future') { - $countslist .= ''.$status_title{$status}.': '. - $student_count{$status}.'
'; + if (@fields) { + $countslist .= ':
'; + foreach my $status (@fields) { + $countslist .= ''.$titles{$status}.': '. + $student_count{$status}.'
'; + $numbers->{$status} += $student_count{$status}; + if ($showcredits) { + $creditsum->{$status} += $credit_count{$status}; + } + } } return $countslist; } sub courseinfo_row { - my ($info,$knownuser,$details,$countref,$now,$course,$trails,$allitems) = @_; + my ($info,$knownuser,$details,$countref,$now,$course,$trails,$allitems,$numbers,$canviewall) = @_; my ($cdom,$cnum,$title,$ownerlast,$code,$owner,$seclist,$xlist_items, - $accessdates,$showsyllabus,$counts,$autoenrollment,$output,$categories); + $accessdates,$showsyllabus,$counts,$autoenrollment,$output,$categories, + $extsyllplain); if (ref($info) eq 'HASH') { $cdom = $info->{'cdom'}; $cnum = $info->{'cnum'}; @@ -962,6 +1543,7 @@ sub courseinfo_row { $counts = $info->{'counts'}; $autoenrollment = $info->{'autoenrollment'}; $showsyllabus = $info->{'showsyllabus'}; + $extsyllplain = $info->{'extsyllplain'}; $categories = $info->{'categories'}; } else { $output = ''.&mt('No information available for [_1].', @@ -989,46 +1571,64 @@ sub courseinfo_row { ''.$xlist_items.''. ''.$title.' '; if ($showsyllabus) { - $output .= ''.&mt('Syllabus').''; + my $usehttp = 0; + if (($ENV{'SERVER_PORT'} == 443) && ($extsyllplain)) { + $usehttp = 1; + } + $output .= ''.&mt('Syllabus').''; } else { $output .= ' '; } $output .= ''. ''.$ownerlast.''; - if ($knownuser) { + if (($knownuser) || ($canviewall && $details)) { if ($details) { - if ($env{'form.currcat_0'} eq 'communities::0') { - $output .= ''.$accessdates.''; - } else { - $output .= - ''.$accessdates.''. - ''.$counts.''. - ''.$autoenrollment.''; + $output .= + ''.$accessdates.''. + ''.$counts.''; + unless (($env{'form.currcat_0'} eq 'communities::0') || ($env{'form.currcat_0'} eq 'placement::0')) { + $output .= ''.$autoenrollment.''; } } else { $output .= "".&mt('Show more details').''; } } - my $selfenroll; - if ($info->{'selfenroll_types'}) { - my $showstart = &Apache::lonlocal::locallocaltime($info->{'selfenroll_start'}); - my $showend = &Apache::lonlocal::locallocaltime($info->{'selfenroll_end'}); - if (($info->{'selfenroll_end'} > 0) && ($info->{'selfenroll_end'} > $now)) { - if (($info->{'selfenroll_start'} > 0) && ($info->{'selfenroll_start'} > $now)) { - $output .= ''.&mt('Starts: [_1]',''.$showstart.'').'
'.&mt('Ends: [_1]',''.$showend.'').''; - } else { - $output .= ''.&mt('Enroll in course').''; - } - $selfenroll = 1; - } - } - if (!$selfenroll) { + my $selfenroll = &selfenroll_status($info,$course); + if ($selfenroll) { + $output .= ''.$selfenroll.''; + } else { $output .= ' '; } $$countref ++; return $output; } +sub selfenroll_status { + my ($info,$course) = @_; + my $now = time; + my $output; + if (ref($info) eq 'HASH') { + if ($info->{'selfenroll_types'}) { + my $showstart = &Apache::lonlocal::locallocaltime($info->{'selfenroll_start'}); + my $showend = &Apache::lonlocal::locallocaltime($info->{'selfenroll_end'}); + if (($info->{'selfenroll_end'} > 0) && ($info->{'selfenroll_end'} > $now)) { + if (($info->{'selfenroll_start'} > 0) && ($info->{'selfenroll_start'} > $now)) { + $output = &mt('Starts: [_1]',''.$showstart.'').'
'.&mt('Ends: [_1]',''.$showend.''); + } else { + $output = ''. + &mt('Enroll in course').'
'; + if ($info->{'selfenroll_end'} == 0) { + $output .= &mt('Available permanently'); + } elsif ($info->{'selfenroll_end'} > $now) { + $output .= &mt('Self-enrollment ends: [_1]',''.$showend.''); + } + } + } + } + } + return $output; +} + sub identify_sections { my ($seclist) = @_; my @secnums;