--- loncom/interface/loncoursegroups.pm 2005/10/27 23:42:17 1.2 +++ loncom/interface/loncoursegroups.pm 2006/05/22 22:35:46 1.21 @@ -29,150 +29,1226 @@ use Apache::lonnet; use Apache::loncommon; use Apache::lonhtmlcommon; use Apache::lonlocal; +use Apache::lonnavmaps; +use Apache::longroup; use Apache::Constants qw(:common :http); sub handler { my ($r) = @_; + &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - + if ($r->header_only) { return OK; } - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['action','state']); - - $r->print(&header()); - - &Apache::lonhtmlcommon::clear_breadcrumbs(); - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>"/adm/groups", - text=>"Group Management", - faq=>9,bug=>'Instructor Interface',}); # Needs to be in a course if (! ($env{'request.course.fn'})) { # Not in a course $env{'user.error.msg'}= - "/adm/groups:mdg:0:0:Cannot create, modify or delete course groups"; + "/adm/coursegroups:mdg:0:0:Cannot edit or view course groups"; return HTTP_NOT_ACCEPTABLE; } + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['action','refpage','state','groupname','branch']); + my $function = &Apache::loncommon::get_users_function(); + my $tabcol = &Apache::loncommon::designparm($function.'.tabbg'); + my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $view_permission = - &Apache::lonnet::allowed('vcg',$env{'request.course.id'}); + &Apache::lonnet::allowed('vcg',$env{'request.course.id'}); my $manage_permission = - &Apache::lonnet::allowed('mdg',$env{'request.course.id'}); + &Apache::lonnet::allowed('mdg',$env{'request.course.id'}); + &Apache::lonhtmlcommon::clear_breadcrumbs(); - if (! exists($env{'form.action'})) { - $r->print(&Apache::lonhtmlcommon::breadcrumbs - (undef,'Course Group Manager')); - &print_main_menu($r,$manage_permission,$view_permission); - } elsif ($env{'form.action'} eq 'create' && $manage_permission) { - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>'/adm/coursegroups?action=create&state=', - text=>"Create Group"}); - $r->print(&Apache::lonhtmlcommon::breadcrumbs - (undef,'Create Group','Course_Create_Group')); - if (! exists($env{'form.state'})) { - &first_creation_form($r); - } elsif ($env{'form.state'} eq 'pick_members') { - &second_creation_form($r); - } elsif ($env{'form.state'} eq 'complete') { - &completed_creation($r); + my %functions = ( + email => 'E-mail', + discussion => 'Discussion boards', + chat => 'Chat', + files => 'File repository', + roster => 'Membership roster', + homepage => 'Group home page', + ); + + my %idx = (); + $idx{id} = &Apache::loncoursedata::CL_ID(); + $idx{fullname} = &Apache::loncoursedata::CL_FULLNAME(); + $idx{udom} = &Apache::loncoursedata::CL_SDOM(); + $idx{uname} = &Apache::loncoursedata::CL_SNAME(); + + my $rowColor1 = "#dddddd"; + my $rowColor2 = "#eeeeee"; + + my $action = $env{'form.action'}; + my $state = $env{'form.state'}; + if ((!defined($action)) || ($action eq 'view')) { + if (!defined($state)) { + $state = 'view'; + } + } + if ($action eq 'create' || $action eq 'modify' || $action eq 'view') { + if ($view_permission || $manage_permission) { + &group_administration($r,$action,$state,$cdom,$cnum,$function, + $tabcol,\%functions,\%idx,$view_permission, + $manage_permission,$rowColor1,$rowColor2); } else { - &first_creation_form($r); + $r->print(&mt('You do not have group administration '. + 'privileges in this course')); } + } else { + &print_main_menu($r,$cdom,$cnum,$function,$tabcol,\%functions,\%idx, + $view_permission,$manage_permission,$action,$state, + $rowColor1,$rowColor2); } - $r->print(&footer()); return OK; } -sub header { - my $html=&Apache::lonxml::xmlbegin(); - my $bodytag=&Apache::loncommon::bodytag('Course Groups Manager'); - my $title = &mt('LON-CAPA Groups Manager'); - return(< -$title - -$bodytag -
-ENDHEAD +sub print_main_menu { + my ($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,$view_permission, + $manage_permission,$action,$state,$rowColor1,$rowColor2) = @_; + my $jscript = qq| +function changeSort(caller) { + document.$state.sortby.value = caller; + document.$state.submit(); +}\n|; + $r->print(&header('Course Groups',$jscript,$action,$state, + undef,$function)); + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/coursegroups", + text=>"Course Groups",}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Groups')); + &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx, + $view_permission,$manage_permission,$action,$state, + $rowColor1,$rowColor2); + $r->print(&footer()); + return; } -sub print_main_menu { - my ($r,$manage_permission,$view_permission)=@_; - my @menu = - ( - { text => 'Create a new group', - help => 'Course_Create_Group', - action => 'create', - permission => $manage_permission, - }, - { text => 'Modify an existing group', - help => 'Course_Modify_Group', - action => 'modify', - permission => $manage_permission, - }, - { text => 'Delete an existing group', - help => 'Course_Delete_Group', - action => 'delete', - permission => $manage_permission, - }, - { text => 'Enter an existing group', - help => 'Course_Display_Group', - action => 'display', - permission => $view_permission, - }, - ); - my $menu_html = ''; - foreach my $menu_item (@menu) { - next if (! $menu_item->{'permission'}); - $menu_html.='

'; - $menu_html.=''; - if (exists($menu_item->{'url'})) { - $menu_html.=qq{}; +sub display_groups { + my ($r,$cdom,$cnum,$function,$tabcol,$functions,$idx,$view_permission, + $manage_permission,$action,$state,$rowColor1,$rowColor2) = @_; + my %curr_groups = (); + my %grp_info = (); + my %actionlinks = ( + modify => ' ' + + $lt{'act'} + $lt{'gname'} + $lt{'desc'} + $lt{'crea'} + + $lt{'crtd'} + + $lt{'last'} + + $lt{'func'} + + $lt{'quot'} + $lt{'memb'} + $lt{'file'} + $lt{'dibd'} + $lt{'dius'} + +END + my %Sortby = (); + foreach my $group (sort(keys(%curr_groups))) { + %{$grp_info{$group}} = + &Apache::longroup::get_group_settings( + $curr_groups{$group}); + my $members_result = &group_members($cdom,$cnum,$group, + \%grp_info); + my $files_result = &group_files($group,\%grp_info); + if ($env{'form.sortby'} eq 'groupname') { + push(@{$Sortby{$group}},$group); + } elsif ($env{'form.sortby'} eq 'description') { + push(@{$Sortby{$grp_info{$group}{'description'}}}, + $group); + } elsif ($env{'form.sortby'} eq 'creator') { + push(@{$Sortby{$grp_info{$group}{'creator'}}},$group); + } elsif ($env{'form.sortby'} eq 'creation') { + push(@{$Sortby{$grp_info{$group}{'creation'}}},$group); + } elsif ($env{'form.sortby'} eq 'modified') { + push(@{$Sortby{$grp_info{$group}{'modified'}}},$group); + } elsif ($env{'form.sortby'} eq 'quota') { + push(@{$Sortby{$grp_info{$group}{'quota'}}},$group); + } elsif ($env{'form.sortby'} eq 'totalmembers') { + push(@{$Sortby{$grp_info{$group}{'totalmembers'}}}, + $group); + } elsif ($env{'form.sortby'} eq 'totalfiles') { + push(@{$Sortby{$grp_info{$group}{'totalfiles'}}},$group); + } elsif ($env{'form.sortby'} eq 'boards') { + push(@{$Sortby{$grp_info{$group}{'boards'}}},$group); + } elsif ($env{'form.sortby'} eq 'diskuse') { + push(@{$Sortby{$grp_info{$group}{'diskuse'}}},$group); + } else { + push(@{$Sortby{$group}},$group); + } + } + my $rowNum = 0; + my $rowColor; + foreach my $key (sort(keys(%Sortby))) { + foreach my $group (@{$Sortby{$key}}) { + if ($rowNum %2 == 1) { + $rowColor = $rowColor1; + } else { + $rowColor = $rowColor2; + } + my $description = + &Apache::lonnet::unescape($grp_info{$group}{'description'}); + my $creator = $grp_info{$group}{'creator'}; + my $creation = $grp_info{$group}{'creation'}; + my $modified = $grp_info{$group}{'modified'}; + my $quota = $grp_info{$group}{'quota'}; + my $totalmembers = $grp_info{$group}{'totalmembers'}; + my $totalfiles = $grp_info{$group}{'totalfiles'}; + my $boards = $grp_info{$group}{'boards'}; + my $diskuse = $grp_info{$group}{'diskuse'}; + my $functionality; + foreach my $tool (sort(keys(%{$functions}))) { + if ($grp_info{$group}{functions}{$tool} eq 'on') { + $functionality .= ' '.$tool; + } + } + if (!$functionality) { + $functionality = &mt('None available'); + } + my $link = $actionlinks{$action}; + if ($action eq 'modify' || $action eq 'delete') { + $link .= $group; + } else { + $link .= $group.'/grppg'; + } + $link .= '">'.$lt{$action}.''; + if ($action eq 'view') { + if (($manage_permission) && + ($env{'form.refpage'} ne 'enrl')) { + $link .= '  '.$actionlinks{'modify'}. + $group.'">'.$lt{'modify'}.''; + } + } + $r->print(''.$link.''.$group.''.$description.''.$creator.''. &Apache::lonnavmaps::timeToHumanString($creation).''. &Apache::lonnavmaps::timeToHumanString($modified).''.$functionality.''.$quota.''.$totalmembers.''.$totalfiles.''.$boards.''.$diskuse.''); + $rowNum ++; + } + } + $r->print(''); + $r->print(&Apache::lonhtmlcommon::end_pick_box()); + $r->print(''); + if ($action eq 'view') { + if (!defined($state)) { + $state = 'view'; + } + $r->print(''); + } } else { - $menu_html.= - qq{}; + $r->print($lt{'nogr'}); + if ($manage_permission) { + $r->print('

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

'.$lt{'crng'}); + + } } - $menu_html.= &mt($menu_item->{'text'}).'
'; - if (exists($menu_item->{'help'})) { - $menu_html.= - &Apache::loncommon::help_open_topic($menu_item->{'help'}); + } else { + my @coursegroups = split(/:/,$env{'request.course.groups'}); + if (@coursegroups > 0) { + $r->print('

'); + my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum); + if (%curr_groups) { + foreach my $group (@coursegroups) { + my %group_info = &Apache::longroup::get_group_settings( + $curr_groups{$group}); + my $description = &Apache::lonnet::unescape( + $group_info{description}); + my ($uname,$udom) = split(/:/,$group_info{creator}); + $r->print(''.$group,'
'.$description.'

'); + } + } + } else { + $r->print(&mt('You are not currently a member of any '. + 'active groups in this course')); } - $menu_html.='

'.$/; } - $r->print($menu_html); return; } +sub group_administration { + my ($r,$action,$state,$cdom,$cnum,$function,$tabcol,$functions,$idx, + $view_permission,$manage_permission,$rowColor1,$rowColor2) = @_; + my %sectioncount = (); + my @tools = (); + my @types = (); + my @roles = (); + my @sections = (); + my %users = (); + my %userdata = (); + my @members = (); + my %usertools = (); + my %stored = (); + my %memchg; + my @member_changes = ('deletion','expire','activate','reenable', + 'changefunc','changepriv'); + my ($groupname,$description,$startdate,$enddate,$granularity,$specificity); + + if (defined($env{'form.groupname'})) { + $groupname = $env{'form.groupname'}; + } + + if (($action eq 'create') && ($state eq '')) { + $state = 'pick_name'; + } + if (($action eq 'create') || + (($action eq 'modify') && ($state eq 'chgresult'))) { + ($startdate,$enddate) = &get_dates_from_form(); + if (defined($env{'form.description'})) { + $description = $env{'form.description'}; + } + if (defined($env{'form.tool'})) { + @tools=&Apache::loncommon::get_env_multiple('form.tool'); + } + if (defined($env{'form.granularity'})) { + $granularity=$env{'form.granularity'}; + } + if (defined($env{'form.specificity'})) { + $specificity=$env{'form.specificity'}; + } + + } + if (($action eq 'create') || (($action eq 'modify') + && (($state eq 'pick_privs') || ($state eq 'addresult')))) { + if (defined($env{'form.member'})) { + @members = &Apache::loncommon::get_env_multiple('form.member'); + foreach my $user (@members) { + %{$usertools{$user}} = (); + } + } + } + + if ($action eq 'modify') { + if ($state eq '') { + if (defined($env{'form.groupname'})) { + $state = 'pick_task'; + } else { + $state = 'pick_group'; + } + } else { + %stored = &retrieve_settings($cdom,$cnum,$groupname); + if (ref($stored{'types'}) eq 'ARRAY') { + @types = @{$stored{'types'}}; + } + if (ref($stored{'roles'}) eq 'ARRAY') { + @roles = @{$stored{'roles'}}; + } + if (ref($stored{'sectionpick'}) eq 'ARRAY') { + @sections = @{$stored{'sectionpick'}}; + } + unless ($state eq 'chgresult') { + if (ref($stored{'tool'}) eq 'ARRAY') { + @tools = @{$stored{'tool'}}; + } + $startdate = $stored{'startdate'}; + $enddate = $stored{'enddate'}; + $description = $stored{'description'}; + $granularity = $stored{'granularity'}; + $specificity = $stored{'specificity'}; + } + } + } + + my %toolprivs = (); + %{$toolprivs{'email'}} = ( + sgm => 'Send group mail', + sgb => 'Broadcast mail', + ); + %{$toolprivs{'discussion'}} = ( + cgb => 'Create boards', + pgd => 'Post', + pag => 'Anon. posts', + rgi => 'Get identities', + vgb => 'View boards', + ); + %{$toolprivs{'chat'}} = ( + pgc => 'Chat', + ); + %{$toolprivs{'files'}} = ( + rgf => 'Retrieve', + ugf => 'Upload', + dgf => 'Delete', + ); + %{$toolprivs{'roster'}} = ( + vgm => 'View', + ); + %{$toolprivs{'homepage'}} = ( + vgh => 'View page', + mgh => 'Modify page', + ); + my %fixedprivs = (); + %{$fixedprivs{'email'}} = ('sgm' => 1); + %{$fixedprivs{'discussion'}} = ('vgb' => 1); + %{$fixedprivs{'chat'}} = ('pgc' => 1); + %{$fixedprivs{'files'}} = ('rgf' => 1); + %{$fixedprivs{'roster'}} = ('vgm' => 1); + %{$fixedprivs{'homepage'}} = ('vgh' => 1); + + my %elements = (); + %{$elements{'create'}} = (); + %{$elements{'modify'}} = (); + %{$elements{'create'}{'pick_name'}} = ( + startdate_month => 'selectbox', + startdate_hour => 'selectbox', + enddate_month => 'selectbox', + enddate_hour => 'selectbox', + startdate_day => 'text', + startdate_year => 'text', + startdate_minute => 'text', + startdate_second => 'text', + enddate_day => 'text', + enddate_year => 'text', + enddate_minute => 'text', + enddate_second => 'text', + groupname => 'text', + description => 'text', + tool => 'checkbox', + granularity => 'radio', + no_end_date => 'checkbox', + ); + %{$elements{'modify'}{'change_settings'}} = ( + %{$elements{'create'}{'pick_name'}}, + specificity => 'radio', + defpriv => 'checkbox', + autorole => 'checkbox', + autoadd => 'radio', + autodrop => 'radio', + ); + if (ref($stored{'autorole'}) eq 'ARRAY') { + foreach my $role (@{$stored{'autorole'}}) { + unless ($role eq 'cc') { + $elements{'modify'}{'change_settings'}{'sec_'.$role} = + 'selectbox'; + } + } + } + %{$elements{'create'}{'pick_members'}} = ( + member => 'checkbox', + defpriv => 'checkbox', + ); + + %{$elements{'modify'}{'add_members'}} = ( + types => 'selectbox', + roles => 'selectbox', + ); + + if (($action eq 'create') && ($state eq 'pick_name')) { + $elements{'create'}{'pick_name'}{'types'} = 'selectbox'; + $elements{'create'}{'pick_name'}{'roles'} = 'selectbox'; + } + if ((($action eq 'create') && + (($state eq 'pick_name') || ($state eq 'pick_privs'))) || + (($action eq 'modify') && (($state eq 'change_settings') || + ($state eq 'add_members')))) { + %sectioncount = &Apache::loncommon::get_sections($cdom,$cnum); + if (%sectioncount) { + $elements{'create'}{'pick_name'}{'sectionpick'} = 'selectbox'; + $elements{'modify'}{'change_mapping'}{'sectionpick'} = 'selectbox'; + $elements{'modify'}{'add_members'}{'sectionpick'} = 'selectbox'; + } + } + + if (($action eq 'create') || + ($action eq 'modify' && $state eq 'pick_members')) { + if (defined($env{'form.types'})) { + @types=&Apache::loncommon::get_env_multiple('form.types'); + } + if (defined($env{'form.roles'})) { + @roles=&Apache::loncommon::get_env_multiple('form.roles'); + } + if (defined($env{'form.sectionpick'})) { + @sections=&Apache::loncommon::get_env_multiple('form.sectionpick'); + if (grep/^all$/,@sections) { + @sections = sort {$a cmp $b} keys(%sectioncount); + } + } + } + + if (($state eq 'pick_members') || ($state eq 'pick_privs') || ($state eq 'change_privs')) { + &build_members_list($cdom,$cnum,\@types,\@roles,\@sections,\%users, + \%userdata); + } + if ($state eq 'pick_members') { + if ((keys(%users) > 0) && (@tools > 0)) { + if ($granularity eq 'Yes') { + $elements{$action}{'pick_members'}{'togglefunc'} = 'checkbox'; + } + foreach my $tool (@tools) { + if ($granularity eq 'Yes') { + $elements{$action}{'pick_members'}{'user_'.$tool} = 'checkbox'; + } + } + $elements{$action}{'pick_members'}{'specificity'} = 'radio'; + } + } + if ($state eq 'change_members') { + my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum, + $groupname); + my $now = time; + my $num_expire = 0; + my $num_activate = 0; + my $num_reenable = 0; + my $num_deletion = 0; + my $numusers = 0; + foreach my $key (sort(keys(%membership))) { + if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) { + my $user = $1; + my($end,$start,@userprivs) = split(/:/,$membership{$key}); + unless ($start == -1) { + $numusers ++; + $num_deletion ++; + if (($end > 0) && ($end < $now)) { + $num_reenable ++; + next; + } elsif (($start > $now)) { + $num_activate = 1; + next; + } else { + $num_expire ++; + next; + } + next; + } + if ($num_reenable && $num_activate && $num_expire) { + last; + } + } + } + if ($num_deletion) { + $elements{$action}{'change_members'}{'deletion'} = 'checkbox'; + } + if ($num_expire) { + $elements{$action}{'change_members'}{'expire'} = 'checkbox'; + } + if ($num_activate) { + $elements{$action}{'change_members'}{'activate'} = 'checkbox'; + } + if ($num_reenable) { + $elements{$action}{'change_members'}{'reenable'} = 'checkbox'; + } + if ($numusers) { + if ($granularity eq 'Yes') { + $elements{$action}{'change_members'}{'togglefunc'} = 'checkbox'; + } + foreach my $tool (@tools) { + if ($granularity eq 'Yes') { + $elements{$action}{'change_members'}{'user_'.$tool} = 'checkbox'; + } + } + if ($specificity eq 'Yes') { + $elements{$action}{'change_members'}{'changepriv'} = 'checkbox'; + } + } + } + + if (($state eq 'pick_privs') || ($state eq 'change_privs') || + (($specificity eq 'No') && + ($state eq 'memresult' || $state eq 'result' || $state eq 'addresult'))) { + foreach my $tool (@tools) { + my @values = &Apache::loncommon::get_env_multiple('form.user_'.$tool); + foreach my $user (@values) { + if ($state eq 'pick_privs' || $state eq 'result' + || $state eq 'addresult') { + if (!grep(/^\Q$user\E$/,@members)) { + next; + } + } + unless(exists($usertools{$user}{$tool})) { + $usertools{$user}{$tool} = 1; + } + } + } + } + + if (($action eq 'modify') && (($state eq 'change_privs') || ($state eq 'memresult'))) { + foreach my $chg (@member_changes) { + if (defined($env{'form.'.$chg})) { + @{$memchg{$chg}} = &Apache::loncommon::get_env_multiple('form.'.$chg); + } + } + + if ($state eq 'change_privs') { + my %membership = &Apache::lonnet::get_group_membership($cdom,$cnum, + $groupname); + my $now = time; + foreach my $key (sort(keys(%membership))) { + if ($key =~ /^\Q$groupname\E:([^:]+:[^:]+)$/) { + my $user = $1; + my $changefunc = 0; + my ($end,$start,@userprivs) = split(/:/,$membership{$key}); + unless ($start == -1) { + if (($end > 0) && ($end < $now)) { + unless (grep/^$user$/,$memchg{'reenable'}) { + next; + } + } + my @currtools = (); + if (@userprivs > 0) { + foreach my $tool (sort(keys(%fixedprivs))) { + foreach my $priv (keys(%{$fixedprivs{$tool}})) { + if (grep/^$priv$/,@userprivs) { + push(@currtools,$tool); + last; + } + } + } + } + foreach my $tool (@currtools) { + if (keys(%{$usertools{$user}}) > 0) { + if (!$usertools{$user}{$tool}) { + push(@{$memchg{'changefunc'}},$user); + $changefunc = 1; + last; + } + } else { + push(@{$memchg{'changefunc'}},$user); + $changefunc = 1; + } + } + if ($changefunc) { + next; + } + if (keys(%{$usertools{$user}}) > 0) { + foreach my $tool (keys(%{$usertools{$user}})) { + if (!grep/^$tool$/,@currtools) { + push(@{$memchg{'changefunc'}},$user); + $changefunc = 1; + last; + } + } + } + } + } + } + &check_changes(\@member_changes,\%memchg); + my %temptools; + foreach my $change (@member_changes) { + if (($change eq 'deletion') || ($change eq 'expire')) { + next; + } + foreach my $user (@{$memchg{$change}}) { + unless (exists($usertools{$user})) { + %{$usertools{$user}} = (); + } + %{$temptools{$user}} = %{$usertools{$user}}; + } + } + %usertools = %temptools; + } elsif ($state eq 'memresult') { + foreach my $change (@member_changes) { + if ($change eq 'expire' || $change eq 'deletion') { + next; + } + if (ref($memchg{$change}) eq 'ARRAY') { + my @users = @{$memchg{$change}}; + foreach my $user (@users) { + unless (exists($usertools{$user})) { + %{$usertools{$user}} = (); + } + } + } + } + } + } + + if ((($state eq 'pick_privs') || ($state eq 'change_privs')) + && ($specificity eq 'Yes')) { + foreach my $user (sort(keys(%usertools))) { + foreach my $tool (keys(%{$usertools{$user}})) { + foreach my $priv (keys(%{$toolprivs{$tool}})) { + unless (exists($fixedprivs{$tool}{$priv})) { + $elements{$action}{$state}{'userpriv_'.$priv} = 'checkbox'; + } + } + } + } + } + + my $jscript = &Apache::loncommon::check_uncheck_jscript(); + $jscript .= qq| +function nextPage(formname,nextstate) { + formname.state.value= nextstate; + formname.submit(); +} +function backPage(formname,prevstate) { + formname.state.value = prevstate; + formname.submit(); +} +function changeSort(caller) { + document.$state.state.value = '$state'; + document.$state.sortby.value = caller; + document.$state.submit(); +} + +|; + $jscript .= &Apache::lonhtmlcommon::set_form_elements( + \%{$elements{$action}{$state}},\%stored); + my $page = 0; + my %states = (); + my %branchstates = (); + @{$states{'create'}} = ('pick_name','pick_members','pick_privs','result'); + @{$states{'modify'}} = ('pick_group','pick_task'); + @{$branchstates{'noprivs'}} = ('result'); + @{$branchstates{'settings'}} = ('change_settings','chgresult'); + @{$branchstates{'members'}} = ('change_members','change_privs','memresult'); + @{$branchstates{'adds'}} = ('add_members','pick_members','pick_privs', + 'addresult'); + + if (defined($env{'form.branch'})) { + push (@{$states{$action}},@{$branchstates{$env{'form.branch'}}}); + } + + if (($action eq 'create') || ($action eq 'modify')) { + my $done = 0; + my $i=0; + while ($i<@{$states{$action}} && !$done) { + if ($states{$action}[$i] eq $state) { + $page = $i; + $done = 1; + } + $i++; + } + } + + my $loaditems = &onload_action($action,$state); + $r->print(&header('Course Groups Manager', + $jscript,$action,$state,$page,$function,$loaditems)); + + if ($env{'form.refpage'} eq 'enrl') { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/dropadd", + text=>"Enrollment Manager", + faq=>9,bug=>'Instructor Interface',}); + } else { + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/coursegroups", + text=>"Course Groups", + faq=>9,bug=>'Instructor Interface',}); + } + + my %trail = (); + %{$trail{'create'}} = &Apache::lonlocal::texthash ( + pick_name => 'Group Settings', + pick_members => 'Select Members', + pick_privs => 'Choose Privileges', + result => 'Creation Complete', + ); + %{$trail{'modify'}} = &Apache::lonlocal::texthash( + pick_group => 'Groups', + pick_task => 'Choose Task', + change_settings => 'Group Settings', + change_members => 'Modify/Delete Members', + change_privs => 'Change Privileges', + change_mapping => 'Membership Mapping', + add_members => 'Add Members', + pick_members => 'Select Members', + pick_privs => 'Choose Privileges', + chgresult => 'Setting Changes Complete', + memresult => 'Modifications Complete', + addresult => 'Additions Complete', + ); + my %navbuttons = &Apache::lonlocal::texthash( + gtns => 'Go to next step', + gtps => 'Go to previous step', + crgr => 'Create group', + mose => 'Modify settings', + gtpp => 'Go to previous page', + adme => 'Add members', + ); + if ((($action eq 'create') || ($action eq 'modify')) && + ($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 + ('Course Groups Manager')); + &display_control($r,$cdom,$cnum,$tabcol,$action,$state,$page, + \%sectioncount,$groupname,$description,$functions, + \@tools,\%toolprivs,\%fixedprivs,$startdate,$enddate, + \%users,\%userdata,$idx,\%memchg,\%usertools, + $function,$view_permission,$manage_permission, + \%stored,$granularity,$specificity,\@types,\@roles, + \@sections,\%states,\%navbuttons,$rowColor1,$rowColor2); + last; + } else { + 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( + {href=>"javascript:backPage(document.$state,'$states{$action}[$i]')", + text=>"$trail{$action}{$states{$action}[$i]}"}); + } + } + } + } elsif (($action eq 'view') && ($view_permission)) { + &Apache::lonhtmlcommon::add_breadcrumb( + {text=>"View groups"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs + ('Course Groups Manager')); + &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx, + $view_permission,$manage_permission,$action,$state, + $rowColor1,$rowColor2); + + } + $r->print(&footer()); + return; +} + +sub retrieve_settings { + my ($cdom,$cnum,$groupname) = @_; + my %curr_groups = &Apache::longroup::coursegroups($cdom,$cnum,$groupname); + + return if (!%curr_groups); + + my %groupinfo = + &Apache::longroup::get_group_settings($curr_groups{$groupname}); + + my %stored; + + $stored{'description'} = + &Apache::lonnet::unescape($groupinfo{'description'}); + $stored{'startdate'} = $groupinfo{'startdate'}; + $stored{'enddate'} = $groupinfo{'enddate'}; + if ($stored{'enddate'} == 0) { + $stored{'no_end_date'} = 1; + } + $stored{'granularity'} = $groupinfo{'granularity'}; + $stored{'specificity'} = $groupinfo{'specificity'}; + $stored{'creation'} = $groupinfo{'creation'}; + $stored{'creator'} = $groupinfo{'creator'}; + + foreach my $tool (sort(keys(%{$groupinfo{'functions'}}))) { + if ($groupinfo{functions}{$tool} eq 'on') { + push(@{$stored{tool}},$tool); + } + } + foreach my $role (@{$groupinfo{'roles'}}) { + push(@{$stored{roles}},$role); + } + foreach my $type (@{$groupinfo{'types'}}) { + push(@{$stored{types}},$type); + } + foreach my $section (@{$groupinfo{'sectionpick'}}) { + push(@{$stored{sectionpick}},$section); + } + foreach my $defpriv (@{$groupinfo{'defpriv'}}) { + push(@{$stored{defpriv}},$defpriv); + } + $stored{'autoadd'} = $groupinfo{'autoadd'}; + $stored{'autodrop'} = $groupinfo{'autodrop'}; + if (exists($groupinfo{'autosec'})) { + 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) { + push(@{$stored{'autorole'}},$role); + } + } + } + } + return %stored; +} + +sub display_control { + my ($r,$cdom,$cnum,$tabcol,$action,$state,$page,$sectioncount,$groupname, + $description,$functions,$tools,$toolprivs,$fixedprivs,$startdate, + $enddate,$users,$userdata,$idx,$memchg,$usertools,$function, + $view_permission,$manage_permission,$stored,$granularity,$specificity, + $types,$roles,$sections,$states,$navbuttons,$rowColor1,$rowColor2)=@_; + if ($action eq 'create') { + if ($state eq 'pick_name') { + &general_settings_form($r,$cdom,$cnum,$action,$tabcol,$state,$page, + $functions,$tools,$toolprivs,$fixedprivs, + $sectioncount,$stored,$states,$navbuttons, + $rowColor1,$rowColor2); + } elsif ($state eq 'pick_members') { + &choose_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $groupname,$description,$granularity, + $startdate,$enddate,$tools,$fixedprivs, + $toolprivs,$functions,$users,$userdata,$idx, + $stored,$states,$navbuttons,$rowColor1, + $rowColor2); + } elsif ($state eq 'pick_privs') { + &choose_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $startdate,$enddate,$tools,$functions, + $toolprivs,$fixedprivs,$userdata,$usertools, + $idx,$states,$stored,$sectioncount,$navbuttons, + $rowColor1,$rowColor2); + } elsif ($state eq 'result') { + &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $groupname,$description,$specificity,$userdata, + $startdate,$enddate,$tools,$functions, + $toolprivs,$usertools,$idx,$types,$roles, + $sections,$states,$navbuttons,$memchg, + $sectioncount,$stored,$rowColor1,$rowColor2); + } + } elsif ($action eq 'modify') { + my $groupname = $env{'form.groupname'}; + if ($state eq 'pick_group') { + &display_groups($r,$cdom,$cnum,$function,$tabcol,$functions,$idx, + $view_permission,$manage_permission,$action,$state, + $rowColor1,$rowColor2); + } elsif ($state eq 'pick_task') { + &modify_menu($r,$groupname,$page); + } elsif ($state eq 'change_settings') { + &general_settings_form($r,$cdom,$cnum,$action,$tabcol,$state,$page, + $functions,$tools,$toolprivs,$fixedprivs, + $sectioncount,$stored,$states,$navbuttons, + $rowColor1,$rowColor2); + } elsif ($state eq 'change_members') { + &change_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $groupname,$description,$startdate,$enddate, + $tools,$fixedprivs,$functions,$users, + $userdata,$granularity,$specificity,$idx, + $states,$navbuttons,$rowColor1,$rowColor2); + } elsif ($state eq 'add_members') { + &add_members_form($r,$tabcol,$action,$state,$page,$startdate, + $enddate,$groupname,$description,$granularity, + $sectioncount,$tools,$functions,$stored,$states, + $navbuttons,$rowColor1,$rowColor2); + } elsif ($state eq 'pick_members') { + &choose_members_form($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $groupname,$description,$granularity, + $startdate,$enddate,$tools,$fixedprivs, + $toolprivs,$functions,$users,$userdata,$idx, + $stored,$states,$navbuttons,$rowColor1, + $rowColor2); + } elsif ($state eq 'pick_privs') { + &choose_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $startdate,$enddate,$tools,$functions, + $toolprivs,$fixedprivs,$userdata,$usertools, + $idx,$states,$stored,$sectioncount,$navbuttons, + $rowColor1,$rowColor2); + } elsif ($state eq 'change_privs') { + &change_privs_form($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $startdate,$enddate,$tools,$functions, + $toolprivs,$fixedprivs,$userdata,$usertools, + $memchg,$idx,$states,$stored,$sectioncount, + $navbuttons,$rowColor1,$rowColor2); + } elsif ($state eq 'chgresult' || $state eq 'memresult' || + $state eq 'addresult') { + &process_request($r,$cdom,$cnum,$tabcol,$action,$state,$page, + $groupname,$description,$specificity,$userdata, + $startdate,$enddate,$tools,$functions, + $toolprivs,$usertools,$idx,$types,$roles, + $sections,$states,$navbuttons,$memchg, + $sectioncount,$stored,$rowColor1,$rowColor2); + } + } +} + +sub header { + my ($bodytitle,$jscript,$action,$state,$page,$function,$loaditems) = @_; + my $start_page= + &Apache::loncommon::start_page($bodytitle, + '', + {'function' => $function, + 'add_entries' => $loaditems,}); + my $output = <<"END"; +$start_page + + +END + if ($action eq 'create' || $action eq 'modify') { + $output .= <<"END"; + + + + +END + } + return $output; +} + +sub onload_action { + my ($action,$state) = @_; + my %loaditems; + if ((defined($env{'form.origin'})) && ($action eq 'create') && + ($state eq 'pick_name' || $state eq 'pick_members' || + $state eq 'pick_privs')) { + unless ($env{'form.origin'} eq '') { + $loaditems{'onload'} = + 'javascript:setFormElements(document.'.$state.')'; + } + } + if (($action eq 'modify') && + ($state eq 'change_settings' || $state eq 'change_members' || + $state eq 'change_privs' || $state eq 'add_members' || + $state eq 'pick_members')) { + $loaditems{'onload'} = + 'javascript:setFormElements(document.'.$state.')'; + } + return \%loaditems; +} + sub footer { + my $end_page = &Apache::loncommon::end_page(); return(< - - +$end_page ENDFOOT - } -sub first_creation_form { - my ($r) = @_; - my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; +sub build_members_list { + my ($cdom,$cnum,$types,$roles,$sections,$users,$userdata) = @_; + my %access = (); + foreach my $role (@{$roles}) { + %{$$users{$role}} = (); + } + foreach my $type (@{$types}) { + $access{$type} = $type; + } + &Apache::loncommon::get_course_users($cdom,$cnum,\%access,$roles, + $sections,$users,$userdata); + return; +} + +sub group_files { + return; +} + +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 $now = time; + 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 ++; + } elsif (($start!=0) && ($start>$now)) { + $future ++; + } else { + $active ++; + } + } + } + if ($totalmembers == 0) { + $$group_info{$group}{'totalmembers'} = 'None'; + } else { + $$group_info{$group}{'totalmembers'} = $active.' - active
'.$previous.' -previous
'.$future.' -future'; + } + return 'ok'; +} + + +sub general_settings_form { + my ($r,$cdom,$cnum,$action,$tabcol,$formname,$page,$functions,$tools, + $toolprivs,$fixedprivs,$sectioncount,$stored,$states,$navbuttons, + $rowColor1,$rowColor2) = @_; + my ($nexttext,$prevtext); + $r->print('
+ +'); + &groupsettings_options($r,$tabcol,$functions,$action,$formname,$stored,1); + $r->print(' + + + '); + &access_date_settings($r,$tabcol,$action,$formname,$stored,2); + $r->print(' + + + '); + if ($action eq 'create') { + &membership_options($r,$action,$formname,$tabcol,$sectioncount,3); + $nexttext = $$navbuttons{'gtns'}; + } else { + my @available = (); + my @unavailable = (); + &check_tools($functions,$tools,\@available,\@unavailable); + @{$tools} = sort(keys(%{$functions})); + &privilege_specificity($r,$tabcol,$rowColor1,$rowColor2,$action, + 3,$tools,$stored,$toolprivs,$fixedprivs, + \@available,$formname); + $r->print(' + + + '); + &mapping_options($r,$action,$formname,$page,$tabcol,$sectioncount, + $states,$stored,$navbuttons,4,5,$rowColor1, + $rowColor2); + $nexttext = $$navbuttons{'mose'}; + } + $prevtext = $$navbuttons{'gtpp'}; + &display_navbuttons($r,$formname,$$states{$action}[$page-1],$prevtext, + $$states{$action}[$page+1],$nexttext); + $r->print(' +
 
 
 
'); + return; +} + +sub groupsettings_options { + my ($r,$tabcol,$functions,$action,$formname,$stored,$image) = @_; my %lt = &Apache::lonlocal::texthash( - 'gmem' => 'Group membership options', - 'picr' => 'Pick the criteria to use to build a list of course users from which you will select members of the new group', 'gdat' => 'Group open and close dates', 'sten' => 'Set a start date/time and end date/time for the group', - 'acst' => 'Active/Inactive status', - 'coro' => 'Course roles', - 'cose' => 'Course sections', 'gfun' => 'Group functionality', + 'gnde' => 'Group name, description and available functionality', + 'desc' => 'Description', + 'func' => 'Functionality', + 'gnam' => 'Group Name', + 'doyo' => 'Do you want to assign different functionality '. + 'to different group members?', ); + &topic_bar($r,$tabcol,$image,$lt{'gnde'}); + $r->print(' + +   + + + + + + + + + + + + +END + my $numitems = keys(%{$functions}); + my $halfnum = int($numitems/2); + my $remnum = $numitems%2; + if ($remnum) { + $halfnum ++; + } + my @allfunctions = sort(keys (%{$functions})); + for (my $i=0; $i<$halfnum; $i++) { + $r->print(' + '); + } + $r->print(''); + for (my $j=$halfnum; $j<@allfunctions; $j++) { + $r->print(' + '); + } + if ($remnum) { + $r->print(''); + } + $r->print(' + + + + + + +
'.$lt{'gnam'}.': +'); + if ($action eq 'create') { + $r->print(''); + } else { + $r->print(''.$env{'form.groupname'}); + } + $r->print(<<"END"); +
$lt{'desc'}: +
$lt{'func'}:  '. + '
     + +
Granularity:'.$lt{'doyo'}.'  '); + if ($action eq 'modify') { + $r->print('  ('.&mt('Currently set to "[_1]"', + $$stored{'granularity'}).')'); + } + $r->print(' +
+ + +'); + return; +} +sub membership_options { + my ($r,$action,$state,$tabcol,$sectioncount,$image) = @_; + my %lt = &Apache::lonlocal::texthash( + 'pipa' => 'Pick parameters to generate membership list', + 'gmem' => 'Group membership options', + 'picr' => 'Pick the criteria to use to build a list of '. + 'course users from which you will select ', + 'meof' => 'members of the new group.', + 'admg' => 'additional members of the group.', + 'ifno' => 'If you do not wish to add members when you first '. + 'create the group, do not make any selections.', + 'asub' => 'A subsequent step will also allow you to specify automatic adding/dropping of group members triggered by specified role and section changes.', + 'acty' => 'Access types', + 'coro' => 'Course roles', + 'cose' => 'Course sections', + ); my %status_types = ( active => &mt('Currently has access'), previous => &mt('Previously had access'), @@ -181,56 +1257,2343 @@ sub first_creation_form { my @roles = ('st','cc','in','ta','ep','cr'); - my %sectioncount = (); - my @sections = (); - my $section_sel = ''; - my $numvisible; - my $numsections = &Apache::loncommon::get_sections($cdom,$cnum, - \%sectioncount); - - @sections = sort {$a cmp $b} keys(%sectioncount); - unshift(@sections,'all'); # Put 'all' at the front of the list - if ($numsections < 4) { - $numvisible = $numsections + 1; + my @sections = keys(%{$sectioncount}); + + &topic_bar($r,$tabcol,$image,$lt{'pipa'}); + $r->print(' + +   + + '.$lt{'gmem'}.'
'.$lt{'picr'}); + if ($action eq 'create') { + $r->print($lt{'meof'}.'
'.$lt{'ifno'}.'
'.$lt{'asub'}); + } else { + $r->print($lt{'admg'}); + } + $r->print(' +
+
+ + + + + '); + if (@sections >0) { + $r->print(' + + + '); + } + $r->print(''); + $r->print(&Apache::lonhtmlcommon::status_select_row(\%status_types)); + $r->print(''); + $r->print(&Apache::lonhtmlcommon::role_select_row(\@roles)); + if (@sections > 0) { + @sections = sort {$a cmp $b} @sections; + unshift(@sections,'all'); # Put 'all' at the front of the list + unshift(@sections,'none'); # Put 'no sections' next + $r->print(' + '); + } + $r->print(' + +
'.$lt{'acty'}.' '.$lt{'coro'}.' '.$lt{'cose'}.' 
  '. + §ions_selection(\@sections,'sectionpick').'
+ + '); + return; +} + +sub sections_selection { + my ($sections,$elementname) = @_; + my $section_sel; + my $numvisible = 4; + if (@{$sections} < 4) { + $numvisible = @{$sections}; + } + foreach my $sec (@{$sections}) { + if ($sec eq 'all') { + $section_sel .= '