--- loncom/interface/courseprefs.pm 2010/02/21 01:06:13 1.8.2.7 +++ loncom/interface/courseprefs.pm 2010/12/26 05:22:21 1.28.2.8 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.8.2.7 2010/02/21 01:06:13 raeburn Exp $ +# $Id: courseprefs.pm,v 1.28.2.8 2010/12/26 05:22:21 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -122,27 +122,27 @@ Creates table used to display and set co Inputs: $cdom,$items,$ordered,$settings,$rowtotal,$crstype where $cdom is course's domain, $items is HASH ref for current config -item, $ordered is ARRAY ref of items to include in row in +item, $ordered is ARRAY ref of items to include in row in display order, $settings is HASH ref of current values forrow, -$rowtotal is SCALAR ref used to accumulate row count, $crstype is +$rowtotal is SCALAR ref used to accumulate row count, $crstype is course type. Returns: $datatable -HTML mark-up of data table which accumulates individual rows. +HTML mark-up of data table which accumulates individual rows. =item nothidepriv_row() Creates row containing form elements used to display and set -whether Domain coordinators who are currently included in +whether Domain coordinators who are currently included in advanced course user .db file for a course are to be hidden (e.g., in syllabus, or from course user lists). Inputs: $cdom,$item,$settings,$crstype where $cdom is course domain, item is nothideprivileged, $settings is -HASH ref of the current values for nothideprivileged, $crstype is -course type (Course or Community). +HASH ref of the current values for nothideprivileged, $crstype is +course type (Course or Community). -Returns: $datatable +Return: $datatable HTML mark-up for Privileged users (Domain Coordinators) in staff listing. =item print_hdrfmt_row() @@ -163,7 +163,7 @@ for the "Print header format" row. =item position_selector() Creates a select box which can be used to reorder substitutions -and text included in a printout header. +and text included in a printout header. Inputs: $pos,$num,$maxnum where $pos is current position, $num is the unique identifier, @@ -171,23 +171,23 @@ and $maxnum is the total number of items and text in the printout header. Returns: $output -HTML mark-up for the selectbox and a hidden form element containing -the current position. +HTML mark-up for the selectbox and a hidden form element containing +the current position. =item substitution_selector() -Creates a combination of select box for choosing an item -(student name, course ID or assignment note) to substitute, +Creates a combination of select box for choosing an item +(student name, course ID or assignment note) to substitute, and a corresponding size limit in the header used for printouts. Inputs: $num,$subst,$limit,$crstype -where $num is the unique identifier, $subst is the current +where $num is the unique identifier, $subst is the current substitution (n,c or a, for name, course or note respectively, $limit is the current size limit (integer), and $crstype is course type - course or community. Returns: $output -HTML mark-up for selectbox and textbox (separate table cells). +HTML mark-up for selectbox and textbox (separate table cells). =item change_clone() @@ -272,6 +272,8 @@ sub handler { gens => 'General community settings', 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', @@ -297,6 +299,8 @@ sub handler { gens => 'General course settings', 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', @@ -316,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 = @@ -331,6 +336,14 @@ sub handler { return OK; } + if ($phase eq 'releaseinfo') { + my $loncaparev = $env{'course.'.$cid.'.internal.releaserequired'}; + if ($loncaparev) { + &display_loncaparev_constraints($r,$navmap,$loncaparev,$crstype); + return OK; + } + } + my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', @@ -342,22 +355,25 @@ sub handler { help => 'Course_Environment', header => [{col1 => 'Setting', col2 => 'Value'}], - ordered => ['description','courseid','categories', - 'hidefromcat','cloners','externalsyllabus', - 'url','rolenames'], + ordered => ['owner','co-owners','loncaparev','description', + 'courseid','categories','hidefromcat', + 'externalsyllabus','cloners','url','rolenames'], itemtext => { - 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/TimeZone/Locale', + { text => 'Language and Time Localization', help => 'Course_Environment', header => [{col1 => 'Setting', col2 => 'Value',}], @@ -385,18 +401,16 @@ sub handler { 'discussion' => { text => 'Discussion and Chat', help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], - 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', - allow_limited_html_in_feedback => 'Allow limited HTML in discussion posts', + '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', }, }, @@ -412,13 +426,13 @@ 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', }, }, @@ -426,12 +440,12 @@ sub handler { { text => 'Display of resources ', help => 'Course_Environment', header => [{col1 => 'Setting', - col2 => 'Value'}], + col2 => 'Value',}], ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', 'tthoptions'], itemtext => { - default_xml_style => 'Default XML Style File', + default_xml_style => 'Default XML style file', pageseparators => 'Visibly Separate Items on Pages', disable_receipt_display => 'Disable display of problem receipts', texengine => 'Force use of a specific math rendering engine', @@ -460,13 +474,14 @@ sub handler { col2 => 'Value',}], ordered => ['problem_stream_switch','suppress_tries', 'default_paper_size','print_header_format', - 'disableexampointprint'], + 'disableexampointprint','canuse_pdfforms'], itemtext => { problem_stream_switch => 'Allow problems to be split over pages', suppress_tries => 'Suppress number of tries in printing', default_paper_size => 'Default paper type', print_header_format => 'Print header format', disableexampointprint => 'Disable automatically printing point values on exams', + canuse_pdfforms => 'Users can print problems as PDF forms and upload later for grading', }, }, 'spreadsheet' => @@ -511,7 +526,7 @@ sub handler { \@prefs_order,\%prefs,\%values, $cnum,undef,\@allitems); } elsif ($phase eq 'display') { - my $jscript = &get_jscript($cdom,$phase,$crstype); + my $jscript = &get_jscript($cid,$cdom,$phase,$crstype); my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype); @@ -546,7 +561,7 @@ sub print_config_box { my $output = '<table class="LC_nested_outer"> <tr> - <th align="left" valign="middle"><span class="LC_font_larger">'. + <th align="left" valign="middle"><span class="LC_nobreak" style="font-size: larger;" >'. &mt($item->{text}).' '. &Apache::loncommon::help_open_topic($item->{'help'}).'</span></th>'."\n". '</tr>'; @@ -554,11 +569,15 @@ sub print_config_box { $output .= ' <tr> <td> - <table class="LC_nested"> - <tr class="LC_info_row"> + <table class="LC_nested">'; + if (exists $item->{'header'}->[0]->{'col1'} || + exists $item->{'header'}->[0]->{'col2'}) { + $output .= ' + <tr class="LC_info_row"> <td class="LC_left_item">'.&mt($item->{'header'}->[0]->{'col1'}).'</td> <td class="LC_right_item">'.&mt($item->{'header'}->[0]->{'col2'}).'</td> - </tr>'; + </tr>'; + } $rowtotal ++; if ($action eq 'feedback') { $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal); @@ -585,21 +604,29 @@ sub print_config_box { </tr> <tr> <td> - <table class="LC_nested"> - <tr class="LC_info_row"> - <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[2]->{'col1'}).'</td> - <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[2]->{'col2'}).'</td> - </tr>'; + <table class="LC_nested">'; + if (exists $item->{'header'}->[0]->{'col1'} || + exists $item->{'header'}->[0]->{'col2'}) { + $output .= ' + <tr class="LC_info_row"> + <td class="LC_left_item">'.&mt($item->{'header'}->[0]->{'col1'}).'</td> + <td class="LC_right_item">'.&mt($item->{'header'}->[0]->{'col2'}).'</td> + </tr>'; + } } } else { $output .= ' <tr> <td> - <table class="LC_nested"> - <tr class="LC_info_row"> + <table class="LC_nested">'; + if (exists $item->{'header'}->[0]->{'col1'} || + exists $item->{'header'}->[0]->{'col2'}) { + $output .= ' + <tr class="LC_info_row"> <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td> <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[0]->{'col2'}).'</td> - </tr>'; + </tr>'; + } } $rowtotal ++; if ($action eq 'courseinfo') { @@ -695,6 +722,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} = '*'; @@ -703,8 +731,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}); @@ -774,6 +802,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') { @@ -942,8 +1044,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; } @@ -990,8 +1092,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}; + } } } } @@ -1067,16 +1171,16 @@ sub store_changes { $output .= '<h3>'.&mt($prefs->{$item}{'text'}).'</h3>'; if (ref($changes->{$item}) eq 'HASH') { if (keys(%{$changes->{$item}}) > 0) { - $output .= &mt('Changes made:').'<ul>'; + $output .= &mt('Changes made:').'<ul style="list-style:none;">'; if ($item eq 'other') { foreach my $key (sort(keys(%{$changes->{$item}}))) { $storehash{$key} = $changes->{$item}{$key}; if ($changes->{$item}{$key} eq '') { push(@delkeys,$key); - $output .= '<li>'.&mt('Deleted setting for [_1]','<i>'.$key.'</i>').'</li>'; + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]','<i>'.$key.'</i>')).'</li>'; } else { - $output .= '<li>'.&mt('[_1] set to [_2]','<i>'.$key.'</i>', - "'$storehash{$key}'").'</li>'; + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]','<i>'.$key.'</i>', + "'$storehash{$key}'")).'</li>'; } } } else { @@ -1108,13 +1212,16 @@ sub store_changes { "'<b>".$newname."</b>'").'</li>'; } if ($msg ne '') { - $output .= '<li>'.&mt($displayname).'<ul>'.$msg.'</ul></li>'; + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt($displayname)).'<ul class="LC_success">'.$msg.'</ul></li>'; } } else { 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}; @@ -1168,33 +1275,91 @@ sub store_changes { if (defined($yesno{$key})) { $displayval = &mt('No'); if ($changes->{$item}{$key} eq 'yes') { - $displayval = &mt('Yes'); + $displayval = &mt('Yes'); } } elsif (($key =~ /^default_enrollment_(start|end)_date$/) && ($displayval)) { $displayval = &Apache::lonlocal::locallocaltime($displayval); } elsif ($key eq 'categories') { $displayval = $env{'form.categories_display'}; - } - if ($changes->{$item}{$key} eq '') { + } elsif ($key eq 'canuse_pdfforms') { + if ($changes->{$item}{$key} eq '1') { + $displayval = &mt('Yes'); + } elsif ($changes->{$item}{$key} eq '0') { + $displayval = &mt('No'); + } + } + 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 .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + '<i>'.$displayname.'</i>')).'</li>'; + } + } elsif (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $displayval = join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } split(',',$changes->{$item}{$key}{$type})); + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + '<i>'.$displayname.'</i>', + "'<b>$displayval</b>'")).'</li>'; + } + } + } + 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 .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Invitation to be co-owner declined')).'</li>'; + } elsif ($env{'form.remove_coowoner'}) { + $displayval = &mt('off'); + } + if ($displayval) { + $displayname = &mt('Your co-ownership status'); + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + '<i>'.$displayname.'</i>', + "'<b>$displayval</b>'")).'</li>'; + } + } + } + } elsif ($changes->{$item}{$key} eq '') { push(@delkeys,$key); - $output .= '<li>'.&mt('Deleted setting for [_1]', - '<i>'.$displayname.'</i>').'</li>'; + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + '<i>'.$displayname.'</i>')).'</li>'; } else { - $output .= '<li>'.&mt('[_1] set to [_2]', + $output .= '<li>'.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', '<i>'.$displayname.'</i>', - "'<b>$displayval</b>'"); + "'<b>$displayval</b>'")); if ($key eq 'url') { my $bkuptime=time; $output .= (' 'x2).&mt('(Previous URL backed up)').': '. - $storehash{'top level map backup '.$bkuptime} => $values->{$key}; + $storehash{'top level map backup '.$bkuptime} = $values->{$key}; } $output .= '</li>'; } - $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 - my %clonenames = + my %clonenames = &Apache::lonnet::dump('environment',$cdom,$cnum,'cloners'); if ($clonenames{'cloners'} =~ /,/) { @oldcloner = split(/\s*\,\s*/,$clonenames{'cloners'}); @@ -1203,7 +1368,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); } } @@ -1238,10 +1404,10 @@ sub store_changes { $output .= &mt('An error occurred when removing course settings which are no longer in use.'); } $output .= '</span>'; - } - } else { - foreach my $key (@delkeys) { - &Apache::lonnet::delenv('course.'.$cdom.'_'.$cnum.'.'.$key); + } else { + foreach my $key (@delkeys) { + &Apache::lonnet::delenv('course.'.$cdom.'_'.$cnum.'.'.$key); + } } } if (@need_env_update) { @@ -1277,6 +1443,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) { @@ -1379,9 +1555,9 @@ sub get_course { } sub get_jscript { - my ($cdom,$phase,$crstype) = @_; + my ($cid,$cdom,$phase,$crstype) = @_; my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype); - my ($jscript,$categorize_js); + my ($jscript,$categorize_js,$loncaparev_js); my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript(); my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset'); my $cloners_js = &cloners_javascript($phase); @@ -1398,9 +1574,23 @@ function catsbrowser() { } ENDSCRIPT } + my $loncaparev = $env{'course.'.$cid.'.internal.releaserequired'}; + if ($loncaparev) { + $loncaparev_js = <<ENDSCRIPT; +function loncaparevinfo() { + var lcrevwin = null; + var url = '/adm/courseprefs?phase=releaseinfo'; + if (!lcrevwin || lcrevwin.closed) { + lcrevwin=window.open(url,'releasewin','height=480,width=600,resizable=yes,scrollbars=yes,location=no,menubar=no,toolbar=no'); + } else { + lcrevwin.focus(); + } +} +ENDSCRIPT + } $jscript = '<script type="text/javascript" language="Javascript">'."\n". - $browse_js."\n".$categorize_js."\n".$cloners_js."\n".'</script>'. - "\n".$stubrowse_js."\n"; + $browse_js."\n".$categorize_js."\n".$loncaparev_js."\n". + $cloners_js."\n".'</script>'."\n".$stubrowse_js."\n"; return $jscript; } @@ -1491,9 +1681,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') { @@ -1502,6 +1692,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.'); } @@ -1530,6 +1723,12 @@ sub print_courseinfo { input => 'textbox', size => '25', }, + 'owner' => { + text => '<b>'.&mt($itemtext->{'owner'}).'</b>', + }, + 'co-owners' => { + text => '<b>'.&mt($itemtext->{'co-owners'}).'</b>', + }, 'courseid' => { text => '<b>'.&mt($itemtext->{'courseid'}).'</b><br />'.'('. &mt('internal, optional').')', @@ -1538,7 +1737,7 @@ sub print_courseinfo { }, 'cloners' => { text => '<b>'.&mt($itemtext->{'cloners'}).'</b><br />'. - &mt('Coordinators included automatically'), + &mt('Owner and Coordinators included automatically'), input => 'textbox', size => '40', }, @@ -1565,6 +1764,9 @@ sub print_courseinfo { input => 'textbox', size => '25', }, + 'loncaparev' => { + text => '<b>'.&mt($itemtext->{'loncaparev'}).'</b>', + }, ); my $datatable; my $count = 0; @@ -1610,7 +1812,6 @@ sub print_courseinfo { if (@entries > 0) { foreach my $entry (@entries) { my ($uname,$udom) = split(/:/,$entry); - my ($uname,$udom) = split(/:/,$entry); if ($udom =~ /^$match_domain$/) { unless (&Apache::lonnet::domain($udom)) { next; @@ -1689,6 +1890,47 @@ sub print_courseinfo { $datatable .= '<input type="hidden" name="categories" value="'.$settings->{$item}.'" />'. &Apache::lonhtmlcommon::textbox($item.'_display',$settings->{$item}, $items{$item}{size},$launcher); + } elsif ($item eq 'owner') { + my $owner = $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'}; + if ($owner =~ /:/) { + my ($ownername,$ownerdom) = split(':',$owner); + $owner = &Apache::loncommon::plainname($ownername,$ownerdom); + } elsif ($owner ne '') { + $owner = &Apache::loncommon::plainname($owner,$cdom); + } else { + $owner = &mt('None specified'); + } + $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).' <a href="javascript:loncaparevinfo()">'. + &mt('Details').'</a>'; + } else { + $showreqd = &mt('No specific version required'); + } + $datatable .= $showreqd; } else { $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); } @@ -1846,6 +2088,577 @@ ENDSCRIPT return; } +sub display_loncaparev_constraints { + my ($r,$navmap,$loncaparev,$crstype) = @_; + my $cid = $env{'request.course.id'}; + my $cdom = $env{'course.'.$cid.'.domain'}; + my $cnum = $env{'course.'.$cid.'.num'}; + my $output; + my %lt = &Apache::lonlocal::texthash ( + 'all' => 'all', + 'section/group' => 'section/group', + 'user' => 'user', + ); + my (%checkparms,%checkresponsetypes,%checkcrstypes,%anonsurvey,%randomizetry); + &Apache::loncommon::build_release_hashes(\%checkparms,\%checkresponsetypes, + \%checkcrstypes,\%anonsurvey,\%randomizetry); + if (defined($checkcrstypes{$crstype})) { + $output .= '<h4>'.&mt('Course type: [_1] requires [_2] or newer',$crstype, + $checkcrstypes{$crstype}).'</h4>'; + } + my (%fromparam,%rowspan,%bymap,%byresource,@scopeorder,%toshow,%allmaps, + %byresponsetype,%bysubmission); + @scopeorder = ('all','section/group','user'); + my $resourcedata = &Apache::lonparmset::readdata($cnum,$cdom); + if (ref($resourcedata) eq 'HASH') { + foreach my $key (keys(%{$resourcedata})) { + foreach my $item (keys(%checkparms)) { + if ($key =~ /(\Q$item\E)$/) { + if (ref($checkparms{$item}) eq 'ARRAY') { + my $value = $resourcedata->{$key}; + my ($middle,$scope,$which,$level,$map,$resource); + if (grep(/^\Q$value\E$/,@{$checkparms{$item}})) { + my $stdtype = &Apache::lonparmset::standard_parameter_types($item); + my $stdname = &Apache::lonparmset::standard_parameter_names($item); + my $valname = &get_param_description($stdtype,$value); + my $rev = $Apache::lonnet::needsrelease{'parameter:'.$item.':'.$value}; + my $start = $cid.'.'; + if ($key =~ /^\Q$start\E(\[useropt\:($match_username\:$match_domain)\]\.)/) { + $middle = $1; + $which = $2; + $scope = 'user'; + } elsif ($key =~ /^\Q$start\E(\[(\w+)\]\.)/) { + $middle = $1; + $which = $2; + $scope = 'section/group'; + } else { + $scope = 'all'; + } + my $what="$stdname=$valname"; + if ($key =~ /^\Q$start$middle\E\w+\.\Q$item\E$/) { + $level = 'general'; + if ($scope eq 'all') { + if (ref($fromparam{$rev}{$scope}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$fromparam{$rev}{$scope}})) { + push(@{$fromparam{$rev}{$scope}},$what); + } + } else { + push(@{$fromparam{$rev}{$scope}},$what); + } + } else { + if (ref($fromparam{$rev}{$scope}{$which}) eq 'ARRAY') { + unless (grep(/^\Q$what\E$/,@{$fromparam{$rev}{$scope}{$which}})) { + push(@{$fromparam{$rev}{$scope}{$which}},$what); + } + } else { + push(@{$fromparam{$rev}{$scope}{$which}},$what); + } + } + $rowspan{$rev} ++; + } elsif ($key =~ /^\Q$start$middle\E(.+)___\(all\).\w+\.\Q$item\E$/) { + $level = 'folder'; + $map = $1; + if ($scope eq 'all') { + if (ref($bymap{$map}{$rev}{$scope}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$bymap{$map}{$rev}{$scope}})) { + push(@{$bymap{$map}{$rev}{$scope}},$what); + } + } else { + push(@{$bymap{$map}{$rev}{$scope}},$what); + } + } else { + if (ref($bymap{$map}{$rev}{$scope}{$which}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$bymap{$map}{$rev}{$scope}{$which}})) { + push(@{$bymap{$map}{$rev}{$scope}{$which}},$what); + } + } else { + push(@{$bymap{$map}{$rev}{$scope}{$which}},$what); + } + } + } elsif ($key =~ /^\Q$start$middle\E(.+)\.\w+\.\Q$item\E$/) { + $level = 'resource'; + $resource = $1; + if ($scope eq 'all') { + if (ref($byresource{$resource}{$rev}{$scope}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$byresource{$resource}{$rev}{$scope}})) { + push(@{$byresource{$resource}{$rev}{$scope}},$what); + } + } else { + push(@{$byresource{$resource}{$rev}{$scope}},$what); + } + } else { + if (ref($byresource{$resource}{$rev}{$scope}{$which}) eq 'ARRAY') { + unless (grep(/^\Q$what\E$/,@{$byresource{$resource}{$rev}{$scope}{$which}})) { + push(@{$byresource{$resource}{$rev}{$scope}{$which}},$what); + } + } else { + push(@{$byresource{$resource}{$rev}{$scope}{$which}},$what); + } + } + } + } + } + } + } + } + if (keys(%fromparam)) { + $output .= '<h4>'.&mt('Requirements from general settings').'</h4>'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + '<th>'.&mt('Release').'</th><th>'.&mt('Scope').'</th>'. + '<th>'.&mt('Extent').'</th><th>'.&mt('Setting').'</th>'. + &Apache::loncommon::end_data_table_header_row(); + foreach my $rev (keys(%fromparam)) { + $output .= &Apache::loncommon::start_data_table_row(). + '<td rowspan="'.$rowspan{$rev}.'">'.$rev.'</td>'; + my $newrow; + foreach my $scope (@scopeorder) { + if (ref($fromparam{$rev}{$scope}) eq 'HASH') { + if ($newrow) { + $output .= &Apache::loncommon::continue_data_table_row(); + } + $output .= '<td>'.$lt{$scope}.'</td>'; + foreach my $which (sort(keys(%{$fromparam{$rev}{$scope}}))) { + $output .= '<td>'.$which.'</td><td>'. + join('<br />',@{$fromparam{$rev}{$scope}{$which}}).'</td>'; + } + $output .= &Apache::loncommon::end_data_table_row(); + $newrow = 1; + } elsif (ref($fromparam{$rev}{$scope}) eq 'ARRAY') { + if ($newrow) { + $output .= &Apache::loncommon::continue_data_table_row(); + } + $output .= '<td>'.$lt{$scope}.'</td><td> </td><td>'. + join('<br />',@{$fromparam{$rev}{$scope}}).'</td>'. + &Apache::loncommon::end_data_table_row(); + $newrow = 1; + } + } + } + $output .= &Apache::loncommon::end_data_table().'<br />'; + } + } + + if (defined($navmap)) { + my %anonsubms=&Apache::lonnet::dump('nohist_anonsurveys',$cdom,$cnum); + my $rev_anonsurv=$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'}; + my %randtrysubms=&Apache::lonnet::dump('nohist_randomizetry',$cdom,$cnum); + my $rev_randtry=$Apache::lonnet::needsrelease{'parameter:type:randomizetry'}; + my $stdtype=&Apache::lonparmset::standard_parameter_types('type'); + my $stdname=&Apache::lonparmset::standard_parameter_names('type'); + my $valanon=&get_param_description($stdtype,'anonsurvey'); + my $valrandtry=&get_param_description($stdtype,'randomizetry'); + + foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() },1,0)) { + my @parts = @{$res->parts()}; + my $symb = $res->symb(); + my $enclosing_map = &Apache::lonnet::declutter($res->enclosing_map_src()); + foreach my $part (@parts) { + if (exists($anonsubms{$symb."\0".$part})) { + my $rev = $rev_anonsurv; + my $what="$stdname=$valanon"; + if (ref($bysubmission{$symb}{$rev}) eq 'ARRAY') { + unless (grep(/^\Q$what\E/,@{$bysubmission{$symb}{$rev}})) { + push(@{$bysubmission{$symb}{$rev}},$what); + } + } else { + push(@{$bysubmission{$symb}{$rev}},$what); + } + $allmaps{$enclosing_map} = 1; + } + if (exists($randtrysubms{$symb."\0".$part})) { + my $rev = $rev_randtry; + my $what="$stdname=$valrandtry"; + if (ref($bysubmission{$symb}{$rev}) eq 'ARRAY') { + unless (grep(/^\Q$what\E/,@{$bysubmission{$symb}{$rev}})) { + push(@{$bysubmission{$symb}{$rev}},$what); + } + } else { + push(@{$bysubmission{$symb}{$rev}},$what); + } + $allmaps{$enclosing_map} = 1; + } + } + my %responses = $res->responseTypes(); + foreach my $key (keys(%responses)) { + if (exists($checkresponsetypes{$key})) { + push(@{$byresponsetype{$symb}{$checkresponsetypes{$key}}},$key); + $allmaps{$enclosing_map} = 1; + } + } + } + if (keys(%byresource) > 0) { + foreach my $symb (keys(%byresource)) { + my ($map,$resid,$resurl)=&Apache::lonnet::decode_symb($symb); + $allmaps{$map} = 1; + } + } + if (keys(%bymap) > 0) { + foreach my $map (keys(%bymap)) { + $allmaps{$map} = 1; + } + } + foreach my $map (keys(%allmaps)) { + my $mapres = $navmap->getResourceByUrl($map); + my $mapsymb = $mapres->symb(); + $toshow{$mapsymb} = 1; + if (ref($mapres)) { + my $pcslist = $mapres->map_hierarchy(); + if ($pcslist ne '') { + foreach my $pc (split(/,/,$pcslist)) { + my $res = $navmap->getByMapPc($pc); + if (ref($res)) { + my $symb = $res->symb(); + unless ($symb eq '______') { + $toshow{$symb} = 1; + } + } + } + } + } + } + } + my $mapres_header = '<h4>'. + &mt('Requirements for specific folders or resources'). + '</h4>'; + if ((keys(%toshow) > 0) || (keys(%byresource) > 0) || + (keys(%bysubmission) > 0) || (keys(%byresponsetype))) { + $output .= $mapres_header; + } + my $top_header = '<h3>'.&mt('LON-CAPA version dependencies').'</h3>'; + my $title = 'Version Constraints'; + my $start_page = + &Apache::loncommon::start_page($title,undef,{'only_body' => 1,}); + $r->print($start_page.$top_header); + if ($output) { + $r->print($output); + if (defined($navmap)) { + &show_contents_view($r,$navmap,$cid,\%toshow,\%bymap,\%byresource,\%bysubmission, + \%byresponsetype,\@scopeorder,\%lt); + } + $r->print('<br /><br />'); + } else { + $r->print('<p class="LC_info">'. + &mt('No version requirements from resource content or settings.'). + '</p>'); + } + $r->print(&Apache::loncommon::end_page()); + return; +} + +sub show_contents_view { + my ($r,$navmap,$cid,$toshow,$bymap,$byresource,$bysubmission,$byresponsetype, + $scopeorder,$lt) = @_; + if ((keys(%{$toshow}) > 0) || (keys(%{$byresource}) > 0) || + (keys(%{$bysubmission}) > 0) || (keys(%{$byresponsetype}) > 0)) { + my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons"); + my $whitespace = '<img src="'.$location.'/whitespace_21.gif" alt="" />'; + my $icon = '<img src="'.$location.'/navmap.folder.open.gif" alt="" />'; + my $topmap = $env{'course.'.$cid.'.url'}; + $r->print(&Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + '<th>'.&mt('Location').'</th><th>'.&mt('Release').'</th>'. + '<th>'.&mt('Attribute/Setting').'</th>'. + &Apache::loncommon::end_data_table_header_row(). + &Apache::loncommon::start_data_table_row(). + '<td> '.$icon.' '.&mt('Main Course Documents').'</td>'); + &releases_by_map($r,$bymap,$topmap,$scopeorder,$lt); + $r->print(&Apache::loncommon::end_data_table_row()); + my $it=$navmap->getIterator(undef,undef,undef,1,1,undef); + my $curRes; + my $depth = 0; + my %parent = (); + my $startcount = 5; + my $lastcontainer = $startcount; + while ($curRes = $it->next()) { + if ($curRes == $it->BEGIN_MAP()) { + $depth++; + $parent{$depth}= $lastcontainer; + } + if ($curRes == $it->END_MAP()) { + $depth--; + $lastcontainer = $parent{$depth}; + } + my $indent; + for (my $i=0; $i<$depth; $i++) { + $indent.= $whitespace; + } + if (ref($curRes)) { + my $symb = $curRes->symb(); + my $ressymb = $symb; + my $srcf = $curRes->src(); + my $title = &Apache::lonnet::gettitle($srcf); + if (($curRes->is_sequence()) || ($curRes->is_page())) { + next unless($toshow->{$symb}); + my ($parent,$ind,$url) = &Apache::lonnet::decode_symb($symb); + $icon = '<img src="'.$location.'/navmap.folder.open.gif" alt="" />'; + if ($curRes->is_page()) { + $icon = '<img src="'.$location.'/navmap.page.open.gif" alt="" />'; + } + my $rowspan = 1; + if (ref($bymap->{$url}) eq 'HASH') { + $rowspan = scalar(keys(%{$bymap->{$url}})); + } + $r->print(&Apache::loncommon::start_data_table_row(). + '<td rowspan="'.$rowspan.'">'.$indent.$icon.' '.$title.'</td>'); + &releases_by_map($r,$bymap,$url,$scopeorder); + $r->print(&Apache::loncommon::end_data_table_row()); + } else { + my $rowspan; + if (ref($byresource->{$symb}) eq 'HASH') { + $rowspan += scalar(keys(%{$byresource->{$symb}})); + } + if (ref($bysubmission->{$symb}) eq 'HASH') { + $rowspan += scalar(keys(%{$bysubmission->{$symb}})); + } + if (ref($byresponsetype->{$symb}) eq 'HASH') { + $rowspan += scalar(keys(%{$byresponsetype->{$symb}})); + } + next if (!$rowspan); + $icon = '<img class="LC_contentImage" src="'.$location.'/problem.gif" alt="'. + &mt('Problem').'" />'; + $r->print(&Apache::loncommon::start_data_table_row(). + '<td rowspan="'.$rowspan.'">'.$indent.$icon.' '.$title.'</td>'); + my $newrow; + if (ref($byresource->{$symb}) eq 'HASH') { + foreach my $rev (sort(keys(%{$byresource->{$symb}}))) { + if ($newrow) { + $r->print(&Apache::loncommon::continue_data_table_row()); + } + $r->print('<td valign="middle">'.$rev.'</td><td>'); + if (ref($byresource->{$symb}{$rev}) eq 'HASH') { + $r->print('<table border="0">'); + foreach my $scope (@{$scopeorder}) { + if (ref($byresource->{$symb}{$rev}{$scope}) eq 'HASH') { + $r->print('<tr><td>'.&mt('Setting - scope: [_1]',$lt->{$scope}).'</td>'); + foreach my $which (sort(keys(%{$byresource->{$symb}{$rev}{$scope}}))) { + $r->print('<td>'.$which.'</td><td>'. + join('<br />',@{$byresource->{$symb}{$rev}{$scope}{$which}}). + '</td>'); + } + $r->print('</tr>'); + } elsif (ref($byresource->{$symb}{$rev}{$scope}) eq 'ARRAY') { + $r->print('<tr><td>'.&mt('Setting - scope: [_1]',$lt->{$scope}).'</td>'. + '<td> </td><td>'. + join('<br />',@{$byresource->{$symb}{$rev}{$scope}}).'</td></tr>'); + } + } + $r->print('</table>'); + } + $r->print('</td>'); + $r->print(&Apache::loncommon::end_data_table_row()); + $newrow = 1; + } + } + if (ref($bysubmission->{$symb}) eq 'HASH') { + foreach my $rev (sort(keys(%{$bysubmission->{$symb}}))) { + if ($newrow) { + $r->print(&Apache::loncommon::continue_data_table_row()); + } + $r->print('<td>'.$rev.'</td><td>'); + if (ref($bysubmission->{$symb}{$rev}) eq 'ARRAY') { + $r->print(&mt('Submissions to: ').' '. + join(', ',@{$bysubmission->{$symb}{$rev}})); + } + $r->print('</td>'); + $r->print(&Apache::loncommon::end_data_table_row()); + $newrow = 1; + } + } + if (ref($byresponsetype->{$symb}) eq 'HASH') { + foreach my $rev (sort(keys(%{$byresponsetype->{$symb}}))) { + if ($newrow) { + $r->print(&Apache::loncommon::continue_data_table_row()); + } + $r->print('<td>'.$rev.'</td><td>'); + if (ref($byresponsetype->{$symb}{$rev}) eq 'ARRAY') { + $r->print(&mt('Response Type(s): ').' '. + join('<br />',@{$byresponsetype->{$symb}{$rev}})); + } + $r->print('</td>'); + } + $r->print(&Apache::loncommon::end_data_table_row()); + } + } + } + } + $r->print(&Apache::loncommon::end_data_table()); + } +} + +sub releases_by_map { + my ($r,$bymap,$url,$scopeorder,$lt) = @_; + return unless ((ref($bymap) eq 'HASH') && (ref($scopeorder) eq 'ARRAY')); + if (ref($bymap->{$url}) eq 'HASH') { + foreach my $rev (sort(keys(%{$bymap->{$url}}))) { + $r->print('<td valign="middle">'.$rev.'</td><td>'); + if (ref($bymap->{$url}{$rev}) eq 'HASH') { + $r->print('<table border="0">'); + foreach my $scope (@{$scopeorder}) { + if (ref($bymap->{$url}{$rev}{$scope}) eq 'HASH') { + $r->print('<tr><td>'.&mt('Setting - scope: [_1]',$lt->{$scope}).'</td>'); + foreach my $which (sort(keys(%{$bymap->{$url}{$rev}{$scope}}))) { + $r->print('<td>'.$which.'</td><td>'. + join('<br />',@{$bymap->{$url}{$rev}{$scope}{$which}}). + '</td>'); + } + $r->print('</tr>'); + } elsif (ref($bymap->{$url}{$rev}{$scope}) eq 'ARRAY') { + $r->print('<tr><td>'.&mt('Setting - scope: [_1]',$lt->{$scope}). + '</td><td> </td><td>'. + join('<br />',@{$bymap->{$url}{$rev}{$scope}}).'</td></tr>'); + } + } + $r->print('</table>'); + } + $r->print('</td>'); + } + } else { + $r->print('<td colspan="2"> </td>'); + } + return; +} + +sub get_param_description { + my ($stdtype,$value) = @_; + my $name = $value; + my $paramstrings = &Apache::lonparmset::standard_string_options($stdtype); + unless (ref($paramstrings) eq 'ARRAY') { + return $name; + } + foreach my $possibilities (@{$paramstrings}) { + next unless (ref($possibilities) eq 'ARRAY'); + my ($thing, $description) = @{ $possibilities }; + if ($thing eq $value) { + $name = $description; + last; + } + } + return $name; +} + +sub show_autocoowners { + my (@currcoown) = @_; + my $output = '<i>'.&mt('Co-ownership is set automatically when a Course Coordinator role is assigned to official course personnel (from institutional data).').'</i>'; + if (@currcoown > 0) { + $output .= '<br />'.&mt('Current co-owners are:').' '. + join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + } else { + $output .= '<br />'.&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(). + '<td><i>'.&mt('Current co-owners').'</i></td><td>'; + foreach my $person (@currcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="coowners" checked="checked" value="'.$person.'" />'.&Apache::loncommon::plainname($co_uname,$co_dom).'</label></span>'.(' 'x2).' '; + } + $output .= '</td>'. + &Apache::loncommon::end_data_table_row(); + } + if ($pendingcoowners) { + $output .= &Apache::loncommon::start_data_table_row(). + '<td><i>'.&mt('Invited as co-owners [_1](agreement pending)','<br />').'</i></td><td>'; + foreach my $person (@pendingcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="pendingcoowners" checked="checked" value="'.$person.'" />'.&Apache::loncommon::plainname($co_uname,$co_dom).'</label></span>'.(' 'x2).' '; + } + $output .= '</td>'. + &Apache::loncommon::end_data_table_row(); + } + if (@othercoords) { + $output .= &Apache::loncommon::start_data_table_row(). + '<td><i>'.&mt('Invite other Coordinators [_1]to become co-owners','<br />').'</i></td><td>'; + foreach my $person (@othercoords) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= '<span class="LC_nobreak"><label><input type="checkbox" name="invitecoowners" value="'.$person.'" />'.&Apache::loncommon::plainname($co_uname,$co_dom).'</label></span>'.(' 'x2).' '; + } + $output .= '</td>'. + &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().'<td>'; + } + $output .= &mt('Current co-owners are:').' '. + join(', ', map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + if ($is_coowner || $is_pending) { + $output .= '</td>'.&Apache::loncommon::end_data_table_row(); + } + } + if ($is_coowner || $is_pending) { + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row().'<td>'; + } + $output .= '<span class="LC_nobreak">'; + if ($is_coowner) { + $output .= &mt('You are currently a co-owner:').' <label><input type="checkbox" name="remove_coowoner" value="'.$uname.':'.$udom.'" />'.&mt('Discontinue?').'</label>'; + } else { + $output .= &mt('The course owner has invited you to become a co-owner:').' <label><input type="radio" name="pending_coowoner" value="accept" />'.&mt('Accept?').'</label>'.(' 'x2). + '<label><input type="radio" name=pending_coowoner" value="decline" />'.&mt('Decline?').'</label>'; + } + $output .= '</span>'; + if (@currcoown) { + $output .= '</td>'.&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')) { @@ -1853,16 +2666,16 @@ sub print_localization { } my %items = ( languages => { - text => &mt($itemtext->{'languages'}).'<br />'. - &mt("(will override user's preference)"), + text => '<b>'.&mt($itemtext->{'languages'}).'</b><br />'. + &mt("(overrides individual user preference)"), input => 'selectbox', }, timezone => { - text => &mt($itemtext->{'timezone'}), + text => '<b>'.&mt($itemtext->{'timezone'}).'</b>', input => 'selectbox', }, datelocale => { - text => &mt($itemtext->{'datelocale'}), + text => '<b>'.&mt($itemtext->{'datelocale'}).'</b>', input => 'selectbox', }, ); @@ -1980,14 +2793,14 @@ sub print_feedback { foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + $datatable .= &item_table_row_start($items{$item}{text},$count); if ($position eq 'top') { my $includeempty = 0; $datatable .= &user_table($cdom,$item,\@sections, $settings->{$item},\%lt); } else { $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text', - $settings->{$item.'.text'},$items{$item}{size}); + $settings->{$item.'.text'},$items{$item}{size}); } $datatable .= &item_table_row_end(); } @@ -2251,7 +3064,7 @@ sub role_checkboxes { $output .= '<tr>'; } } - $output .= '<td align="left"><span class="LC_nobreak"><label><input type="checkbox" name='. + $output .= '<td align="left"><span class="LC_nobreak"><label><input type="checkbox" name="'. $item.'" value="'.$role.'"'.$checked.'/> '. $plrole.'</label></span></td>'; if ($showsections) { @@ -2283,7 +3096,7 @@ sub role_checkboxes { $output .= '<tr>'; } } - $output .= '<td><span class="LC_nobreak"><label><input type="checkbox" name='. + $output .= '<td><span class="LC_nobreak"><label><input type="checkbox" name="'. $item.'" value="'.$value.'"'.$checked.' /> '.$rolename. '</label></span></td>'; if ($showsections) { @@ -2319,7 +3132,8 @@ sub print_classlists { @ordered = ('nothideprivileged'); } else { @ordered = ('student_classlist_view', - 'student_opt_in','student_classlist_portfiles'); + 'student_classlist_opt_in', + 'student_classlist_portfiles'); } my %lt; @@ -2358,8 +3172,8 @@ sub print_classlists { options => \%lt, order => ['disabled','all','section'], }, - 'student_opt_in' => { - text => '<b>'.&mt($itemtext->{'student_opt_in'}).'</b>', + 'student_classlist_opt_in' => { + text => '<b>'.&mt($itemtext->{'student_classlist_opt_in'}).'</b>', input => 'radio', }, @@ -2444,7 +3258,7 @@ sub print_grading { }, 'rndseed' => { text => '<b>'.&mt($itemtext->{'rndseed'}).'</b>'. - '<span class="LC_error">'.'<br />'. + '<span class="LC_warning">'.'<br />'. &mt('Modifying this will make problems have different numbers and answers!'). '</span>', input => 'selectbox', @@ -2516,6 +3330,16 @@ sub print_printouts { text => '<b>'.&mt($itemtext->{'disableexampointprint'}).'</b>', input => 'radio', }, + canuse_pdfforms => { + text => '<b>'.&mt($itemtext->{'canuse_pdfforms'}).'</b>', + input => 'selectbox', + options => { + 1 => &mt('Yes'), + 0 => &mt('No'), + }, + order => ['1','0'], + nullval => 'None specified - use domain default', + } ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype); } @@ -2646,15 +3470,13 @@ sub get_other_items { } sub item_table_row_start { - my ($text,$count) = @_; + my ($text,$count,$add_class) = @_; my $output; - if ($count%2) { - $output .= '<tr class="LC_odd_row">'; - } else { - $output .= '<tr>'; - } + my $css_class = ($count % 2) ? 'LC_odd_row' : 'LC_even_row'; + $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); + $output .= '<tr class="'.$css_class.'">'."\n";; $output .= '<td class="LC_left_item">'.$text. - '</td><td class="LC_right_item" align="right">'; + '</td><td class="LC_right_item">'; return $output; } @@ -2987,7 +3809,7 @@ sub substitution_selector { a => 'assignment note', ); my $output .= &mt('Substitution').'<br />'. - '<select name=""printfmthdr_sub__'.$num.'">'; + '<select name="printfmthdr_sub_'.$num.'">'; if ($subst eq '') { $output .= '<option value="" selected="selected"> </option>'; }