--- loncom/interface/courseprefs.pm 2010/02/21 16:02:09 1.24 +++ loncom/interface/courseprefs.pm 2010/12/22 16:57:41 1.28.2.5 @@ -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.28.2.5 2010/12/22 16:57:41 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', @@ -318,6 +320,7 @@ sub handler { seme => 'Send message to student when clicking Done on Tasks', ); } + $lt{'lcrv'} = 'Required LON-CAPA version'; &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/courseprefs', text=>$lt{'conf'}}); my $breadcrumbs = @@ -342,24 +345,30 @@ sub handler { 'courseinfo' => { text => $lt{'gens'}, help => 'Course_Environment', - ordered => ['owner','description','courseid','categories', - 'hidefromcat','externalsyllabus', - 'cloners','url','rolenames'], + header => [{col1 => 'Setting', + col2 => 'Value'}], + ordered => ['owner','co-owners','loncaparev','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'}, + 'loncaparev' => $lt{'lcrv'}, }, }, 'localization' => - { text => 'Language & Time Localization', + { text => 'Language and Time Localization', help => 'Course_Environment', + header => [{col1 => 'Setting', + col2 => 'Value',}], ordered => ['languages','timezone','datelocale'], itemtext => { languages => 'Languages used', @@ -371,7 +380,9 @@ sub handler { { text => 'Feedback messages', help => 'Course_Environment', header => [{col1 => 'Questions about:', - col2 => 'Recipients'}], + col2 => 'Recipients'}, + {col1 => 'Questions about:', + col2 => 'Custom Text'}], ordered => ['question.email','comment.email','policy.email'], itemtext => { 'question.email' => 'Resource Content', @@ -382,15 +393,15 @@ sub handler { 'discussion' => { text => 'Discussion and Chat', help => 'Course_Environment', - ordered => ['plc.roles.denied','plc.users.denied', - 'pch.roles.denied','pch.users.denied', + ordered => ['pch.roles.denied','pch.users.denied', + 'plc.roles.denied','plc.users.denied', 'allow_limited_html_in_feedback', 'allow_discussion_post_editing'], itemtext => { - 'plc.roles.denied' => 'No Resource Discussion', - 'plc.users.denied' => 'No Resource Discussion', - 'pch.roles.denied' => 'No Chat room use', - 'pch.users.denied' => 'No Chat room use', + 'pch.roles.denied' => 'No Resource Discussion', + 'pch.users.denied' => 'No Resource Discussion', + 'plc.roles.denied' => 'No Chat room use', + 'plc.users.denied' => 'No Chat room use', allow_limited_html_in_feedback => 'Allow limited HTML in discussion', allow_discussion_post_editing => 'Users can edit/delete own discussion posts', }, @@ -407,19 +418,21 @@ sub handler { ordered => ['default_enrollment_start_date', 'default_enrollment_end_date', 'nothideprivileged','student_classlist_view', - 'student_opt_in','student_classlist_portfiles'], + 'student_classlist_opt_in','student_classlist_portfiles'], itemtext => { default_enrollment_start_date => 'Start date', default_enrollment_end_date => 'End date', nothideprivileged => $lt{'priv'}, student_classlist_view => $lt{'stuv'}, - student_opt_in => $lt{'stul'}, + student_classlist_opt_in => $lt{'stul'}, student_classlist_portfiles => 'Include link to accessible portfolio files', }, }, 'appearance' => { text => 'Display of resources ', help => 'Course_Environment', + header => [{col1 => 'Setting', + col2 => 'Value',}], ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', 'tthoptions'], @@ -434,6 +447,8 @@ sub handler { 'grading' => { text => 'Grading', help => 'Course_Environment', + header => [{col1 => 'Setting', + col2 => 'Value',}], ordered => ['grading','rndseed', 'receiptalg','disablesigfigs'], itemtext => { @@ -447,6 +462,8 @@ sub handler { 'printouts' => { text => 'Printout generation', help => 'Course_Environment', + header => [{col1 => 'Setting', + col2 => 'Value',}], ordered => ['problem_stream_switch','suppress_tries', 'default_paper_size','print_header_format', 'disableexampointprint','canuse_pdfforms'], @@ -462,6 +479,8 @@ sub handler { 'spreadsheet' => { text => 'Spreadsheets', help => 'Course_Environment', + header => [{col1 => 'Setting', + col2 => 'Value'}], ordered => ['spreadsheet_default_classcalc', 'spreadsheet_default_studentcalc', 'spreadsheet_default_assesscalc','hideemptyrows'], @@ -475,6 +494,8 @@ sub handler { 'bridgetasks' => { text => 'Bridge tasks', help => 'Course_Environment', + header => [{col1 => 'Setting', + col2 => 'Value'}], ordered => ['task_messages','task_grading', 'suppress_embed_prompt'], itemtext => { @@ -530,12 +551,17 @@ sub print_config_box { my $itemtext = $item->{'itemtext'}; my $rowtotal = 0; my $output = - '
'. + &mt($item->{text}).' '. + &Apache::loncommon::help_open_topic($item->{'help'}).' | '."\n". + '
---|
+ |
+ |||||||||||
|
+ |||||||||||
'; return ($output,$rowtotal); } @@ -676,6 +714,7 @@ sub process_changes { } } else { foreach my $entry (@ordered) { + next if (($entry eq 'loncaparev') || ($entry eq 'owner')); if ($entry eq 'cloners') { if ($env{'form.cloners_all'}) { $newvalues{$entry} = '*'; @@ -684,8 +723,8 @@ sub process_changes { if (exists($env{'form.cloners_activate'})) { my $actnum = $env{'form.cloners_activate'}; if ($actnum ne '') { - if ($env{'form.clonersdom_'.$actnum} ne '') { - my $clonedom = $env{'form.clonersdom_'.$actnum}; + if ($env{'form.cloners_dom_'.$actnum} ne '') { + my $clonedom = $env{'form.cloners_dom_'.$actnum}; if (&check_clone($clonedom,$disallowed) eq 'ok') { $newvalues{$entry} = '*:'.$clonedom; push(@clonedoms,$newvalues{$entry}); @@ -755,6 +794,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') { @@ -923,8 +1036,8 @@ sub process_changes { $hdr .= $env{'form.printfmthdr_limit_'.$i}; } $hdr .= $env{'form.printfmthdr_sub_'.$i}; - } elsif ($env{'form.printfmthdr_sub_'.$i} ne '') { - $hdr = $env{'form.printfmthdr_sub_'.$i}; + } elsif ($env{'form.printfmthdr_text_'.$i} ne '') { + $hdr = $env{'form.printfmthdr_text_'.$i}; } $newhdr[$env{'form.printfmthdr_pos_'.$i}] = $hdr; } @@ -971,8 +1084,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 +1210,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 +1280,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 .= ' '.'('. &mt('internal, optional').')', @@ -1532,14 +1718,12 @@ sub print_courseinfo { &mt('Owner and Coordinators included automatically'), input => 'textbox', size => '40', - advanced => 1 }, 'rolenames' => { text => ''.&mt($itemtext->{'rolenames'}).' '. '('.$replace.')', input => 'textbox', size => '20', - advanced => 1 }, 'externalsyllabus' => { text => ''.&mt($itemtext->{'externalsyllabus'}).' ('. @@ -1558,6 +1742,9 @@ sub print_courseinfo { input => 'textbox', size => '25', }, + 'loncaparev' => { + text => ''.&mt($itemtext->{'loncaparev'}).'', + }, ); my $datatable; my $count = 0; @@ -1568,11 +1755,7 @@ sub print_courseinfo { next if (!$can_categorize); } $count ++; - if (exists $items{$item}{advanced} && $items{$item}{advanced} == 1) { - $datatable .= &item_table_row_start($items{$item}{text},$count,"advanced"); - } else { - $datatable .= &item_table_row_start($items{$item}{text},$count); - } + $datatable .= &item_table_row_start($items{$item}{text},$count); if ($items{$item}{input} eq 'radio') { $datatable .= &yesno_radio($item,$settings); } elsif ($item eq 'cloners') { @@ -1695,8 +1878,36 @@ sub print_courseinfo { } else { $owner = &mt('None specified'); } - 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); + } + } + } elsif ($item eq 'loncaparev') { + my $loncaparev = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'}; + my $showreqd; + if ($loncaparev) { + $showreqd = &mt('[_1] or newer',$loncaparev); + } else { + $showreqd = &mt('No specific version required'); + } + $datatable .= $showreqd; } else { $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); } @@ -1854,6 +2065,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')) { @@ -1988,18 +2321,14 @@ sub print_feedback { foreach my $item (@{$ordered}) { $count ++; - if ($position eq 'top') { - $datatable .= &item_table_row_start($items{$item}{text},$count); - } else { - $datatable .= &item_table_row_start($items{$item}{text}."|||
'; if ($showsections) { @@ -2295,7 +2624,7 @@ sub role_checkboxes { $output .= ' | |||||||||||