--- loncom/interface/loncoursegroups.pm 2005/10/27 23:32:27 1.1 +++ loncom/interface/loncoursegroups.pm 2013/07/22 18:06:51 1.118 @@ -1,3 +1,6 @@ +# The LearningOnline Network with CAPA +# +# $Id: loncoursegroups.pm,v 1.118 2013/07/22 18:06:51 bisitz Exp $ # # Copyright Michigan State University Board of Trustees # @@ -26,209 +29,4239 @@ 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::Constants qw(:common :http); +use LONCAPA::map(); +use lib '/home/httpd/lib/perl/'; +use LONCAPA; 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/community groups"; return HTTP_NOT_ACCEPTABLE; } + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, + ['action','refpage','state','groupname','branch']); + 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'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')); my $manage_permission = - &Apache::lonnet::allowed('mdg',$env{'request.course.id'}); + &Apache::lonnet::allowed('mdg',$env{'request.course.id'}.($env{'request.course.sec'}?'/'.$env{'request.course.sec'}:'')); + &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) { + my $gpterm = &Apache::loncommon::group_term(); + my $ucgpterm = $gpterm; + $ucgpterm =~ s/^(\w)/uc($1)/e; + my $crstype = &Apache::loncommon::course_type(); + + my %functions = ( + email => 'Send Messages', + discussion => 'Discussion Boards', + chat => 'Chat Room', + files => 'Group Portfolio', + roster => 'Membership Roster', + homepage => $ucgpterm.' 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(); + $idx{section} = &Apache::loncoursedata::CL_SECTION(); + + my $action = $env{'form.action'}; + my $state = $env{'form.state'}; + 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' || + $action eq 'delete' || $action eq 'reenable') { + if ($view_permission || $manage_permission) { + if ($state eq 'view') { + &print_main_menu($r,$cdom,$cnum,\%functions,\%idx, + $view_permission,$manage_permission, + $action,$state,$gpterm,$ucgpterm,$crstype); + } else { + &group_administration($r,$action,$state,$cdom,$cnum, + \%functions,\%idx,$view_permission, + $manage_permission,$gpterm,$ucgpterm, + $crstype); + } + } else { + $r->print('
' + .&mt('You are not currently a member of any active '.$gpterm.'s' + .' in this '.lc($crstype).'.') + .'
' + ); + } + } + return; +} + +sub group_administration { + my ($r,$action,$state,$cdom,$cnum,$functions,$idx,$view_permission, + $manage_permission,$gpterm,$ucgpterm,$crstype) = @_; + 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, + $quota,$validate_script); + + 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 (defined($env{'form.quota'})) { + $quota=$env{'form.quota'}; + } + } + 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 { + %stored = &retrieve_settings($cdom,$cnum,$groupname,$action); + 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'}; + $quota = $stored{'quota'}; + } + } + } + + my $toolprivs = &Apache::longroup::get_tool_privs($gpterm); + + my $fixedprivs = &Apache::longroup::get_fixed_privs(); + + my %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', + quota => 'text', + tool => 'checkbox', + granularity => 'radio', + no_end_date => 'checkbox', + }, + pick_members => { + member => 'checkbox', + defpriv => 'checkbox', + }, + }, + ); + + $elements{'modify'} = { + change_settings => { + %{$elements{'create'}{'pick_name'}}, + specificity => 'radio', + defpriv => 'checkbox', + autorole => 'checkbox', + autoadd => 'radio', + autodrop => 'radio', + }, + add_members => { + types => 'selectbox', + roles => 'selectbox', + }, + }; + + if (ref($stored{'autorole'}) eq 'ARRAY') { + foreach my $role (@{$stored{'autorole'}}) { + unless (($role eq 'cc') || ($role eq 'co')) { + $elements{'modify'}{'change_settings'}{'sec_'.$role} = + '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); + $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 (($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 ++; + 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'; + } + } + } + } + } + + if (($action eq 'create' && $state eq 'pick_name') || + ($action eq 'modify' && $state eq 'change_settings')) { + my ($crsquota,$freespace,$maxposs) = &get_quota_constraints($action,\%stored); + my $space_trim = '/^\s*|\s*\$/g,""'; + my $float_check = '/^([0-9]*\.?[0-9]*)$/'; + $validate_script = ' + var newquota = new String(document.'.$state.'.quota.value); + newquota.replace('.$space_trim.'); + if (newquota == "" ) { + document.'.$state.'.quota.value = 0; + newquota = "0"; + } + var maxposs = '.sprintf("%.2f",$maxposs).'; + if (newquota > maxposs) { + alert("The group portfolio quota you entered for this group ("+newquota+" Mb) exceeds the maximum possible ("+maxposs+" Mb). Please enter a smaller number."); + return; + } + var re_quota = '.$float_check.'; + var check_quota = newquota.match(re_quota); + if (check_quota == null) { + alert("The quota you entered contains invalid characters, the quota should only include numbers, with or without a decimal point."); + return; + } + if (newquota == 0) { + var warn_zero = 0; + for (var i=0; i