--- loncom/interface/loncoursegroups.pm 2006/07/29 00:31:58 1.59 +++ loncom/interface/loncoursegroups.pm 2006/11/20 23:49:49 1.64 @@ -1,6 +1,6 @@ # The LearningOnline Network with CAPA # -# $Id: loncoursegroups.pm,v 1.59 2006/07/29 00:31:58 raeburn Exp $ +# $Id: loncoursegroups.pm,v 1.64 2006/11/20 23:49:49 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; @@ -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')) { 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') { if ($view_permission || $manage_permission) { if ($state eq 'view') { &print_main_menu($r,$cdom,$cnum,\%functions,\%idx, @@ -127,6 +129,15 @@ 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') { @@ -155,7 +166,7 @@ sub display_groups { $env{'form.refpage'}.'&state=pick_task&groupname=', view => ' 'Modify', @@ -176,8 +187,8 @@ sub display_groups { nogr => 'No groups exist.', crng => 'Create a new group', alth => 'Although your current role has privileges'. - ' to view any existing groups in this'. - lc($crstype).', you do not have privileges'. + ' to view any existing groups in this '. + lc($crstype).', you do not have privileges '. 'to create new groups.', ); if ($view_permission) { @@ -295,7 +306,9 @@ END if (($manage_permission) && ($env{'form.refpage'} ne 'enrl')) { $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'). @@ -798,6 +811,7 @@ function changeSort(caller) { my %branchstates = (); @{$states{'create'}} = ('pick_name','pick_members','pick_privs','result'); @{$states{'modify'}} = ('pick_task'); + @{$states{'delete'}} = ('verify','result'); @{$branchstates{'noprivs'}} = ('result'); @{$branchstates{'settings'}} = ('change_settings','chgresult'); @{$branchstates{'members'}} = ('change_members','change_privs','memresult'); @@ -808,7 +822,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')) { my $done = 0; my $i=0; while ($i<@{$states{$action}} && !$done) { @@ -829,9 +843,9 @@ function changeSort(caller) { ({href=>"/adm/dropadd", text=>"Enrollment Manager", 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=enrl&action=$action", text=>"Groups", faq=>9,bug=>'Instructor Interface',}); } @@ -867,6 +881,10 @@ function changeSort(caller) { memresult => 'Modifications Complete', addresult => 'Additions Complete', ); + %{$trail{'delete'}} = &Apache::lonlocal::texthash( + verify => 'Verify deletion', + result => 'Deletion Complete' + ); my %navbuttons = &Apache::lonlocal::texthash( gtns => 'Go to next step', gtps => 'Go to previous step', @@ -875,14 +893,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')) && ($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 +911,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,7 +932,6 @@ function changeSort(caller) { &display_groups($r,$cdom,$cnum,$functions,$idx,$view_permission, $manage_permission,$action,$state,$gpterm,$ucgpterm, $crstype); - } $r->print(&footer()); return; @@ -1059,7 +1078,138 @@ sub display_control { $sections,$states,$navbuttons,$memchg, $sectioncount,$stored,$gpterm,$ucgpterm,$crstype); } + } elsif ($action eq 'delete') { + my %stored = &retrieve_settings($cdom,$cnum,$groupname); + if ($state eq 'verify') { + &verify_delete($r,$groupname,$state,$action,$page,$states, + \%stored); + } elsif ($state eq 'result') { + &delete_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 following group: ").''. + $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 'enrl') { + $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; + foreach my $key (sort(keys(%membership))) { + if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) { + my $user = $1; + my($end,$start,@userprivs) = split(/:/,$membership{$key}); + if ($start != -1) { + $num_users ++; + $usersettings{$groupname.':'.$user} = $now.':-1:'; + if (&Apache::lonnet::modify_group_roles($cdom,$cnum, + $groupname,$user, + $now,'-1','') + 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::delete_coursegroup($cdom,$cnum,$groupname); + 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 ([_1]) occurred when removing the group's folder from the 'Course Groups' folder.",$outcome)); + } + } else { + $r->print(&mt('Group deletion failed')); + } } + return; +} + +sub modify_folders { + my ($cdom,$cnum,$groupname) = @_; + my $outcome; + my $navmap = Apache::lonnavmaps::navmap->new(); + my $groupmap = '/uploaded/'.$cdom.'/'.$cnum.'/'.'group_folder_'. + $groupname.'.sequence'; + my $groupmapres = $navmap->getResourceByUrl($groupmap); + if ($groupmapres) { + my ($map,$id,$src)=&Apache::lonnet::decode_symb($groupmapres->symb()); + $map = '/'.$map; + my ($errtext,$fatal) = &LONCAPA::map::mapread($map); + if ($fatal) { + $outcome=&mt('Error 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 ($outtext) { + $outcome = &mt('Error storing updated parent folder to group'). " ($map): $errtext".'
'; + return; + } + } + } + } + undef($navmap); + return $outcome; } sub header { @@ -1151,39 +1301,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, @@ -1518,6 +1683,11 @@ sub display_navbuttons {    '); + } elsif ($prevtext) { + $r->print(' + +    '); } if ($next) { $r->print(' @@ -3423,17 +3593,17 @@ sub map_updater { $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".'
'; 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); - if ($errtext) { + $LONCAPA::map::order[1+$#LONCAPA::map::order]=$newidx; + my ($outtext,$errtext) = &LONCAPA::map::storemap($parentmap,1); + if ($outtext) { $outcome = &mt('Error storing updated parent folder')." ($parentmap): $errtext".'
'; return $outcome; } @@ -3543,7 +3713,11 @@ 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::lonnet::get_deleted_groups($cdom,$cnum); + 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 ", @@ -3570,12 +3744,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'}.