--- loncom/interface/courseprefs.pm 2010/02/21 16:02:09 1.24 +++ loncom/interface/courseprefs.pm 2010/03/08 14:41:01 1.25 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.24 2010/02/21 16:02:09 raeburn Exp $ +# $Id: courseprefs.pm,v 1.25 2010/03/08 14:41:01 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -273,6 +273,7 @@ sub handler { idnu => 'Community ID or number', desc => 'Community Description', ownr => 'Community Owner', + cown => 'Community Co-owners', catg => 'Categorize community', excc => 'Exclude from community catalog', clon => 'Users allowed to clone community', @@ -299,6 +300,7 @@ sub handler { idnu => 'Course ID or number', desc => 'Course Description', ownr => 'Course Owner', + cown => 'Course Co-owners', catg => 'Categorize course', excc => 'Exclude from course catalog', clon => 'Users allowed to clone course', @@ -342,19 +344,20 @@ sub handler { 'courseinfo' => { text => $lt{'gens'}, help => 'Course_Environment', - ordered => ['owner','description','courseid','categories', - 'hidefromcat','externalsyllabus', + ordered => ['owner','co-owners','description','courseid', + 'categories','hidefromcat','externalsyllabus', 'cloners','url','rolenames'], itemtext => { - owner => $lt{'ownr'}, - description => $lt{'desc'}, - courseid => $lt{'idnu'}, - categories => $lt{'catg'}, - hidefromcat => $lt{'excc'}, - cloners => $lt{'clon'}, - externalsyllabus => 'URL of Syllabus', - url => 'Top Level Map', - rolenames => $lt{'rept'}, + 'owner' => $lt{'ownr'}, + 'co-owners' => $lt{'cown'}, + 'description' => $lt{'desc'}, + 'courseid' => $lt{'idnu'}, + 'categories' => $lt{'catg'}, + 'hidefromcat' => $lt{'excc'}, + 'cloners' => $lt{'clon'}, + 'externalsyllabus' => 'URL of Syllabus', + 'url' => 'Top Level Map', + 'rolenames' => $lt{'rept'}, }, }, 'localization' => @@ -755,6 +758,80 @@ sub process_changes { } } } + } elsif ($entry eq 'co-owners') { + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $coowners = $values->{'internal.co-owners'}; + my @currcoown; + if ($coowners) { + @currcoown = split(',',$coowners); + } + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + my $autocoowner; + if (($crstype eq 'Course') && + ($values->{'internal.coursecode'})) { + my %domconf = + &Apache::lonnet::get_dom('configuration',['autoenroll'],$cdom); + if (ref($domconf{'autoenroll'}) eq 'HASH') { + $autocoowner = $domconf{'autoenroll'}{'co-owners'}; + } + } + unless ($autocoowner) { + my @keepcoowners = &Apache::loncommon::get_env_multiple('form.coowners'); + my @pendingcoowners = &Apache::loncommon::get_env_multiple('form.pendingcoowners'); + my @invitecoowners = &Apache::loncommon::get_env_multiple('form.invitecoowners'); + if (@invitecoowners) { + push(@pendingcoowners,@invitecoowners); + } + $newvalues{'pendingco-owners'} = join(',',sort(@pendingcoowners)); + $newvalues{'co-owners'} = join(',',sort(@keepcoowners)); + if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) { + $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'}; + push(@{$changes->{$entry}{'changed'}},'co-owners'); + } + if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) { + $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'}; + push(@{$changes->{$entry}{'changed'}},'pendingco-owners'); + } + } + } else { + my (@newpending,@newcoown); + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + my $pendingcoowners = $values->{'internal.pendingco-owners'}; + my @pendingcoown = split(',',$pendingcoowners); + if ($env{'form.pending_coowoner'}) { + foreach my $item (@pendingcoown) { + unless ($item eq $uname.':'.$udom) { + push(@newpending,$item); + } + } + @newcoown = @currcoown; + if ($env{'form.pending_coowoner'} eq 'accept') { + unless (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { + push(@newcoown,$uname.':'.$udom); + } + } + } elsif ($env{'form.remove_coowoner'}) { + foreach my $item (@currcoown) { + unless ($item eq $uname.':'.$udom) { + push(@newcoown,$item); + } + } + if ($pendingcoowners ne '') { + @newpending = @pendingcoown; + } + } + $newvalues{'pendingco-owners'} = join(',',sort(@newpending)); + $newvalues{'co-owners'} = join(',',sort(@newcoown)); + if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) { + $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'}; + push(@{$changes->{$entry}{'changed'}},'co-owners'); + } + if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) { + $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'}; + push(@{$changes->{$entry}{'changed'}},'pendingco-owners'); + } + } } elsif ($entry =~ /^default_enrollment_(start|end)_date$/) { $newvalues{$entry}=&Apache::lonhtmlcommon::get_date_from_form($entry); } elsif ($entry eq 'rolenames') { @@ -971,8 +1048,10 @@ sub process_changes { } else { $newvalues{$entry} = $env{'form.'.$entry}; } - if ($newvalues{$entry} ne $values->{$entry}) { - $changes->{$entry} = $newvalues{$entry}; + unless ($entry eq 'co-owners') { + if ($newvalues{$entry} ne $values->{$entry}) { + $changes->{$entry} = $newvalues{$entry}; + } } } } @@ -1095,7 +1174,10 @@ sub store_changes { next if (!exists($changes->{$item}{$key})); my ($displayname,$text); $text = $prefs->{$item}->{'itemtext'}{$key}; - my $displayval = $changes->{$item}{$key}; + my $displayval; + unless ($key eq 'co-owners') { + $displayval = $changes->{$item}{$key}; + } if ($item eq 'feedback') { if ($key =~ /^(question|policy|comment)(\.email)\.text$/) { $text = $prefs->{$item}->{'itemtext'}{$1.$2}; @@ -1162,7 +1244,48 @@ sub store_changes { $displayval = &mt('No'); } } - if ($changes->{$item}{$key} eq '') { + if ($key eq 'co-owners') { + if (ref($changes->{$item}{$key}) eq 'HASH') { + if (ref($changes->{$item}{$key}{'changed'}) eq 'ARRAY') { + foreach my $type ('co-owners','pendingco-owners') { + next unless (grep(/^\Q$type\E$/,@{$changes->{$item}{$key}{'changed'}})); + if ($type eq 'pendingco-owners') { + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $displayname = &mt('Invited as co-owners, pending acceptance'); + } + } + if ($changes->{$item}{$key}{$type} eq '') { + push(@delkeys,'internal.'.$type); + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + ''.$displayname.'')).'
  • '; + } + } elsif (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $displayval = join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } split(',',$changes->{$item}{$key}{$type})); + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + ''.$displayname.'', + "'$displayval'")).'
  • '; + } + } + } + unless (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + if ($env{'form.pending_coowoner'} eq 'accept') { + $displayval = &mt('on'); + } elsif ($env{'form.pending_coowoner'} eq 'decline') { + $displayval = ''; + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Invitation to be co-owner declined')).'
  • '; + } elsif ($env{'form.remove_coowoner'}) { + $displayval = &mt('off'); + } + if ($displayval) { + $displayname = &mt('Your co-ownership status'); + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + ''.$displayname.'', + "'$displayval'")).'
  • '; + } + } + } + } elsif ($changes->{$item}{$key} eq '') { push(@delkeys,$key); $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', ''.$displayname.'')).'
  • '; @@ -1177,7 +1300,18 @@ sub store_changes { } $output .= ''; } - $storehash{$key} = $changes->{$item}{$key}; + if ($key eq 'co-owners') { + if (ref($changes->{$item}{$key}) eq 'HASH') { + if (ref($changes->{$item}{$key}{'changed'}) eq 'ARRAY') { + foreach my $type ('co-owners','pendingco-owners') { + next unless (grep(/^\Q$type\E$/,@{$changes->{$item}{$key}{'changed'}})); + $storehash{'internal.'.$type} = $changes->{$item}{$key}{$type}; + } + } + } + } else { + $storehash{$key} = $changes->{$item}{$key}; + } } if ($key eq 'cloners') { # Get existing cloners @@ -1190,7 +1324,8 @@ sub store_changes { } } if (($key eq 'description') || ($key eq 'cloners') || - ($key eq 'hidefromcat') || ($key eq 'categories')) { + ($key eq 'hidefromcat') || ($key eq 'categories') || + ($key eq 'co-owners')) { push(@need_env_update,$key); } } @@ -1264,6 +1399,16 @@ sub update_env { &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.'.$key => $storehash->{$key}}); $crsinfo{$env{'request.course.id'}}{$key} = $storehash->{$key}; $count ++; + } elsif ($key eq 'co-owners') { + if ($storehash->{'internal.co-owners'} ne '') { + &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.internal.co-owners' => $storehash->{'internal.co-owners'}}); + } + if ($storehash->{'internal.pendingco-owners'} ne '') { + &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.internal.pendingco-owners' => $storehash->{'internal.pendingco-owners'}}); + } + my @coowners = split(',',$storehash->{'internal.'.$key}); + $crsinfo{$env{'request.course.id'}}{'co-owners'} = \@coowners; + $count ++; } } if ($count) { @@ -1478,9 +1623,9 @@ sub print_courseinfo { unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } - my ($cathash,$categoriesform); + my ($cathash,$categoriesform,$autocoowner); my %domconf = - &Apache::lonnet::get_dom('configuration',['coursecategories'],$cdom); + &Apache::lonnet::get_dom('configuration',['coursecategories','autoenroll'],$cdom); if (ref($domconf{'coursecategories'}) eq 'HASH') { $cathash = $domconf{'coursecategories'}{'cats'}; if (ref($cathash) eq 'HASH') { @@ -1489,6 +1634,9 @@ sub print_courseinfo { $settings->{'categories'},$crstype)."\n"; } } + if (ref($domconf{'autoenroll'}) eq 'HASH') { + $autocoowner = $domconf{'autoenroll'}{'co-owners'}; + } if (!defined($categoriesform)) { $categoriesform = &mt('No categories defined in this domain.'); } @@ -1521,6 +1669,9 @@ sub print_courseinfo { 'owner' => { text => ''.&mt($itemtext->{'owner'}).'', }, + 'co-owners' => { + text => ''.&mt($itemtext->{'co-owners'}).'', + }, 'courseid' => { text => ''.&mt($itemtext->{'courseid'}).'
    '.'('. &mt('internal, optional').')', @@ -1697,6 +1848,26 @@ sub print_courseinfo { } my $domdesc = &Apache::lonnet::domain($cdom,'description'); $datatable .= $owner; + } elsif ($item eq 'co-owners') { + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $coowners = $env{'course.'.$env{'request.course.id'}.'.internal.co-owners'}; + my @currcoown; + if ($coowners) { + @currcoown = split(',',$coowners); + } + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) { + $datatable .= &show_autocoowners(@currcoown); + } else { + $datatable .= &coowner_invitations($cnum,$cdom,@currcoown); + } + } else { + if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) { + $datatable .= &show_autocoowners(@currcoown); + } else { + $datatable .= &manage_coownership($cnum,$cdom,@currcoown); + } + } } else { $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); } @@ -1854,6 +2025,128 @@ ENDSCRIPT return; } +sub show_autocoowners { + my (@currcoown) = @_; + my $output = ''.&mt('Co-ownership is set automatically when a Course Coordinator role is assigned to official course personnel (from institutional data).').''; + if (@currcoown > 0) { + $output .= '
    '.&mt('Current co-owners are:').' '. + join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + } else { + $output .= '
    '.&mt('Currently no co-owners.'); + } + return $output; +} + +sub coowner_invitations { + my ($cnum,$cdom,@currcoown) = @_; + my ($output,@pendingcoown,@othercoords); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + my $ccrole = 'cc'; + my %ccroles = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,undef,[$ccrole]); + foreach my $key (sort(keys(%ccroles))) { + my ($ccname,$ccdom,$role) = split(':',$key); + next if ($key eq $env{'user.name'}.':'.$env{'user.domain'}.':'.$ccrole); + unless (grep(/^\Q$ccname\E:\Q$ccdom\E$/,@currcoown,@pendingcoown)) { + push(@othercoords,$ccname.':'.$ccdom); + } + } + my $coowner_rows = @currcoown + @pendingcoown + @othercoords; + if ($coowner_rows) { + $output .= &Apache::loncommon::start_data_table(); + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Current co-owners').''; + foreach my $person (@currcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if ($pendingcoowners) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invited as co-owners [_1](agreement pending)','
    ').'
    '; + foreach my $person (@pendingcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if (@othercoords) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invite other Coordinators [_1]to become co-owners','
    ').'
    '; + foreach my $person (@othercoords) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + } else { + $output = &mt('There are no coordinators to select as co-owners'); + } + return $output; +} + +sub manage_coownership { + my ($cnum,$cdom,@currcoown) = @_; + my (@pendingcoown); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + my ($is_coowner,$is_pending,$output); + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + if (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { + $is_coowner = 1; + } + if (grep(/^\Q$uname\E:\Q$udom\E$/,@pendingcoown)) { + $is_pending = 1; + } + if (@currcoown && ($is_coowner || $is_pending)) { + $output = &Apache::loncommon::start_data_table(); + } + if (@currcoown) { + if ($is_coowner || $is_pending) { + $output .= &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row().''; + } + $output .= &mt('Current co-owners are:').' '. + join(', ', map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + if ($is_coowner || $is_pending) { + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + if ($is_coowner || $is_pending) { + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row().''; + } + $output .= ''; + if ($is_coowner) { + $output .= &mt('You are currently a co-owner:').' '; + } else { + $output .= &mt('The course owner has invited you to become a co-owner:').' '.(' 'x2). + ''; + } + $output .= ''; + if (@currcoown) { + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + if (@currcoown && ($is_coowner || $is_pending)) { + $output .= &Apache::loncommon::end_data_table(); + } + return $output; +} + sub print_localization { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) {