# The LearningOnline Network with CAPA
# Handler to display the classlist
#
# $Id: lonviewclasslist.pm,v 1.21 2023/11/05 19:59:54 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
###############################################################
##############################################################
package Apache::lonviewclasslist;
use strict;
use Apache::loncoursedata();
use Apache::loncommon();
use Apache::lonhtmlcommon();
use Apache::courseprefs();
use Apache::Constants qw(:common :http REDIRECT);
use Apache::lonlocal;
use Apache::lonnet;
###################################################################
###################################################################
=pod
=item &handler
The typical handler you see in all these modules. Takes $r, the
http request, as an argument.
=cut
###################################################################
###################################################################
sub handler {
my $r=shift;
if ($r->header_only) {
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
return OK;
}
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['register','forceedit','action',
'symb','todocs','only_body']);
if (! ($env{'request.course.fn'})) {
$env{'user.error.msg'}=
"/adm/viewclasslist:not in course role";
return HTTP_NOT_ACCEPTABLE;
}
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
#
my $start_page;
if ($env{'form.register'}) {
$start_page = &Apache::loncommon::start_page('Classlist',undef,
{'force_register' => $env{'form.register'}});
} else {
my $args = {};
if ($env{'form.only_body'}) {
$args->{'only_body'} = 1;
} else {
my $brcrum = [{'href' => 'adm/viewclasslist',
'text' => 'View Classlist'},];
$args->{'bread_crumbs'} = $brcrum;
}
$start_page = &Apache::loncommon::start_page('Classlist',undef,
$args);
}
$r->print(<<ENDHEADER);
$start_page
ENDHEADER
# Get classlist view settings
my %viewsettings = &retrieve_view_settings();
my $crstype = &Apache::loncommon::course_type();
if (($env{'form.forceedit'}) || ($env{'form.action'} eq 'setconfig')) {
if (&Apache::lonnet::allowed('opa',$env{'request.course.id'})) {
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my $rosterprefs = &roster_prefs($crstype);
my $allitems = {};
if ($env{'form.action'} eq 'setconfig') {
my %values=&Apache::lonnet::dump('environment',$cdom,$cnum);
if (keys(%values) > 0) {
my ($numchanged,%changes,%disallowed);
my $prefs = {
classlists => $rosterprefs,
};
$changes{'classlists'} = {};
&Apache::courseprefs::process_changes($cdom,$cnum,'classlists',\%values,
$rosterprefs,
$changes{'classlists'},
$allitems,\%disallowed,$crstype);
my $message;
if (keys(%{$changes{'classlists'}}) > 0) {
my $actions = ['classlists'];
$message =
&Apache::courseprefs::store_changes($cdom,$cnum,$actions,
$actions,$prefs,\%values,
\%changes,$crstype);
} else {
if ($crstype eq 'Community') {
$message = &mt('No changes made to community settings.');
} else {
$message = &mt('No changes made to course settings.');
}
}
$r->print(&Apache::loncommon::confirmwrapper($message));
} else {
$r->print('<div class="LC_info">'.
&mt('Unable to retrieve current settings.').'<br />'.
&mt('No changes saved.').
'</div>');
}
} else {
my $current = {};
my @settings = ('student_classlist_view','student_classlist_opt_in',
'student_classlist_portfiles');
foreach my $setting (@settings) {
$current->{$setting} = $env{"course.$env{'request.course.id'}.$setting"};
}
my ($output,$rowtotal) =
&Apache::courseprefs::print_config_box($r,$cdom,$cnum,'display',
'viewableroster',
$rosterprefs,$current,
$allitems,$crstype);
if ($output) {
$r->print('<form method="post" name="display" action="/adm/viewclasslist">'."\n".
'<input type="hidden" name="action" value="setconfig" />'."\n".
'<input type="hidden" name="register" value="'.$env{'form.register'}.'" />'."\n".
'<input type="hidden" name="forceedit" value="'.$env{'form.forceedit'}.'" />'."\n");
if ($env{'form.symb'}) {
$r->print('<input type="hidden" name="symb" value="'.$env{'form.symb'}.'" />'."\n");
}
if ($env{'form.symb'}) {
$r->print('<input type="hidden" name="todocs" value="'.$env{'form.todocs'}.'" />'."\n");
}
$r->print('<div class="LC_left_float">'.
$output.
'</div><br clear="all" />'.
'<input type="submit" value="'.&mt('Save').'" />'.
'</form>');
} else {
$r->print('<div class="LC_info">');
if ($crstype eq 'Community') {
$r->print(&mt('No member-viewable community roster settings available.'));
} else {
$r->print(&mt('No student-viewable course roster settings available.'));
}
$r->print('</div>');
}
}
} else {
$r->print('<div class="LC_info">');
if ($crstype eq 'Community') {
$r->print(&mt('You do not have rights to modify member-viewable community roster settings.'));
} else {
$r->print(&mt('You do not have rights to modify student-viewable course roster settings.'));
}
$r->print('</div>');
}
} else {
# Print classlist
if (keys(%viewsettings) > 0) {
$r->print(&html_classlist($r,$crstype,\%viewsettings));
} else {
$r->print('<div class="LC_info">');
if ($crstype eq 'Community') {
$r->print(&mt("Display of a member-viewable community roster is not currently enabled."));
} else {
$r->print(&mt("Display of a student-viewable course roster is not currently enabled."));
}
$r->print('</div>');
}
}
#
# Finish up
$r->print(&Apache::loncommon::end_page());
return OK;
}
sub retrieve_view_settings {
my %viewsettings;
if (exists($env{'request.course.id'})) {
my $cid = $env{'request.course.id'};
my $viewpermission = 'course.'.$cid.'.student_classlist_view';
my $student_opt_in = 'course.'.$cid.'.student_classlist_opt_in';
my $portfiles_link = 'course.'.$cid.'.student_classlist_portfiles';
if (exists($env{$viewpermission}) &&
$env{$viewpermission} =~ /^(all|section)$/) {
$viewsettings{'permission'} = $env{$viewpermission};
if ($viewsettings{'permission'} =~ /^section$/i) {
$viewsettings{'limit_to_section'} = 1;
} else {
$viewsettings{'limit_to_section'} = 0;
}
$viewsettings{'student_opt_in'} = $env{$student_opt_in};
$viewsettings{'portfiles_link'} = $env{$portfiles_link};
}
}
return %viewsettings;
}
sub roster_prefs {
my ($crstype) = @_;
my %lt;
if ($crstype eq 'Community') {
%lt = &Apache::lonlocal::texthash (
svrs => 'Member-viewable roster settings',
stuv => 'Member-viewable membership list options',
stul => 'Member agreement needed to be listed',
);
} else {
%lt = &Apache::lonlocal::texthash(
svrs => 'Student-viewable roster settings',
stuv => 'Student-viewable classlist options',
stul => 'Student agreement needed to be listed',
);
}
$lt{'incl'} = &mt('Include link to accessible portfolio files');
return
{ text => $lt{'svrs'},
header => [ {col1 => 'Setting',
col2 => $lt{'stuv'}}],
ordered => ['student_classlist_view',
'student_classlist_opt_in',
'student_classlist_portfiles'],
itemtext => {
student_classlist_view => $lt{'stuv'},
student_classlist_opt_in => $lt{'stul'},
student_classlist_portfiles => $lt{'incl'},
},
};
}
sub html_classlist {
my ($r,$crstype,$viewsettings) = @_;
my ($Str,$title,$secdisplay,$cid,$cdom,$cnum,$listtype,%publicroster);
my $fullroster = &Apache::loncoursedata::get_classlist();
my $classlist;
my $singular = 'student';
my $plural = 'students';
my $titleplural = 'Students';
my $heading = &mt('Student-viewable course roster');
if ($crstype eq 'Community') {
$singular = 'member';
$plural = 'members';
$titleplural = 'Members';
$heading = &mt('Member-viewable community roster');
}
if ($env{'form.action'} eq 'setenv') {
$Str .= &process_student_prefs($crstype);
}
$Str .= '<h2>'.$heading.'</h2>';
$cid = $env{'request.course.id'};
$cdom = $env{'course.'.$cid.'.domain'};
$cnum = $env{'course.'.$cid.'.num'};
if ($viewsettings->{'limit_to_section'}) {
if ($env{'request.course.sec'} eq '') {
$title = &mt($titleplural.' with no section');
$listtype = 'without a section';
} else {
$title = &mt($titleplural.' in section "[_1]"',
$env{'request.course.sec'});
$listtype = 'in the section';
$secdisplay = " ($env{'request.course.sec'}) ";
}
} else {
$title = &mt($titleplural.' in any section');
$listtype = 'in the course';
if ($crstype eq 'Community') {
$listtype = 'in the community';
}
}
if ($viewsettings->{'student_opt_in'}) {
if ($env{'request.role'} =~ /^st/) {
$Str .= &print_roster_form($crstype);
}
%publicroster = &Apache::lonnet::dump('publicroster',$cdom,$cnum);
}
$Str .= '<h3>'.$title.'</h3>';
my $fullcount = 0;
my $publiccount = 0;
my $displaycount = 0;
my $sectionidx = &Apache::loncoursedata::CL_SECTION();
my $statusidx = &Apache::loncoursedata::CL_STATUS();
foreach my $student (keys(%{$fullroster})) {
my $section = $fullroster->{$student}->[$sectionidx];
my $status = $fullroster->{$student}->[$statusidx];
next if (lc($status) ne 'active');
if ($viewsettings->{'limit_to_section'}) {
next if ($section ne $env{'request.course.sec'});
}
$fullcount ++;
if ($viewsettings->{'student_opt_in'}) {
if ($publicroster{$student}) {
$classlist->{$student} = $fullroster->{$student};
$publiccount ++;
}
} else {
$classlist->{$student} = $fullroster->{$student};
}
}
if ($viewsettings->{'student_opt_in'}) {
$displaycount = $publiccount;
if ($fullcount > $publiccount) {
if ($publiccount) {
$Str .= &mt('Only '.$plural.' who have opted to be listed in the roster ([_1] out of [_2] '.$plural.') are shown.',$publiccount,$fullcount).'<br />';
} else {
if ($fullcount == 1) {
$Str .= &mt('The single '.$singular.' '.$listtype.'[_1] has opted not to be listed in the roster.',$secdisplay);
} else {
$Str .= &mt('None of the [_1] '.$plural.' '.$listtype.'[_2] have opted to be listed in the roster.',$fullcount,$secdisplay);
}
return $Str;
}
} else {
if ($fullcount > 1) {
$Str .= &mt('All [_1] '.$plural.' '.$listtype.'[_2] have opted to be listed in the roster.',$fullcount,$secdisplay);
} elsif ($fullcount == 1) {
$Str .= &mt('The single '.$singular.' '.$listtype.'[_1] has opted to be listed in the roster.',$secdisplay);
}
}
} else {
$displaycount = $fullcount;
if ($fullcount > 1) {
$Str .= &mt('All [_1] '.$plural.' '.$listtype.'[_2] are listed in the roster.',$fullcount,$secdisplay);
} elsif ($fullcount == 1) {
$Str .= &mt('There is only a single '.$singular.' '.$listtype.'[_1]',$secdisplay);
}
}
undef($fullroster);
if (!$displaycount) {
$Str .= &mt('There are currently no '.$plural.' to display.');
return $Str;
}
# Set up a couple variables.
my $usernameidx = &Apache::loncoursedata::CL_SNAME();
my $domainidx = &Apache::loncoursedata::CL_SDOM();
my $fullnameidx = &Apache::loncoursedata::CL_FULLNAME();
# Sort the students
my $sortby = $fullnameidx;
my @Sorted_Students = sort {
lc($classlist->{$a}->[$sortby]) cmp lc($classlist->{$b}->[$sortby])
} (keys(%$classlist));
$Str .= '<br />'.&Apache::loncommon::start_data_table()."\n".
&Apache::loncommon::start_data_table_header_row()."\n".
'<th></th>'. # for the count
'<th>'.&mt('Name').'</th>'.
'<th>'.&mt('Username').'</th>';
if (! $viewsettings->{'limit_to_section'}) {
$Str .= '<th>'.&mt('Section').'</th>';
}
if ($viewsettings->{'portfiles_link'}) {
$Str .= '<th>'.&mt('Available Portfolio files').'</th>';
}
$Str .= &Apache::loncommon::end_data_table_header_row();
my $count ++;
foreach my $student (@Sorted_Students) {
my $username = $classlist->{$student}->[$usernameidx];
my $domain = $classlist->{$student}->[$domainidx];
my $fullname = $classlist->{$student}->[$fullnameidx];
if ($fullname =~ /^\s*$/) {
$fullname = &mt('Name not given');
}
my $section = $classlist->{$student}->[$sectionidx];
if ($section eq '') {
$section = &mt('none');
}
$Str .= &Apache::loncommon::start_data_table_row()."\n".
'<td>'.$count++.'</td>'.
'<td>'.&Apache::loncommon::aboutmewrapper($fullname,
$username,
$domain).'</td>'.
'<td>'.(' 'x2).
&Apache::loncommon::messagewrapper
('<img src="/adm/lonIcons/mailto.gif" border="0" /> '.
$username.':'.$domain,$username,$domain).'</td>';
if (! $viewsettings->{'limit_to_section'}) {
$Str .= '<td>'.$section.'</td>';
}
if ($viewsettings->{'portfiles_link'}) {
my $filecounts = &Apache::lonaboutme::portfolio_files($r,'showlink',undef,undef,$domain,$username,$fullname);
my $link;
if (ref($filecounts) eq 'HASH') {
$link = &mt('[quant,_1,file,files,No files]',$filecounts->{'both'});
if ($filecounts->{'both'} > 0) {
$link = '<a href="/adm/'.$domain.'/'.$username.'/aboutme/portfolio?classlist">'.$link.'</a>';
}
} else {
$link = '<span class="LC_error">'.&mt("Error retrieving file information.").'</span>';
}
$Str .= '<td>'.$link.'</td>';
}
$Str .= &Apache::loncommon::end_data_table_row()."\n";
}
$Str .= &Apache::loncommon::end_data_table();
return $Str;
}
sub print_roster_form {
my ($crstype) = @_;
my $cid = $env{'request.course.id'};
my $showinroster = $env{'environment.internal.'.$cid.'.showinroster'};
my ($showoff,$showon);
if ($showinroster) {
$showon = ' checked="checked" ';
$showoff = ' ';
} else {
$showoff = ' checked="checked" ';
$showon = ' ';
}
my $singular = 'student';
if ($crstype eq 'Community') {
$singular = 'member';
}
my $output =
'<div class="LC_left_float">'
.'<fieldset><legend>'.&mt('Your roster setting').'</legend>';
if ($showinroster) {
$output .= &mt("You are currently listed in the $singular-viewable roster.");
} else {
$output .= &mt("You are currently [_1]not[_2] listed in the $singular-viewable roster.",'<b>','</b>');
}
$output .= '<br />'.&mt('Include yourself in the roster?').' '.
'<form name="studentparm" method="post" action="">'.
'<span class="LC_nobreak"><label><input type="radio" name="showinroster" value="1"'.$showon.'/>'.&mt('Yes').'</label> <label>'.
'<input type="radio" name="showinroster" value="0"'.$showoff.'/>'.&mt('No').
'</label></span><br /><br />'.
'<input type="hidden" name="action" value="setenv" />'.
'<input type="submit" name="studentsubmit" value="'.&mt('Save').'" />'.
'</form></fieldset></div><br clear="all" />';
return $output;
}
sub process_student_prefs {
my ($crstype) = @_;
my $cid = $env{'request.course.id'};
my $cdom = $env{'course.'.$cid.'.domain'};
my $cnum = $env{'course.'.$cid.'.num'};
my $uname = $env{'user.name'};
my $udom = $env{'user.domain'};
my $student = $uname.':'.$udom;
my %pubroster = &Apache::lonnet::get('publicroster',[$student],$cdom,$cnum);
my $visibility = &mt('off');
my $showinroster = $env{'form.showinroster'};
if ($showinroster) {
$visibility = &mt('on');
}
my $sturoster = 0;
if ($pubroster{$student}) {
$sturoster = 1;
}
my $singular = 'student';
if ($crstype eq 'Community') {
$singular = 'member';
}
my $output;
if ($sturoster ne $showinroster) {
my %changeHash = (
'environment.internal.'.$cid.'.showinroster' => $showinroster,
);
my $putresult = &Apache::lonnet::put('environment',
\%changeHash,$udom,$uname);
if ($putresult eq 'ok') {
&Apache::lonnet::appenv(\%changeHash);
my $result = &Apache::lonnet::put('publicroster',{$student => $showinroster,},$cdom,$cnum);
if ($result eq 'ok') {
$output .=
&Apache::lonhtmlcommon::confirm_success(
&mt("Display of your name in the $singular-viewable roster set to [_1].",'<b>'.$visibility.'</b>'));
} else {
$output .=
&Apache::lonhtmlcommon::confirm_success(
&mt('Error occurred saving display setting.'),1);
}
} else {
$output .=
&Apache::lonhtmlcommon::confirm_success(
&mt('Error occurred saving display setting.'),1);
}
} else {
$output .=
&Apache::lonhtmlcommon::confirm_success(
&mt("Display of your name in the $singular-viewable roster unchanged (set to [_1]).",'<b>'.$visibility.'</b>'));
}
$output = &Apache::loncommon::confirmwrapper($output);
return $output;
}
###################################################################
###################################################################
1;
__END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>