--- loncom/interface/loncoursegroups.pm 2006/07/21 02:51:31 1.57 +++ loncom/interface/loncoursegroups.pm 2008/12/16 23:45:29 1.86 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: loncoursegroups.pm,v 1.57 2006/07/21 02:51:31 raeburn Exp $ +# $Id: loncoursegroups.pm,v 1.86 2008/12/16 23:45:29 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -29,13 +29,14 @@ package Apache::loncoursegroups; use strict; use Apache::lonnet; -use Apache::loncommon; -use Apache::lonhtmlcommon; +use Apache::loncommon(); +use Apache::lonhtmlcommon(); use Apache::lonlocal; -use Apache::lonnavmaps; -use Apache::longroup; -use Apache::portfolio; +use Apache::lonnavmaps(); +use Apache::longroup(); +use Apache::portfolio(); use Apache::Constants qw(:common :http); +use LONCAPA::map(); use lib '/home/httpd/lib/perl/'; use LONCAPA; @@ -75,10 +76,10 @@ sub handler { my %functions = ( email => 'E-mail', - discussion => 'Discussion boards', + discussion => 'Discussion Boards', chat => 'Chat', - files => 'File repository', - roster => 'Membership roster', + files => 'File Repository', + roster => 'Membership Roster', homepage => $ucgpterm.' home page', ); @@ -91,12 +92,13 @@ sub handler { my $action = $env{'form.action'}; my $state = $env{'form.state'}; - if ((!defined($action)) || ($action eq 'view') || ($action eq 'modify')) { + if ((!defined($action)) || ($action eq 'view') || ($action eq 'modify') || ($action eq 'delete') || ($action eq 'reenable')) { if (!defined($state)) { $state = 'view'; } } - if ($action eq 'create' || $action eq 'modify' || $action eq 'view') { + if ($action eq 'create' || $action eq 'modify' || $action eq 'view' || + $action eq 'delete' || $action eq 'reenable') { if ($view_permission || $manage_permission) { if ($state eq 'view') { &print_main_menu($r,$cdom,$cnum,\%functions,\%idx, @@ -109,8 +111,10 @@ sub handler { $crstype); } } else { - $r->print(&mt('You do not have [_1] administration '. - 'privileges in this [_2]',$gpterm,lc($crstype))); + $r->print('
' + .&mt('You do not have '.$gpterm.' administration ' + .'privileges in this '.lc($crstype).'.') + .'
'); } } else { &print_main_menu($r,$cdom,$cnum,\%functions,\%idx,$view_permission, @@ -127,17 +131,30 @@ sub print_main_menu { function changeSort(caller) { document.$state.sortby.value = caller; document.$state.submit(); +} +function openGroupRoster(group,status) { + var url = '/adm/grouproster?'; + url += 'group='+group+'&status='+status+'&ref=popup'; + var title = 'Group Membership'; + var options = 'scrollbars=1,resizable=1,menubar=0'; + options += ',width=700,height=600'; + rosterbrowser = open(url,title,options,'1'); + rosterbrowser.focus(); }\n|; $r->print(&header('Groups',$jscript,$action,$state)); - if ($env{'form.refpage'} eq 'enrl') { + if ($env{'form.refpage'} eq 'cusr') { &Apache::lonhtmlcommon::add_breadcrumb - ({href=>"/adm/dropadd", - text=>"Enrollment Manager"}); + ({href=>"/adm/createuser", + text=>"User Management"}); } &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/coursegroups", text=>"Groups"}); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Groups')); + my $helpitem; + if ($manage_permission) { + $helpitem = 'Creating_Groups'; + } + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Groups',$helpitem)); &display_groups($r,$cdom,$cnum,$functions,$idx,$view_permission, $manage_permission,$action,$state,$gpterm,$ucgpterm, $crstype); @@ -155,12 +172,15 @@ sub display_groups { $env{'form.refpage'}.'&state=pick_task&groupname=', view => ' ''.$lt{'redg'}.''; + } + } + } + my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum,undef, + $status); + if (%curr_groups) { if ($manage_permission) { - if (!exists($env{'form.refpage'})) { - $r->print('
'.$lt{'crng'}.''); + if ($action ne 'reenable') { + $r->print('
'.$lt{'crng'}.''); + } + if ($reenable_link) { + $r->print($reenable_link); } } $r->print('

'); @@ -218,13 +256,13 @@ END my $members_result = &group_members($cdom,$cnum,$group, \%grp_info); my $port_path = '/userfiles/groups/'.$group.'/portfolio'; - my $port_dir = &Apache::loncommon::propath($cdom,$cnum).$port_path; my $totaldirs = 0; my $totalfiles = 0; - &group_files($group,$port_dir,\$totalfiles,\$totaldirs); + &group_files($group,$port_path,\$totalfiles,\$totaldirs); $grp_info{$group}{'totalfiles'} = $totalfiles; $grp_info{$group}{'totaldirs'} = $totaldirs; - my $diskuse = &Apache::lonnet::diskusage($cdom,$cnum,$port_dir); + my $getpropath = 1; + my $diskuse = &Apache::lonnet::diskusage($cdom,$cnum,$port_path, $getpropath); if ($grp_info{$group}{'quota'} > 0) { my $pct_use = 0.1 * $diskuse/$grp_info{$group}{'quota'}; $grp_info{$group}{'diskuse'} = sprintf("%.0f",$pct_use); @@ -282,7 +320,8 @@ END $functionality = &mt('None available'); } my $link = $actionlinks{$action}; - if ($action eq 'modify' || $action eq 'delete') { + if ($action eq 'modify' || $action eq 'delete' || + $action eq 'reenable') { $link .= $group; } else { $link .= $group.'/smppg?ref=grouplist'; @@ -292,10 +331,11 @@ END } $link .= '">'.$lt{$action}.''; if ($action eq 'view') { - if (($manage_permission) && - ($env{'form.refpage'} ne 'enrl')) { + if ($manage_permission) { $link .= '  '.$actionlinks{'modify'}. - $group.'">'.$lt{'modify'}.''; + $group.'">'.$lt{'modify'}.''. + '  '.$actionlinks{'delete'}. + $group.'">'.$lt{'delete'}.''; } } $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense'). @@ -308,7 +348,10 @@ END ''.$functionality.''. ''.$quota.''. ''.$totalmembers.''. - ''.&mt('Files: ').$totalfiles.'
'.&mt('Folders: ').$totaldirs.''. + ''. + '
'.&mt('Files: [_1]',$totalfiles).'
'. + '
'.&mt('Folders: [_1]',$totaldirs).'
'. + ''. ''.$boards.''. ''.$diskuse.''. &Apache::loncommon::end_data_table_row()); @@ -327,12 +370,14 @@ END } else { $r->print($lt{'nogr'}); if ($manage_permission) { - if (!exists($env{'form.refpage'})) { - $r->print('

'.$lt{'crng'}.''); + $r->print('

'.$lt{'crng'}.''); + if ($action ne 'reenable') { + if ($reenable_link) { + $r->print($reenable_link); + } } } else { $r->print('

'.$lt{'alth'}); - } } } else { @@ -350,9 +395,7 @@ END } } } else { - $r->print(&mt('You are not currently a member of any '. - 'active [_1]s in this [_2]',$gpterm, - lc($crstype))); + $r->print(&mt('You are not currently a member of any active '.$gpterm.'s in this '.lc($crstype).'.')); } } return; @@ -366,7 +409,6 @@ sub group_administration { my @types = (); my @roles = (); my @sections = (); - my @buildsections = (); my %users = (); my %userdata = (); my @members = (); @@ -420,7 +462,7 @@ sub group_administration { $state = 'pick_task'; } } else { - %stored = &retrieve_settings($cdom,$cnum,$groupname); + %stored = &retrieve_settings($cdom,$cnum,$groupname,$action); if (ref($stored{'types'}) eq 'ARRAY') { @types = @{$stored{'types'}}; } @@ -526,16 +568,11 @@ sub group_administration { } if (defined($env{'form.sectionpick'})) { @sections=&Apache::loncommon::get_env_multiple('form.sectionpick'); - if (grep/^all$/,@sections) { - @buildsections = sort {$a cmp $b} keys(%sectioncount); - } else { - @buildsections = @sections; - } } } if (($state eq 'pick_members') || ($state eq 'pick_privs') || ($state eq 'change_privs')) { - &build_members_list($cdom,$cnum,\@types,\@roles,\@buildsections,\%users, + &build_members_list($cdom,$cnum,\@types,\@roles,\@sections,\%users, \%userdata); } if ($state eq 'pick_members') { @@ -798,6 +835,8 @@ function changeSort(caller) { my %branchstates = (); @{$states{'create'}} = ('pick_name','pick_members','pick_privs','result'); @{$states{'modify'}} = ('pick_task'); + @{$states{'delete'}} = ('verify','result'); + @{$states{'reenable'}} = ('verify','result'); @{$branchstates{'noprivs'}} = ('result'); @{$branchstates{'settings'}} = ('change_settings','chgresult'); @{$branchstates{'members'}} = ('change_members','change_privs','memresult'); @@ -808,7 +847,7 @@ function changeSort(caller) { push (@{$states{$action}},@{$branchstates{$env{'form.branch'}}}); } - if (($action eq 'create') || ($action eq 'modify')) { + if (($action eq 'create') || ($action eq 'modify') || ($action eq 'delete') || ($action eq 'reenable')) { my $done = 0; my $i=0; while ($i<@{$states{$action}} && !$done) { @@ -824,14 +863,14 @@ function changeSort(caller) { $r->print(&header("Groups Manager", $jscript,$action,$state,$page,$loaditems)); - if ($env{'form.refpage'} eq 'enrl') { + if ($env{'form.refpage'} eq 'cusr') { &Apache::lonhtmlcommon::add_breadcrumb - ({href=>"/adm/dropadd", - text=>"Enrollment Manager", + ({href=>"/adm/createuser", + text=>"User Management", faq=>9,bug=>'Instructor Interface',}); - if ($action eq 'modify') { + if ($action eq 'modify' || $action eq 'delete') { &Apache::lonhtmlcommon::add_breadcrumb - ({href=>"/adm/coursegroups?refpage=enrl&action=modify", + ({href=>"/adm/coursegroups?refpage=cusr&action=$action", text=>"Groups", faq=>9,bug=>'Instructor Interface',}); } @@ -867,6 +906,14 @@ function changeSort(caller) { memresult => 'Modifications Complete', addresult => 'Additions Complete', ); + %{$trail{'delete'}} = &Apache::lonlocal::texthash( + verify => 'Verify deletion', + result => 'Deletion Complete' + ); + %{$trail{'reenable'}} = &Apache::lonlocal::texthash( + verify => 'Verify Re-enable', + result => 'Re-enabled' + ); my %navbuttons = &Apache::lonlocal::texthash( gtns => 'Go to next step', gtps => 'Go to previous step', @@ -875,14 +922,14 @@ function changeSort(caller) { gtpp => 'Go to previous page', adme => 'Add members', ); - if ((($action eq 'create') || ($action eq 'modify')) && + if ((($action eq 'create') || ($action eq 'modify') || ($action eq 'delete') || ($action eq 'reenable')) && ($manage_permission)) { for (my $i=0; $i<@{$states{$action}}; $i++) { if ($state eq $states{$action}[$i]) { &Apache::lonhtmlcommon::add_breadcrumb( {text=>"$trail{$action}{$state}"}); $r->print(&Apache::lonhtmlcommon::breadcrumbs - ("Groups Manager")); + ("Groups Manager","Creating_Groups")); &display_control($r,$cdom,$cnum,$action,$state,$page, \%sectioncount,$groupname,$description,$functions, \@tools,$toolprivs,$fixedprivs,$startdate,$enddate, @@ -893,16 +940,18 @@ function changeSort(caller) { $crstype); last; } else { - if (($state eq 'result') && ($i > 0)) { - &Apache::lonhtmlcommon::add_breadcrumb( + if (($action eq 'create') || ($action eq 'modify')) { + if (($state eq 'result') && ($i > 0)) { + &Apache::lonhtmlcommon::add_breadcrumb( {href=>"javascript:backPage(document.$state,'$states{$action}[0]')", text=>"$trail{$action}{$states{$action}[$i]}"}); - } else { - &Apache::lonhtmlcommon::add_breadcrumb( + } else { + &Apache::lonhtmlcommon::add_breadcrumb( {href=>"javascript:backPage(document.$state,'$states{$action}[$i]')", text=>"$trail{$action}{$states{$action}[$i]}"}); + } } - } + } } } elsif (($action eq 'view') && ($view_permission)) { &Apache::lonhtmlcommon::add_breadcrumb( @@ -912,15 +961,22 @@ function changeSort(caller) { &display_groups($r,$cdom,$cnum,$functions,$idx,$view_permission, $manage_permission,$action,$state,$gpterm,$ucgpterm, $crstype); - } $r->print(&footer()); return; } sub retrieve_settings { - my ($cdom,$cnum,$groupname) = @_; - my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum,$groupname); + my ($cdom,$cnum,$groupname,$action) = @_; + my %curr_groups; + my $namespace; + if ($action eq 'reenable') { + $namespace = 'deleted_groups'; + } else { + $namespace = 'coursegroups'; + } + %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum,$groupname, + $namespace); return if (!%curr_groups); @@ -965,6 +1021,7 @@ sub retrieve_settings { foreach my $role (sort(keys(%{$groupinfo{'autosec'}}))) { if (ref($groupinfo{'autosec'}{$role}) eq 'ARRAY') { foreach my $section (@{$groupinfo{'autosec'}{$role}}) { + push (@{$stored{'sec_'.$role}},$section); } if (@{$groupinfo{'autosec'}{$role}} > 0) { @@ -1026,7 +1083,7 @@ sub display_control { $userdata,$granularity,$quota,$specificity, $idx,$states,$navbuttons,$gpterm,$ucgpterm); } elsif ($state eq 'add_members') { - &add_members_form($r,$action,$state,$page,$startdate, + &add_members_form($r,$cdom,$cnum,$action,$state,$page,$startdate, $enddate,$groupname,$description,$granularity, $quota,$sectioncount,$tools,$functions,$stored, $states,$navbuttons,$gpterm,$ucgpterm); @@ -1058,7 +1115,320 @@ sub display_control { $sections,$states,$navbuttons,$memchg, $sectioncount,$stored,$gpterm,$ucgpterm,$crstype); } + } elsif ($action eq 'delete') { + my %stored = &retrieve_settings($cdom,$cnum,$groupname,$action); + if ($state eq 'verify') { + &verify_delete($r,$groupname,$state,$action,$page,$states, + \%stored); + } elsif ($state eq 'result') { + &delete_group($r,$cdom,$cnum,$groupname); + } + } elsif ($action eq 'reenable') { + my %stored = &retrieve_settings($cdom,$cnum,$groupname,$action); + if ($state eq 'verify') { + &verify_reenable($r,$groupname,$state,$action,$page,$states, + \%stored); + } elsif ($state eq 'result') { + &reenable_group($r,$cdom,$cnum,$groupname); + } + } +} + +sub verify_delete { + my ($r,$groupname,$formname,$action,$page,$states,$stored) = @_; + $r->print(&Apache::lonhtmlcommon::echo_form_input([])); + $r->print(&mt('You have requested deletion of the group [_1].' + ,''.$stored->{'description'}.''). + '

'.&mt('When a group is deleted the following occurs:').''.&mt('Although a deleted group is no longer accessible, the group name used for the group will be reserved, and will not be available for assignment to a new group in the same course in the future.')); + my $prevtext = &mt('Go back'); + my $nexttext = &mt('Delete group'); + my $prev; + if ($env{'form.refpage'} eq 'cusr') { + $prev = 'view'; + } + &display_navbuttons($r,$formname,$prev,$prevtext, + $$states{$action}[$page+1],$nexttext); + return; +} + +sub delete_group { + my ($r,$cdom,$cnum,$groupname) = @_; + my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum, + $groupname); + my $now = time; + my $num_users = 0; + my $num_fail = 0; + my $num_ok = 0; + my @deleted; + my @undeleted; + my %usersettings; + my $context = 'deletegroup'; + foreach my $key (sort(keys(%membership))) { + if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) { + my $user = $1; + my($end,$start,$userprivs) = split(/:/,$membership{$key},3); + if ($start != -1) { + $num_users ++; + $usersettings{$groupname.':'.$user} = $now.':-1:'.$userprivs; + if (&Apache::lonnet::modify_group_roles($cdom,$cnum, + $groupname,$user, + $now,'-1',$userprivs, + '',$context) + eq 'ok') { + $num_ok ++; + push(@deleted,$user); + } else { + push(@undeleted,$user); + $num_fail ++; + } + } + } + } + if ($num_ok > 0) { + my $roster_result = + &Apache::lonnet::modify_coursegroup_membership($cdom,$cnum, + \%usersettings); + } + if ($num_fail > 0) { + $r->print('
' + .&mt('Group deletion failed because deletion of [_1] out of [_2] members failed.' + ,$num_fail,$num_users) + .'
'); + + } else { + my ($result,$message) = + &Apache::lonnet::toggle_coursegroup_status($cdom,$cnum, + $groupname,'delete'); + if ($result eq 'ok') { + my $outcome = &modify_folders($cdom,$cnum,$groupname); + if ($outcome eq '') { + $r->print('
' + .&mt('Group successfully deleted.') + .'
'); + } else { + $r->print('
' + .&mt("Although the group was deleted, an error occurred when removing" + ." the group's folder from the 'Course Groups' folder: [_1]",$outcome) + .'
'); + } + } else { + $r->print('
' + .&mt('Group deletion failed.') + .'
'); + } + } + return; +} + +sub reenable_folder { + my ($cdom,$cnum,$groupname,$description) = @_; + my $outcome; + my $crspath = '/uploaded/'.$cdom.'/'.$cnum.'/'; + my $allgrpsmap = $crspath.'group_allfolders.sequence'; + my $foldertitle = &mt('Course Folder -[_1]',$description); + my $mapurl = $crspath.'group_folder_'. + $groupname.'.sequence'; + my ($errtext,$fatal)=&LONCAPA::map::mapread($allgrpsmap); + if ($fatal) { + $outcome='
' + .&mt('An error occurred when reading contents of parent folder to group:') + ."
($allgrpsmap): $errtext" + .'
'; + } else { + my $idx=&LONCAPA::map::getresidx($mapurl); + $LONCAPA::map::resources[$idx] = $foldertitle.':'.$mapurl. + ':false:normal:res'; + $LONCAPA::map::order[1+$#LONCAPA::map::order]=$idx; + my ($outtext,$errtext) = &LONCAPA::map::storemap($allgrpsmap,1); + if ($errtext) { + $outcome='
' + .&mt('An error occurred when saving updated parent folder to group:' + ,"
$allgrpsmap - $errtext") + .'
'; + } else { + my ($furl,$ferr) = + &Apache::lonuserstate::readmap($cdom.'/'.$cnum); + } + } + return $outcome; +} + +sub modify_folders { + my ($cdom,$cnum,$groupname) = @_; + my ($outcome,$groupmap,$groupmapres,$map,$id,$src); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (!defined($navmap)) { + $outcome = '
'. + &mt('Error reading course contents.').' '. + &mt('You need to re-initialize the course.'). + '
'; + return $outcome; + } + $groupmap = '/uploaded/'.$cdom.'/'.$cnum.'/'.'group_folder_'. + $groupname.'.sequence'; + $groupmapres = $navmap->getResourceByUrl($groupmap); + if ($groupmapres) { + ($map,$id,$src)=&Apache::lonnet::decode_symb($groupmapres->symb()); + } + undef($navmap); + if ($map) { + $map = '/'.$map; + my ($errtext,$fatal) = &LONCAPA::map::mapread($map); + if ($fatal) { + $outcome='
' + .&mt('An error occurred when reading contents of parent folder to group:') + ."
($map): $errtext" + .'
'; + } else { + my $idx = 0; + my $grpidx; + foreach my $item (@LONCAPA::map::order) { + my ($name,$url)=split(/\:/,$LONCAPA::map::resources[$item]); + $url=&LONCAPA::map::qtescape($url); + if ($url eq $groupmap) { + $grpidx = $idx; + last; + } else { + $idx++; + } + } + + if ($grpidx ne '') { + &LONCAPA::map::makezombie($LONCAPA::map::order[$grpidx]); + for (my $i=$grpidx;$i<$#LONCAPA::map::order;$i++) { + $LONCAPA::map::order[$i] = $LONCAPA::map::order[$i+1]; + } + $#LONCAPA::map::order--; + my ($outtext,$errtext) = &LONCAPA::map::storemap($map,1); + if ($errtext) { + $outcome='
' + .&mt('An error occurred when saving updated parent folder to group:') + ."
$map - $errtext" + .'
'; + } else { + my ($furl,$ferr) = + &Apache::lonuserstate::readmap($cdom.'/'.$cnum); + } + } + } + } + return $outcome; +} + +sub verify_reenable { + my ($r,$groupname,$formname,$action,$page,$states,$stored) = @_; + $r->print(&Apache::lonhtmlcommon::echo_form_input([])); + $r->print(&mt('You have requested enabling the previously deleted group [_1].' + ,''.$stored->{'description'}.''). + '

'.&mt('When a deleted group is re-enabled the following occurs:').''); + my $prevtext = &mt('Go back'); + my $nexttext = &mt('Reenable group'); + my $prev; + if ($env{'form.refpage'} eq 'cusr') { + $prev = 'view'; + } + &display_navbuttons($r,$formname,$prev,$prevtext, + $$states{$action}[$page+1],$nexttext); + return; +} + +sub reenable_group { + my ($r,$cdom,$cnum,$groupname) = @_; + my %groups = + &Apache::longroup::coursegroups($cdom,$cnum,$groupname, + 'deleted_groups'); + if (keys(%groups) == 0) { + $r->print(&mt('The group [_1] was not re-enabled, because it is not a deleted group.[_2]Perhaps it has already been re-enabled?',''.$groupname.''),'
'); + return; + } + my %groupinfo = + &Apache::longroup::get_group_settings($groups{$groupname}); + my $defstart = $groupinfo{'startdate'}; + my $defend = $groupinfo{'enddate'}; + my $showstart = &Apache::lonlocal::locallocaltime($defstart); + my $showend; + if ($defend == 0) { + $showend = &mt('No end date set'); + } else { + $showend = &Apache::lonlocal::locallocaltime($defend); + } + my $description = &unescape($groupinfo{'description'}); + my $num_users = 0; + my $num_ok = 0; + my $num_fail = 0; + my $context = 'reenablegroup'; + my (%usersettings,@enabled,@unenabled); + my ($result,$message) = + &Apache::lonnet::toggle_coursegroup_status($cdom,$cnum,$groupname, + 'reenable'); + if ($result eq 'ok') { + my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum, + $groupname); + foreach my $key (sort(keys(%membership))) { + if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) { + my $user = $1; + my($end,$start,$userprivs) = split(/:/,$membership{$key},3); + if (($start == -1) && ($end == $groupinfo{'modified'})) { + $num_users ++; + $usersettings{$groupname.':'.$user} = $defend.':'. + $defstart.':'. + $userprivs; + if (&Apache::lonnet::modify_group_roles($cdom,$cnum, + $groupname,$user, + $defend,$defstart, + $userprivs,'', +$context) eq 'ok') { + $num_ok ++; + push(@enabled,$user); + } else { + push(@unenabled,$user); + $num_fail ++; + } + } + } + } + if ($num_users > 0) { + if ($num_ok > 0) { + my $roster_result = + &Apache::lonnet::modify_coursegroup_membership($cdom,$cnum, + \%usersettings); + if ($roster_result eq 'ok') { + $r->print('
' + .&mt('Membership reinstated for [quant,_1,user], each with start and end dates for group access set to defaults: [_2] and [_3]',$num_ok,$showstart,$showend) + .'
'); + } + } else { + $r->print('
' + .&mt('A problem occurred when trying to reinstate [_1] of the [_2] members of the pre-existing group.',$num_fail,$num_users) + .'
'); + } + } else { + $r->print('
' + .&mt('There were no group members to reinstate, as none were removed when the group was deleted.') + .'
'); + } + my $outcome = &reenable_folder($cdom,$cnum,$groupname,$description); + if ($outcome eq '') { + $r->print('
' + .&mt('Group successfully re-enabled.') + .'
'); + } else { + $r->print('
' + .&mt("Although the group was re-enabled, an error occurred when adding the group's folder to the 'Course Groups' folder: [_1]",$outcome) + .'
'); + } + } else { + $r->print('
' + .&mt('Re-enabling group failed.') + .'
'); } + return; } sub header { @@ -1128,16 +1498,16 @@ sub build_members_list { } sub group_files { - my ($group,$currdir,$numfiles,$numdirs) = @_; + my ($group,$portpath,$numfiles,$numdirs) = @_; my $dirptr=16384; - my @dir_list=&Apache::portfolio::get_dir_list($currdir,$group); + my @dir_list=&Apache::portfolio::get_dir_list($portpath,undef,$group); foreach my $line (@dir_list) { my ($filename,$dom,undef,$testdir,undef,undef,undef,undef,$size,undef,$mtime,undef,undef,undef,$obs,undef)=split(/\&/,$line,16); if (($filename !~ /^\.\.?$/) && ($filename !~ /\.meta$/ ) && ($filename !~ /(.*)\.(\d+)\.([^\.]*)$/) && ($filename ne 'no_such_dir')) { if ($dirptr&$testdir) { - $currdir .= '/'.$filename; + $portpath .= '/'.$filename; $$numdirs ++; - &group_files($numfiles,$numdirs) + &group_files($group,$portpath,$numfiles,$numdirs) } else { $$numfiles ++; } @@ -1150,39 +1520,54 @@ sub group_members { my ($cdom,$cnum,$group,$group_info) = @_; my %memberhash = &Apache::lonnet::get_group_membership($cdom,$cnum,$group); my $now = time; - my ($tmp)=keys(%memberhash); - if ($tmp=~/^error:/) { - $$group_info{'totalmembers'} = 'Unknown - an error occurred'; - return $tmp; - } + my %lt = &Apache::lonlocal::texthash ( + active => 'active', + previous => 'previous', + future => 'future', + ); + my %membercounts = ( + active => 0, + previous => 0, + future => 0, + ); my $totalmembers = 0; - my $active = 0; - my $previous = 0; - my $future = 0; foreach my $member (keys %memberhash) { $totalmembers ++; my ($end,$start) = split(/:/,$memberhash{$member}); unless ($start == -1) { if (($end!=0) && ($end<$now)) { - $previous ++; + $membercounts{previous} ++; } elsif (($start!=0) && ($start>$now)) { - $future ++; + $membercounts{future} ++; } else { - $active ++; + $membercounts{active} ++; } } } if ($totalmembers == 0) { $$group_info{$group}{'totalmembers'} = 'None'; } else { - $$group_info{$group}{'totalmembers'} = ''.$active. - ' - active
'.$previous. - ' - previous
'.$future. - ' - future'; + foreach my $type ('active','previous','future') { + $$group_info{$group}{'totalmembers'} .= + &open_list_window($group,$type,$membercounts{$type},$lt{$type}); + } } return 'ok'; } +sub open_list_window { + my ($group,$status,$count,$text) = @_; + my $entry; + if ($count > 0) { + $entry = ''.$text.' - '.$count. + '
'; + } else { + $entry = ''.$text.' - '.$count.'
'; + } + return $entry; +} + sub general_settings_form { my ($r,$cdom,$cnum,$action,$formname,$page,$functions,$tools, @@ -1193,8 +1578,8 @@ sub general_settings_form { $gpterm,$ucgpterm,$crstype); &access_date_settings($r,$action,$formname,$stored,2,$gpterm,$ucgpterm); if ($action eq 'create') { - &membership_options($r,$action,$formname,$sectioncount,3,$gpterm, - $ucgpterm); + &membership_options($r,$cdom,$cnum,$action,$formname,$sectioncount,3, + $gpterm,$ucgpterm); $nexttext = $$navbuttons{'gtns'}; } else { my @available = (); @@ -1206,7 +1591,7 @@ sub general_settings_form { $gpterm,$ucgpterm); &mapping_options($r,$action,$formname,$page,$sectioncount, $states,$stored,$navbuttons,4,5, - $gpterm,$ucgpterm,$crstype); + $gpterm,$ucgpterm,$crstype,$cdom,$cnum); $nexttext = $$navbuttons{'mose'}; } $prevtext = $$navbuttons{'gtpp'}; @@ -1229,8 +1614,7 @@ sub groupsettings_options { 'for different group members?', ); my ($crsquota,$freespace,$maxposs) = &get_quota_constraints($action,$stored); - &topic_bar($r,$image,$lt{'gnde'}); - $r->print(' + $r->print(&Apache::lonhtmlcommon::topic_bar($image,$lt{'gnde'}).' @@ -1268,7 +1652,7 @@ END $$functions{$allfunctions[$i]}.''); } - $r->print(''); for (my $j=$halfnum; $j<@allfunctions; $j++) { @@ -1282,7 +1666,7 @@ END } $r->print(' @@ -1290,8 +1674,8 @@ END @@ -1299,23 +1683,25 @@ END @@ -1342,7 +1728,7 @@ sub get_quota_constraints { } sub membership_options { - my ($r,$action,$state,$sectioncount,$image,$gpterm,$ucgpterm) = @_; + my ($r,$cdom,$cnum,$action,$state,$sectioncount,$image,$gpterm,$ucgpterm)=@_; my $crstype = &Apache::loncommon::course_type(); my %lt = &Apache::lonlocal::texthash( 'pipa' => 'Build a list of users for selection of group members', @@ -1364,13 +1750,11 @@ sub membership_options { future => &mt('Will have future access'), ); - #FIXME need to plumb around for the various cr roles defined by the user - my @roles = ('st','cc','in','ta','ep'); + my @roles = ('st','cc','in','ta','ep','cr'); my @sections = keys(%{$sectioncount}); - &topic_bar($r,$image,$lt{'pipa'}); - $r->print(' + $r->print(&Apache::lonhtmlcommon::topic_bar($image,$lt{'pipa'}).' '.$lt{'gmem'}.'
'.$lt{'picr'}); if ($action eq 'create') { $r->print($lt{'meof'}.'
'.$lt{'ifno'}.'
'.$lt{'asub'}); @@ -1388,7 +1772,7 @@ sub membership_options { - - + + @@ -1648,9 +2036,9 @@ sub pick_new_members { 'nnew' => "There are no users to add as new members, as all users". " matching the specified type(s), role(s), and ". "section(s) are already affiliated with this group.", - 'yoma' => 'You may need to use the '."'".'modify existing, past or '. - 'future members'."'".' page if you need to re-enable '. - 'or activate access for previous or future members.', + 'yoma' => "You may need to use the 'modify existing, past or ". + "future members' page if you need to re-enable ". + "or activate access for previous or future members.", ); my %members; my $totalusers = 0; @@ -1674,7 +2062,7 @@ sub pick_new_members { $r->print(&check_uncheck_tools($r,$available)); } } - &topic_bar($r,$img,$lt{'gpme'}); + $r->print(&Apache::lonhtmlcommon::topic_bar($img,$lt{'gpme'})); if (keys(%members) > 0) { $r->print('
'.$lt{'gnam'}.':   print(''. '
  -
'.&mt('Granularity:').' '.$lt{'doyo'}.'  '); if ($action eq 'modify') { - $r->print('  ('.&mt('Currently set to "[_1]"', - $$stored{'granularity'}).')'); + $r->print('  ('.&mt('Currently set to [_1].' + ,'"'.&mt($$stored{'granularity'}).'"').')'); } $r->print('
'.&mt('Disk quota: ').''); if ($action eq 'create') { - $r->print(&mt('If you enable the file repository for the [_1], allocate a disk quota.',$gpterm)); + $r->print(&mt('If you enable the file repository for the '.$gpterm.', allocate a disk quota.')); } else { $r->print(&mt('Quota allocated to file repository:')); } - $r->print(' Mb'); + $r->print(' '.&mt('[_1] Mb','')); if ($action eq 'create') { - $r->print('
'. - &mt('A total of [_1] Mb can be divided amongst all [_2]s in the '. - '[_3], and [_4] Mb are currently unallocated.',$crsquota, - $gpterm,lc($crstype),sprintf("%.2f",$freespace))); + $r->print('
' + .&mt('A total of [_1] Mb can be divided amongst all '.$gpterm.'s in the ' + .lc($crstype).', and [_2] Mb are currently unallocated.' + ,$crsquota,sprintf("%.2f",$freespace)) + ); } else { $r->print('  ('.&mt('The quota is currently [_1] Mb', $$stored{'quota'}).').'); - $r->print('
'.&mt('The quota can be increased to [_1] Mb, '. - 'by adding all unallocated space for [_2]s in the [_3].', - sprintf("%.2f",$maxposs),$gpterm,lc($crstype))); + $r->print('
' + .&mt('The quota can be increased to [_1] Mb, ' + .'by adding all unallocated space for '.$gpterm.'s in the '.lc($crstype).'.' + ,sprintf("%.2f",$maxposs))); } $r->print('
'); $r->print(&Apache::lonhtmlcommon::status_select_row(\%status_types)); $r->print(''); - $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles)); + $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles,undef,undef,1,$cdom,$cnum)); if (@sections > 0) { @sections = sort {$a cmp $b} @sections; unshift(@sections,'none'); # Put 'no sections' next @@ -1428,9 +1812,7 @@ sub sections_selection { sub access_date_settings { my ($r,$action,$formname,$stored,$image,$gpterm,$ucgpterm) = @_; - my %lt = &Apache::lonlocal::texthash( - 'sten' => "Default start and end dates for $gpterm access", - ); + my $sten = &mt("Default start and end dates for $gpterm access"); my $starttime = time; my $endtime = time+(6*30*24*60*60); # 6 months from now, approx if ($action eq 'modify') { @@ -1440,8 +1822,7 @@ sub access_date_settings { } } my ($table) = &date_setting_table($starttime,$endtime,$formname); - &topic_bar($r,$image,$lt{'sten'}); - $r->print(' + $r->print(&Apache::lonhtmlcommon::topic_bar($image,$sten).' '.$table.' '); return; @@ -1518,6 +1899,11 @@ sub display_navbuttons {    '); + } elsif ($prevtext) { + $r->print(' + +    '); } if ($next) { $r->print(' @@ -1553,7 +1939,7 @@ sub print_current_settings { ygrs => "Your group selections - ", tfwa => "The following settings will apply to the group:", difn => 'Different collaborative tools
for different members:', - stda => 'Start date', + stda => 'Start date:', enda => 'End date:', ); my $showstart = &Apache::lonlocal::locallocaltime($startdate); @@ -1587,7 +1973,7 @@ sub print_current_settings {
'); if (@{$available} > 0) { - $r->print(&mt('Available for assignment to members:'). + $r->print(''.&mt('Available for assignment to members:').''. ''); my $rowcell = int(@{$available}/2) + @{$available}%2; for (my $i=0; $i<@{$available}; $i++) { @@ -1605,7 +1991,7 @@ sub print_current_settings { $r->print('

'); } if (@{$unavailable} > 0) { - $r->print(&mt('Unavailable for assignment:'). + $r->print(''.&mt('Unavailable for assignment:').''. ''); my $rowcell = int(@{$unavailable}/2) + @{$unavailable}%2; for (my $j=0; $j<@{$unavailable}; $j++) { @@ -1622,10 +2008,12 @@ sub print_current_settings { } $r->print('
'); } + my $quota_text=&mt('[_1] Mb',$quota); + my $granu_text=&mt($granularity); $r->print(<<"END");
$lt{'difn'} $granularity$quota Mb$lt{'difn'} $granu_text$quota_text $lt{'stda'} $showstart
$lt{'enda'} $showend
@@ -1683,13 +2071,13 @@ sub pick_new_members { if (@{$available} > 0 && $granularity eq 'Yes') { $r->print(''); } $r->print('
'.$lt{'setf'}.' - - +    - - +
@@ -1712,13 +2100,13 @@ sub pick_new_members { if ($granularity eq 'Yes') { $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense LC_data_table_highlight').'   - '.&mt('All:').' '); + '.&mt('All:').' '); foreach my $tool (@{$available}) { $r->print('   '); } - $r->print(''); + $r->print(''); } } my %Sortby = (); @@ -1752,7 +2140,7 @@ sub pick_new_members { ''.$id.''. ''.$section.''); if (@{$available} > 0) { - $r->print(''. + $r->print(''. '       '); foreach my $tool (@{$available}) { if ($granularity eq 'Yes') { @@ -1763,7 +2151,7 @@ sub pick_new_members { $tool.'" value="'.$user.'" />'.$tool.'   '); } } - $r->print(''); + $r->print(''); } $r->print(&Apache::loncommon::end_data_table_row()."\n"); } @@ -1823,7 +2211,7 @@ sub privilege_specificity { } } } - &topic_bar($r,$img,$lt{'uprv'}); + $r->print(&Apache::lonhtmlcommon::topic_bar($img,$lt{'uprv'})); if ((($action eq 'create') && (@{$available} > 0)) || (($action eq 'modify') && ($formname eq 'change_settings'))) { my %specific = ( @@ -1850,8 +2238,8 @@ sub privilege_specificity { if ($totaloptionalprivs) { $r->print('
-
-

'); +
+

'); } else { $r->print(''); } @@ -1927,7 +2315,8 @@ sub default_privileges { if ($fixed ne '') { $fixed .= ''; } - $fixed .= ''.$$toolprivs{$tool}{$priv}.' '; + $fixed .= '' + .''.$$toolprivs{$tool}{$priv}.' '; if ($action eq 'modify') { if (grep(/^$tool$/,@{$available})) { $fixed .= ''.&mt('(on)').' '; @@ -1935,18 +2324,18 @@ sub default_privileges { $fixed .= ''.&mt('(off)').' '; } } - $fixed .= ''; + $fixed .= ''; } else { $privcount++; if ($privcount == 3) { $dynamic .= ' '."\n"; } - $dynamic .= ''."\n"; + $dynamic .= ''."\n"; } } if ($privcount == 0) { - $dynamic .= 'None'."\n"; + $dynamic .= ''.&mt('None').''."\n"; } if ($privcount < 3) { $dynamic .= ' '."\n"; @@ -2064,11 +2453,11 @@ sub change_members_form { $r->print('
'); - &topic_bar($r,1,$lt{'grse'}); + $r->print(&Apache::lonhtmlcommon::topic_bar(1,$lt{'grse'})); &print_current_settings($r,$action,$functions,$startdate,$enddate, $groupname,$description,$granularity,$quota, \@available,\@unavailable,$gpterm,$ucgpterm); - &topic_bar($r,2,$lt{'mogm'}); + $r->print(&Apache::lonhtmlcommon::topic_bar(2,$lt{'mogm'})); my $numcurrent = ¤t_membership($r,$cdom,$cnum,$formname,$groupname, \@available,\@unavailable,$fixedprivs, $granularity,$specificity); @@ -2126,15 +2515,15 @@ sub current_membership { $r->print(&check_uncheck_tools($r,$available)); $r->print(' - +
'.$lt{'curf'}.' -    -
-
+ '); } @@ -2169,14 +2558,14 @@ END if ($granularity eq 'Yes') { $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense LC_data_table_highlight').'   - '.&mt('All:'). + '.&mt('All:'). ' '); foreach my $tool (@{$available}) { $r->print('   '); } - $r->print(''); + $r->print(''); } } my %Sortby = (); @@ -2204,25 +2593,25 @@ END $r->print(&Apache::loncommon::start_data_table_row('LC_data_table_dense').' '); if ($$current{$user}{changestate} eq 'reenable') { - $r->print('
'); + $lt{'reen'}.'
'); } elsif ($$current{$user}{changestate} eq 'expire') { - $r->print('
'); + $lt{'expi'}.'
'); } elsif ($$current{$user}{changestate} eq 'activate') { - $r->print('
'); + $lt{'acti'}.'
'); } - $r->print(''); + $lt{'dele'}.''); if ($specificity eq 'Yes') { - $r->print('
'); + ''); } $r->print(' '. @@ -2233,7 +2622,7 @@ END ''.$start.''. ''.$end.''); if ($hastools) { - $r->print(''. + $r->print(''. '      '); foreach my $tool (@{$$current{$user}{currtools}}) { if ($granularity eq 'Yes') { @@ -2249,23 +2638,23 @@ END } $r->print('   '); } - $r->print(''); + $r->print(''); } if ($addtools) { $r->print(''); if ($granularity eq 'Yes') { foreach my $tool (@{$$current{$user}{newtools}}) { - $r->print('   '); + '   '); } } else { foreach my $tool (@{$$current{$user}{newtools}}) { - $r->print('print(''.$tool. - '   '); + '   '); } } $r->print(''); @@ -2286,13 +2675,13 @@ sub check_uncheck_buttons {
'.$title.' - - +    - - +
'); @@ -2318,7 +2707,7 @@ sub change_privs_form { } else { $nexttext = $$navbuttons{'mose'}; } - &topic_bar($r,3,&mt('Members to delete or expire')); + $r->print(&Apache::lonhtmlcommon::topic_bar(3,&mt('Members to delete or expire'))); my $exp_or_del = 0; if (ref($$memchg{'deletion'}) eq 'ARRAY') { if (@{$$memchg{'deletion'}} > 0) { @@ -2346,7 +2735,7 @@ sub change_privs_form { $r->print($lt{'nome'}.'
'); } - &topic_bar($r,4,&mt('Setting optional privileges for specific group members')); + $r->print(&Apache::lonhtmlcommon::topic_bar(4,&mt('Setting optional privileges for specific group members'))); my $numchgs = &member_privileges_form($r,$action,$formname,$tools, $toolprivs,$fixedprivs,$userdata, @@ -2363,7 +2752,7 @@ sub change_privs_form { } sub add_members_form { - my ($r,$action,$formname,$page,$startdate,$enddate,$groupname, + my ($r,$cdom,$cnum,$action,$formname,$page,$startdate,$enddate,$groupname, $description,$granularity,$quota,$sectioncount,$tools,$functions, $stored,$states,$navbuttons,$gpterm,$ucgpterm)=@_; $r->print('
'); @@ -2373,7 +2762,8 @@ sub add_members_form { &print_current_settings($r,$action,$functions,$startdate,$enddate, $groupname,$description,$granularity,$quota, \@available,\@unavailable,$gpterm,$ucgpterm); - &membership_options($r,$action,$formname,$sectioncount,1,$gpterm,$ucgpterm); + &membership_options($r,$cdom,$cnum,$action,$formname,$sectioncount,1,$gpterm, + $ucgpterm); my $nexttext = $$navbuttons{'gtns'}; my $prevtext = $$navbuttons{'gtpp'}; &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext, @@ -2402,7 +2792,7 @@ sub choose_privs_form { $nexttext = $$navbuttons{'adme'}; } - &topic_bar($r,6,&mt('Setting optional privileges for specific group members')); + $r->print(&Apache::lonhtmlcommon::topic_bar(6,&mt('Setting optional privileges for specific group members'))); &member_privileges_form($r,$action,$formname,$tools,$toolprivs, $fixedprivs,$userdata,$usertools,$idx,undef, @@ -2413,7 +2803,7 @@ sub choose_privs_form { my $img2 = 8; &mapping_options($r,$action,$formname,$page,$sectioncount, $states,$stored,$navbuttons,$img1,$img2, - $gpterm,$ucgpterm,$crstype); + $gpterm,$ucgpterm,$crstype,$cdom,$cnum); } my $prevtext = $$navbuttons{'gtps'}; &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext, @@ -2491,7 +2881,8 @@ sub member_privileges_form { 'members being added or modified, '. 'there are no optional privileges to set '. 'for specific members.', - 'algr' => 'All new group members will receive the same privileges.', 'ifex' => 'If previously expired members are being re-enabled, or '. + 'algr' => 'All new group members will receive the same privileges.', + 'ifex' => 'If previously expired members are being re-enabled, or '. 'if access for future members is being activated now, '. 'previously set privileges will be preserved.', 'asno' => 'As no group members are being added, '. @@ -2569,7 +2960,7 @@ sub member_privileges_form { $r->print(''); $r->print(''. ''); + &mt($tool).''); my $privcount = 0; foreach my $priv (@{$showboxes{$tool}}) { $privcount ++; @@ -2583,15 +2974,16 @@ sub member_privileges_form { } else { $r->print(''); if ($privcount < @{$showboxes{$tool}}) { if (@{$showboxes{$tool}} > 2) { @@ -2735,11 +3127,19 @@ sub write_group_data { } if ($quota !~ /^\d*\.?\d*$/) { $quota = 0; - $r->print(&mt('The value you entered for the quota for the file repository in this [_1] contained invalid characters, so it has been set to 0 Mb. You can change this by modifying the [_1] settings.
',$gpterm)); + $r->print('
' + .&mt('The value you entered for the quota for the file repository in this '.$gpterm + .' contained invalid characters, so it has been set to 0 Mb. You can change this by' + .' modifying the '.$gpterm.' settings.') + .'
'); } if ($quota > $maxposs) { $quota = $maxposs; - $r->print(&mt('The value you entered for the quota for the file repository in this [_1] exceeded the maximum possible value, so it has been set to [_2] Mb (the maximum possible value).
',$gpterm,sprintf("%.2f",$maxposs))); + $r->print('
' + .&mt('The value you entered for the quota for the file repository in this '.$gpterm + .' exceeded the maximum possible value, so it has been set to [_1] Mb ' + .'(the maximum possible value).',sprintf("%.2f",$maxposs)) + .'
'); } my %groupinfo = ( description => $esc_description, @@ -2804,10 +3204,17 @@ sub write_group_data { my $result = &add_group_folder($cdom,$cnum,$now,$groupname,$action, $description,$tools,\%groupinfo, $gpterm,$ucgpterm,$crstype); - if ($result ne 'ok') { - $r->print(&mt('A problem occurred when creating folders for the new [_1]. [_2].
',$gpterm,$result)); + if ($result eq 'ok') { + $r->print('
' + .&mt($ucgpterm.' [_1] was created.',''.$groupname.'') + .'
'); + } else { + $r->print('
' + .&mt('A problem occurred when creating folders for the new '.$gpterm.' [_1]:' + ,''.$groupname.'') + .'
'.$result + .'
'); } - $r->print(&mt('[_1] [_2] was created.
',$ucgpterm,$groupname)); } elsif ($action eq 'modify') { my (@oldtools,@newtools); if (ref($$stored{'tool'}) eq 'ARRAY') { @@ -2821,35 +3228,54 @@ sub write_group_data { my $crspath = '/uploaded/'.$cdom.'/'.$cnum.'/'; my $boardsmap = $crspath.'group_boards_'.$groupname.'.sequence'; my $navmap = Apache::lonnavmaps::navmap->new(); - my $bbmapres = $navmap->getResourceByUrl($boardsmap); - undef($navmap); - if (!$bbmapres) { - my $grpmap = $crspath.'group_folder_'.$groupname.'.sequence'; - my $disctitle = &mt('Discussion Boards'); - my $outcome = &map_updater($cdom,$cnum,'group_boards_'. - $groupname.'.sequence','bbseq', - $disctitle,$grpmap); - my ($furl,$ferr) = - &Apache::lonuserstate::readmap($cdom.'/'.$cnum); - $navmap = Apache::lonnavmaps::navmap->new(); - # modify parameter - if ($outcome eq 'ok') { - my $parm_result = &parm_setter($navmap,$cdom,$boardsmap, - $groupname); - if ($parm_result) { - $r->print(&mt('Error while setting parameters '. - 'for Discussion Boards folder: '. - '[_1]
.',$parm_result)); + my ($bbmapres,$error); + if (defined($navmap)) { + $bbmapres = $navmap->getResourceByUrl($boardsmap); + undef($navmap); + if (!$bbmapres) { + my $grpmap = $crspath.'group_folder_'.$groupname.'.sequence'; + my $disctitle = &mt('Discussion Boards'); + my $outcome = &map_updater($cdom,$cnum,'group_boards_'. + $groupname.'.sequence','bbseq', + $disctitle,$grpmap); + my ($furl,$ferr) = + &Apache::lonuserstate::readmap($cdom.'/'.$cnum); + # modify parameter + if ($outcome eq 'ok') { + $navmap = Apache::lonnavmaps::navmap->new(); + if (defined($navmap)) { + my $parm_result = &parm_setter($navmap,$cdom,$boardsmap, + $groupname); + if ($parm_result) { + $error = &mt('An error occurred while setting parameters ' + .'for Discussion Boards folder: ' + .'[_1]',$parm_result); + } else { + $r->print('
'. + &mt('Discussion Boards Folder created.') + .'
'); + } + undef($navmap); + } else { + $error = &mt('An error occurred while setting parameters '. + 'for Discussion Boards folder: '. + 'Could not retrieve course information' ); + } } else { - $r->print(&mt('Discussion Boards Folder created.
')); + $r->print($outcome); } - } else { - $r->print($outcome); } - undef($navmap); + } else { + $error = &mt("An error occurred while retrieving the contents of the group's folder.").'
'. + &mt('You need to re-initialize the course.'); + } + if ($error ne '') { + $r->print('
'.$error.'
'); } } - $r->print(&mt('[_1] [_2] was updated.
',$ucgpterm,$groupname)); + $r->print('
' + .&mt($ucgpterm.' [_1] was updated.',''.$groupname.'') + .'
'); } } else { my %actiontype = ( @@ -2859,8 +3285,10 @@ sub write_group_data { &Apache::lonnet::logthis("Failed to store $gpterm $groupname ". 'in '.lc($crstype).': '.$cnum. ' in domain: '.$cdom); - $r->print(&mt('An error occurred when [_1] the [_2]. '. - 'Please try again.',$actiontype{$action},$gpterm)); + $r->print('
' + .&mt('An error occurred when [_1] the '.$gpterm.'. ' + .'Please try again.',$actiontype{$action}) + .'
'); } return $result; } @@ -2879,6 +3307,7 @@ sub process_membership { my %curr_start = (); my %curr_end = (); my %tooltype = (); + my $context = 'processgroupmembership'; foreach my $tool (@{$tools}) { foreach my $priv (sort(keys(%{$$toolprivs{$tool}}))) { @@ -2948,7 +3377,7 @@ sub process_membership { $curr_privs{$user}; if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname, $user,$now,$savestart, - $curr_privs{$user}) eq 'ok') { + $curr_privs{$user},'',$context) eq 'ok') { push(@{$added{'expired'}},$user); $num_ok ++; } else { @@ -2959,7 +3388,7 @@ sub process_membership { foreach my $user (@deletion) { $usersettings{$groupname.':'.$user} = $now.':-1:'; if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname, - $user,$now,'-1','') + $user,$now,'-1','','',$context) eq 'ok') { push(@{$added{'deleted'}},$user); $num_ok ++; @@ -3013,7 +3442,7 @@ sub process_membership { $group_privs{$user}; if (&Apache::lonnet::modify_group_roles($cdom,$cnum,$groupname, $user,$end,$start, - $group_privs{$user}) eq 'ok') { + $group_privs{$user},'',$context) eq 'ok') { push(@{$added{$type}},$user); $num_ok ++; } else { @@ -3052,7 +3481,9 @@ sub process_membership { } if ($num_fail) { foreach my $type (sort(keys(%failed))) { - $r->print(&mt('The following users could not be [_1], because an error occurred:
',$type)); + $r->print('
' + .&mt("The following users could not be $type, because an error occurred:") + .'
'); foreach my $user (@{$failed{$type}}) { $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'
'); } @@ -3060,24 +3491,35 @@ sub process_membership { $r->print('
'); } if (@unchanged > 0) { - $r->print(&mt('No change occurred for the following users:
')); + $r->print(&mt('No change occurred for the following users:').'
'); foreach my $user (sort(@unchanged)) { $r->print($$userdata{$user}[$$idx{fullname}].' - '.$user.'
'); } $r->print('
'); } if ($roster_result eq 'ok') { - $r->print('
'.&mt('[_1] membership list updated.',$ucgpterm)); - $r->print('

'.&mt("Any currently logged in course users affected by the changes you made to group membership or privileges for the [_1] group will need to log out and log back in for their LON-CAPA sessions to reflect these changes.",$groupname).'

'); + $r->print('
' + .&mt($ucgpterm.' membership list updated.') + .'
'); + $r->print('

' + .&mt('Any currently logged in course users affected by the changes you made' + .' to group membership or privileges for the [_1] group will need to log out' + .' and log back in for their LON-CAPA sessions to reflect these changes.' + ,''.$groupname.'') + .'

' + ); } else { - $r->print('
'.&mt('An error occurred while updating the [_1] membership list -',$gpterm).$roster_result.'
'); + $r->print('
' + .&mt("An error occurred while updating the $gpterm membership list:") + .'
'.$roster_result + .'
'); } return; } sub mapping_options { my ($r,$action,$formname,$page,$sectioncount,$states,$stored, - $navbuttons,$img1,$img2,$gpterm,$ucgpterm,$crstype) = @_; + $navbuttons,$img1,$img2,$gpterm,$ucgpterm,$crstype,$cdom,$cnum) = @_; my %lt = &Apache::lonlocal::texthash( 'auto' => "Settings for automatic $gpterm enrollment", 'gmma' => "$ucgpterm membership mapping to specific sections/roles", @@ -3086,7 +3528,6 @@ sub mapping_options { 'adds' => "If automatic $gpterm enrollment is enabled, when a user is newly assigned a ".lc($crstype)."-wide or section-specific role, he/she will automatically be added as a member of the $gpterm, with start and end access dates defined by the default dates set for the $gpterm, unless he/she is already a $gpterm member, with access dates that permit either current or future $gpterm access.", 'drops' => "If automatic $gpterm disenrollment is enabled, when a user's role is expired, access to the $gpterm will be terminated unless the user continues to have other ".lc($crstype)."-wide or section-specific active or future roles which receive automatic membership in the $gpterm.", 'pirs' => "Pick roles and sections for automatic $gpterm enrollment", - 'curr' => 'Currently set to', 'on' => 'on', 'off' => 'off', 'auad' => "Automatically enable $gpterm membership when roles are added?", @@ -3094,7 +3535,8 @@ sub mapping_options { 'mapr' => "Mapping of roles and sections affected by automatic $gpterm enrollment/disenrollment follows scheme chosen below.", ); &automapping($r,$action,$stored,\%lt,$img1); - &mapping_settings($r,$sectioncount,\%lt,$stored,$img2,$crstype); + &mapping_settings($r,$sectioncount,\%lt,$stored,$img2,$crstype,$cdom,$cnum, + $action); return; } @@ -3108,26 +3550,25 @@ sub automapping { if (exists($$stored{'autodrop'})) { $drop = $$stored{'autodrop'}; } - &topic_bar($r,$image,$$lt{'endi'}); - $r->print(' + $r->print(&Apache::lonhtmlcommon::topic_bar($image,$$lt{'endi'}).' '.$$lt{'gmma'}.':
'.$$lt{'adds'}.'
'.$$lt{'drops'}.'

- '.$$lt{'auad'}.':  - '); + '.$$lt{'auad'}.':  + '); if ($action eq 'modify') { - $r->print('    ('.$$lt{'curr'}.' '.$$lt{$add}.')'); + $r->print('    ('.&mt('Currently set to [_1].',''.$$lt{$add}.'').')'); } $r->print(' -
- '.$$lt{'auex'}.':  - '); +
+ '.$$lt{'auex'}.':  + '); if ($action eq 'modify') { - $r->print('    ('.$$lt{'curr'}.' '.$$lt{$drop}.')'); + $r->print('    ('.&mt('Currently set to [_1].',''.$$lt{$drop}.'').')'); } - $r->print('


'.$$lt{'mapr'}); + $r->print('

'.$$lt{'mapr'}); } sub mapping_settings { - my ($r,$sectioncount,$lt,$stored,$image,$crstype) = @_; + my ($r,$sectioncount,$lt,$stored,$image,$crstype,$cdom,$cnum,$action) = @_; my @sections = keys(%{$sectioncount}); if (@sections > 0) { @sections = sort {$a cmp $b} @sections; @@ -3136,9 +3577,9 @@ sub mapping_settings { } else { @sections = ('all','none'); } - &topic_bar($r,$image,$$lt{'pirs'}); + $r->print(&Apache::lonhtmlcommon::topic_bar($image,$$lt{'pirs'})); my @roles = &standard_roles(); - my %customroles = &my_custom_roles(); + my %customroles = &Apache::lonhtmlcommon::course_custom_roles($cdom,$cnum); $r->print(&Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row()); $r->print(' @@ -3149,57 +3590,60 @@ sub mapping_settings { } $r->print(&Apache::loncommon::end_data_table_header_row()."\n"); foreach my $role (@roles) { - my $plrole=&Apache::lonnet::plaintext($role,$crstype); - my $sections_sel; - if (@sections > 0) { - if ($role eq 'cc') { - $sections_sel = ''; - } else { - $sections_sel=''; - } - } - $r->print(&Apache::loncommon::start_data_table_row(). - ''.$sections_sel. - &Apache::loncommon::end_data_table_row()); + my $roletitle=&Apache::lonnet::plaintext($role,$crstype); + $r->print(&print_autorole_item($role,$roletitle,\@sections)); } + my @customs; foreach my $role (sort(keys(%customroles))) { - my $sections_sel; - if (@sections > 0) { - $sections_sel = - ''; - } - $r->print(&Apache::loncommon::start_data_table_row(). - ''.$sections_sel. - &Apache::loncommon::end_data_table_row()); + my ($roletitle) = ($role =~ m|^cr/[^/]+/[^/]+/(.+)$|); + push (@customs,$role); + $r->print(&print_autorole_item($role,$roletitle,\@sections)); + } + if ($action eq 'modify') { + foreach my $role (@{$$stored{'autorole'}}) { + if ((!grep(/^\Q$role\E$/,@customs)) && + (!grep(/^\Q$role\E$/,@roles))) { + my $roletitle; + if ($role =~ /^cr/) { + ($roletitle) = ($role =~ m|_([^_]+)$|); + } else { + $roletitle = &Apache::lonnet::plaintext($role,$crstype); + } + $r->print(&print_autorole_item($role,$roletitle,\@sections)); + } + } } $r->print(&Apache::loncommon::end_data_table()); return; } +sub print_autorole_item { + my ($role,$roletitle,$sections) = @_; + my $sections_sel; + if (@{$sections} > 0) { + if ($role eq 'cc') { + $sections_sel = ''; + } else { + $sections_sel=''; + } + } + my $output = &Apache::loncommon::start_data_table_row(). + ''.$sections_sel. + &Apache::loncommon::end_data_table_row(); + return $output; +} + sub standard_roles { my @roles = ('cc','in','ta','ep','st'); return @roles; } -sub my_custom_roles { - my %returnhash=(); - my %rolehash=&Apache::lonnet::dump('roles'); - foreach (keys %rolehash) { - if ($_=~/^rolesdef\_(\w+)$/) { - $returnhash{$1}=$1; - } - } - return %returnhash; -} - sub modify_menu { my ($r,$groupname,$page,$gpterm) = @_; my @menu = @@ -3280,16 +3724,16 @@ sub member_privs_entries { if ($privcount == 3) { $dynamic .= ''; } - $dynamic .=''; + ''; } } - $r->print(''.$dynamic.'
'. - $tool.'
'); } - $r->print(qq| -
$$toolprivs{$tool}{$priv} - - -   - -

|); + $r->print( + '
'.&mt($$toolprivs{$tool}{$priv}).'' +.'' +.' ' +.' ' +.'' +.'

' + ); $r->print('
'. - &mt('all sections').''. - §ions_selection(\@sections,'sec_'.$role). - ''.$plrole. - ''.§ions_selection(\@sections,'sec_'.$role).''.&mt('Custom role: '). - ''.$role.''. + &mt('all sections').''. + §ions_selection($sections,'sec_'.$role). + ''. + ''.$roletitle.'
'.$fixed.'
'); + $r->print(''.$fixed.''.$dynamic.''); } else { $r->print('
'.$tool.'
 
 
'); } @@ -3316,8 +3760,8 @@ sub date_setting_table { my $endform = &Apache::lonhtmlcommon::date_setter($formname, 'enddate',$endtime); my $perpetual = - ''; + ''; my $table = "\n". ''. ''. @@ -3333,40 +3777,56 @@ sub add_group_folder { my ($cdom,$cnum,$now,$groupname,$action,$description,$tools,$groupinfo, $gpterm,$ucgpterm,$crstype) = @_; if ($cdom eq '' || $cnum eq '') { - return &mt('Error: invalid course domain or number - group folder creation failed'); + return '' + .&mt('Error: invalid course domain or number - group folder creation failed.') + .''; } - my ($outcome,$allgrpsmap,$grpmap,$boardsmap,$grppage); - my $navmap = Apache::lonnavmaps::navmap->new(); + my ($outcome,$allgrpsmap,$grpmap,$boardsmap,$grppage,$warning); my $crspath = '/uploaded/'.$cdom.'/'.$cnum.'/'; $allgrpsmap = $crspath.'group_allfolders.sequence'; - my $topmap = $navmap->getResourceByUrl($allgrpsmap); - undef($navmap); if ($action eq 'create') { - # check if group_allfolders.sequence exists. - if (!$topmap) { - my $grpstitle = &mt('[_1] [_2]s',$crstype,$ucgpterm); - my $topmap_url = '/'.$env{'course.'.$env{'request.course.id'}.'.url'}; - $topmap_url =~ s|/+|/|g; - if ($topmap_url =~ m|^/uploaded|) { - $outcome = &map_updater($cdom,$cnum,'group_allfolders.sequence', - 'toplevelgroup',$grpstitle,$topmap_url); + if (&get_folder_lock($cdom,$cnum,'group_allfolders',$now) eq 'ok') { + # check if group_allfolders.sequence exists. + my $mapcontents = &Apache::lonnet::getfile($allgrpsmap); + if ($mapcontents eq '-1') { #file does not exist; + my $grpstitle = &mt("$crstype $ucgpterm".'s'); + my $topmap_url = '/'.$env{'course.'.$env{'request.course.id'}.'.url'}; + $topmap_url =~ s|/+|/|g; + if ($topmap_url =~ m|^/uploaded|) { + $outcome = &map_updater($cdom,$cnum,'group_allfolders.sequence', + 'toplevelgroup',$grpstitle,$topmap_url); + } else { + $outcome = '' + .&mt('Non-standard course - folder for all groups not added.') + .''; + } if ($outcome ne 'ok') { - return $outcome; + my $delresult = &release_folder_lock($cdom,$cnum,'group_allfolders'); + if ($delresult ne 'ok') { + $warning = $delresult; + } + return $outcome.$warning; } - } else { - $outcome = &mt('Non-standard course - folder for all groups not added.'); - return $outcome; } + my $delresult = &release_folder_lock($cdom,$cnum,'group_allfolders'); + if ($delresult ne 'ok') { + $warning = $delresult ; + } + } else { + $outcome = '' + .&mt('Could not obtain exclusive lock to check status of the folder for all groups. No group folder added.') + .''; + return $outcome; } - my $grpfolder = &mt('[_1] Folder -',$ucgpterm,).$description; + my $grpfolder = &mt($ucgpterm.' Folder - [_1]',$description); $grppage='/adm/'.$cdom.'/'.$cnum.'/'.$groupname.'/smppg'; - my $grptitle = &mt('Group homepage').' - '.$description; + my $grptitle = &mt('Group homepage - [_1]',$description); my ($discussions,$disctitle); my $outcome = &map_updater($cdom,$cnum,'group_folder_'.$groupname.'.sequence', 'grpseq',$grpfolder,$allgrpsmap,$grppage, $grptitle); if ($outcome ne 'ok') { - return $outcome; + return $outcome.$warning; } my $pageout = &create_homepage($cdom,$cnum,$groupname,$groupinfo, $tools,$gpterm,$ucgpterm,$now); @@ -3377,7 +3837,7 @@ sub add_group_folder { my $outcome = &map_updater($cdom,$cnum,'group_boards_'.$groupname. '.sequence','bbseq',$disctitle,$grpmap); if ($outcome ne 'ok') { - return $outcome; + return $outcome.$warning; } $boardsmap = $crspath.'group_boards_'.$groupname.'.sequence'; } @@ -3385,7 +3845,11 @@ sub add_group_folder { #modify group folder if status of discussions tools is changed } my ($furl,$ferr)= &Apache::lonuserstate::readmap($cdom.'/'.$cnum); - $navmap = Apache::lonnavmaps::navmap->new(); + my $navmap = Apache::lonnavmaps::navmap->new(); + if (!defined($navmap)) { + return $warning.''.&mt('Error retrieving course contents'). + ' '.&mt('You need to re-initialize the course.').''; + } # modify parameters my $parm_result; if ($action eq 'create') { @@ -3399,8 +3863,42 @@ sub add_group_folder { $parm_result .= &parm_setter($navmap,$cdom,$boardsmap,$groupname); } } + undef($navmap); if ($parm_result) { - return $parm_result; + return $warning.$parm_result; + } else { + return 'ok'; + } +} + +sub get_folder_lock { + my ($cdom,$cnum,$folder_name,$now) = @_; + # get lock for folder being edited. + my $lockhash = { + $folder_name."\0".'locked_folder' => $now.':'.$env{'user.name'}. + ':'.$env{'user.domain'}, + }; + my $tries = 0; + my $gotlock = &Apache::lonnet::newput('coursegroups',$lockhash,$cdom,$cnum); + + while (($gotlock ne 'ok') && $tries <3) { + $tries ++; + sleep(1); + $gotlock = &Apache::lonnet::newput('coursegroups',$lockhash,$cdom,$cnum); + } + return $gotlock; +} + +sub release_folder_lock { + my ($cdom,$cnum,$folder_name) = @_; + # remove lock + my @del_lock = ($folder_name."\0".'locked_folder'); + my $dellockoutcome=&Apache::lonnet::del('coursegroups',\@del_lock,$cdom,$cnum); + if ($dellockoutcome ne 'ok') { + return ('
' + .&mt('Warning: failed to release lock for folder: [_1].',''.$folder_name.'') + .'
' + ); } else { return 'ok'; } @@ -3415,21 +3913,27 @@ sub map_updater { my $newmapurl=&Apache::lonnet::finishuserfileupload($cnum,$cdom,$itemname, $newfile); if ($newmapurl !~ m|^/uploaded|) { - $outcome = &mt('Error uploading new folder.')." ($newfile): $newmapurl".'
'; + $outcome = '
' + .&mt('Error uploading new folder.')." ($newfile): $newmapurl" + .'
'; return $outcome; - } - my ($errtext,$fatal)=&Apache::lonratedt::mapread($parentmap); + } + my ($errtext,$fatal)=&LONCAPA::map::mapread($parentmap); if ($fatal) { - $outcome = &mt('Error reading contents of parent folder')." ($parentmap): $errtext".'
'; + $outcome = '
' + .&mt('Error reading contents of parent folder.')." ($parentmap): $errtext" + .'
'; return $outcome; } else { - my $newidx=&Apache::lonratedt::getresidx($newmapurl); - $Apache::lonratedt::resources[$newidx] = $itemtitle.':'.$newmapurl. + my $newidx=&LONCAPA::map::getresidx($newmapurl); + $LONCAPA::map::resources[$newidx] = $itemtitle.':'.$newmapurl. ':false:normal:res'; - $Apache::lonratedt::order[1+$#Apache::lonratedt::order]=$newidx; - my ($outtext,$errtext) = &Apache::lonratedt::storemap($parentmap,1); + $LONCAPA::map::order[1+$#LONCAPA::map::order]=$newidx; + my ($outtext,$errtext) = &LONCAPA::map::storemap($parentmap,1); if ($errtext) { - $outcome = &mt('Error storing updated parent folder')." ($parentmap): $errtext".'
'; + $outcome = '
' + .&mt('Error saving updated parent folder.')." ($parentmap): $errtext" + .'
'; return $outcome; } } @@ -3451,6 +3955,12 @@ sub new_map { sub parm_setter { my ($navmap,$cdom,$url,$groupname) = @_; my $allresults; + if (!defined($navmap)) { + $allresults = '
'. + &mt('Parameters not set for [_1] because the contents of the course could not be retrieved.',$url).' '. + &mt('You need to reinitialize the course.'). + '
'; + } my %hide_settings = ( 'course' => { 'num' => 13, @@ -3463,18 +3973,26 @@ sub parm_setter { }, ); my $res = $navmap->getResourceByUrl($url); - my $symb = $res->symb(); - foreach my $level (keys(%hide_settings)) { - my $parmresult = &Apache::lonparmset::storeparm_by_symb($symb, + if ($res) { + my $symb = $res->symb(); + foreach my $level (keys(%hide_settings)) { + my $parmresult = + &Apache::lonparmset::storeparm_by_symb($symb, '0_hiddenresource', $hide_settings{$level}{'num'}, $hide_settings{$level}{'set'}, 'string_yesno',undef,$cdom, undef,undef, $hide_settings{$level}{'extra'}); - if ($parmresult) { - $allresults .= $level.': '.$parmresult; + if ($parmresult) { + $allresults .= $level.': '.$parmresult; + } } + } else { + $allresults = '
' + .&mt('Parameters not set for [_1] because the resource was not recognized' + .' as part of the course.',''.$url.'') + .'
'; } return $allresults; } @@ -3538,7 +4056,12 @@ sub validate_groupname { my ($groupname,$action,$cdom,$cnum,$gpterm,$ucgpterm,$crstype) = @_; my %sectioncount = &Apache::loncommon::get_sections($cdom,$cnum); my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum); - + my %deleted_groups = &Apache::longroup::coursegroups($cdom,$cnum,undef, + 'deleted_groups'); + if (my $tmp = &Apache::lonnet::error(%deleted_groups)) { + undef(%deleted_groups); + &Apache::lonnet::logthis('Error retrieving groups: '.$tmp.' in '.$cnum.':'.$cdom); + } my %lt = &Apache::lonlocal::texthash ( igna => "Invalid $gpterm name", tgne => "The $gpterm name entered ", @@ -3565,12 +4088,14 @@ sub validate_groupname { return $exitmsg.$lt{'cnnb'}.&mt('a section').$lt{'inth'}. '
'.$lt{'grna'}; } - if ($action eq 'create' - && exists($curr_groups{$groupname})) { - - return $exitmsg.$lt{'cnnb'}.&mt('an existing [_1]',$gpterm). - $lt{'inth'}.'
'.$lt{'grna'}; - + if ($action eq 'create') { + if (exists($curr_groups{$groupname})) { + return $exitmsg.$lt{'cnnb'}.&mt('an existing [_1]',$gpterm). + $lt{'inth'}.'.
'.$lt{'grna'}; + } elsif (exists($deleted_groups{$groupname})) { + return $exitmsg.$lt{'cnnb'}.&mt('a [_1] which previously existed',$gpterm). + $lt{'inth'}.'.
'.$lt{'grna'}; + } } elsif ($action eq 'modify') { unless(exists($curr_groups{$groupname})) { $earlyout = &mt('[_1] name:',$ucgpterm).' '.$groupname.$lt{'thgr'}. @@ -3581,18 +4106,6 @@ sub validate_groupname { return; } -sub topic_bar { - my ($r,$imgnum,$title) = @_; - $r->print(' -
- '.&mt('Step [_1]',$imgnum).
-	      '  - '.$title.' -
-'); - return; -} - sub check_changes { my ($member_changes,$memchg) = @_; my %exclusions;
'.&mt('Start:').''.$startform.'