--- loncom/interface/courseprefs.pm 2010/01/07 18:43:32 1.17 +++ loncom/interface/courseprefs.pm 2010/04/02 21:39:12 1.27 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.17 2010/01/07 18:43:32 faziophi Exp $ +# $Id: courseprefs.pm,v 1.27 2010/04/02 21:39:12 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -28,6 +28,185 @@ ############################################################### ############################################################## +=pod + +=head1 NAME + +courseprefs- Handler to set/modify course configuration + +=head1 SYNOPSIS + +courseprefs provides an interface for setting general course configuration + +=head1 DESCRIPTION + +This module is used for configuration of a course + +=head1 INTERNAL SUBROUTINES + +=over + +=item get_allitems() + +=item print_config_box() + +=item process_changes() + +=item get_sec_str() + +=item check_clone() + +=item store_changes() + +=item update_env() + +=item display_disallowed() + +=item get_course() + +=item get_jscript() + +=item cloners_javascript() + +=item print_courseinfo() + +=item new_cloners_dom_row() + +=item can_modify_catsettings() + +=item assign_course_categories() + +=item print_localization() + +=item get_lang_choices() + +=item print_feedback() + +=item user_table() + +=item select_recipient() + +=item select_sections() + +=item print_discussion() + +=item role_checkboxes() + +=item print_classlists() + +=item print_appearance() + +=item print_grading() + +=item print_printouts() + +=item print_spreadsheet() + +=item print_bridgetasks() + +=item print_other() + +=item get_other_items() + +=item item_table_row_start() + +=item item_table_row_end() + +=item yes_no_radio() + +=item select_from_options() + +=item make_item_rows() + +Creates table used to display and set course configuration items. + +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 +display order, $settings is HASH ref of current values forrow, +$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. + +=item nothidepriv_row() + +Creates row containing form elements used to display and set +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). + +Return: $datatable +HTML mark-up for Privileged users (Domain Coordinators) in staff listing. + +=item print_hdrfmt_row() + +Creates row containing form elements used to display and set +substitution items and text to be used in the header included +on printouts. + +Inputs: $item,$settings +where $item is print_header_format, and $settings is a HASH ref +of the current values stored for print_header_format. + +Returns: $output +HTML mark-up containing Javascript functions: reOrder() and getIndexByName() +used to dynamically update position selectboxes, and HTML table elements +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. + +Inputs: $pos,$num,$maxnum +where $pos is current position, $num is the unique identifier, +and $maxnum is the total number of items (both substitutions +and text in the printout header. + +Returns: $output +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, +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 +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). + +=item change_clone() + +Modifies the list of courses a user can clone (stored +in the user's environment.db file), called when a +change is made to the list of users allowed to clone +a course. + +Inputs: $action,$cloner +where $action is add or drop, and $cloner is identity of +user for whom cloning ability is to be changed in course. + +Returns: nothing + +=back + +=cut + + package Apache::courseprefs; use strict; @@ -93,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', @@ -115,15 +296,17 @@ sub handler { %lt = ( conf => 'Course Configuration', edit => 'Edit Course Configuration', - gens => 'General Settings', - idnu => 'ID/Number', - desc => 'Title', + 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', rept => 'Replacement titles for standard course roles', - time => 'Timezone', - date => 'Calendar Locale', + time => 'Timezone in which the course takes place', + date => 'Locale used for course calendar', coco => 'Course Content', copo => 'Course Policy', priv => 'Domain Coordinators in course', @@ -161,41 +344,37 @@ sub handler { 'courseinfo' => { text => $lt{'gens'}, help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], - ordered => ['description','courseid','categories', - 'hidefromcat','externalsyllabus', - 'url','rolenames','cloners'], + ordered => ['owner','co-owners','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 => 'External Syllabus URL', - 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' => - { text => 'Language & Time Localization', + { text => 'Language and Time Localization', help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], ordered => ['languages','timezone','datelocale'], itemtext => { - languages => 'Language(s)', + languages => 'Languages used', timezone => $lt{'time'}, datelocale => $lt{'date'}, }, }, 'feedback' => - { text => 'Feedback Messages', + { text => 'Feedback messages', help => 'Course_Environment', header => [{col1 => 'Questions about:', - col2 => 'Recipients'}, - {col1 => 'Questions about:', - col2 => 'Custom Text'}], + col2 => 'Recipients'}], ordered => ['question.email','comment.email','policy.email'], itemtext => { 'question.email' => 'Resource Content', @@ -206,19 +385,17 @@ 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', 'allow_limited_html_in_feedback', 'allow_discussion_post_editing'], itemtext => { - 'plc.roles.denied' => 'Disable resource discussion', - 'plc.users.denied' => 'Disable resource discussion', - 'pch.roles.denied' => 'Disable chat room', - 'pch.users.denied' => 'Disable chat room', - allow_limited_html_in_feedback => 'HTML in discussion', - allow_discussion_post_editing => 'Allow users to edit/delete own discussion posts', + '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', + allow_discussion_post_editing => 'Users can edit/delete own discussion posts', }, }, 'classlists' => @@ -233,52 +410,46 @@ 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 ', + { text => 'Display of resources ', help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', 'tthoptions'], itemtext => { default_xml_style => 'Default XML style file', - pageseparators => 'Separate items on composite pages', - disable_receipt_display => 'Disable problem receipts display', - texengine => 'Force specific math rendering engine', + pageseparators => 'Visibly Separate Items on Pages', + disable_receipt_display => 'Disable display of problem receipts', + texengine => 'Force use of a specific math rendering engine', tthoptions => 'Default set of options to pass to tth/m when converting TeX', }, }, 'grading' => { text => 'Grading', help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], ordered => ['grading','rndseed', 'receiptalg','disablesigfigs'], itemtext => { - grading => 'Grading Type', - rndseed => 'Randomization algorithm', - receiptalg => 'Receipt algorithm', - disablesigfigs => 'Disable significant figure checks', + grading => 'Grading', + rndseed => 'Randomization algorithm used', + receiptalg => 'Receipt algorithm used', + disablesigfigs => 'Disable checking of Significant Figures', }, }, 'printouts' => - { text => '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'], @@ -294,8 +465,6 @@ sub handler { 'spreadsheet' => { text => 'Spreadsheets', help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], ordered => ['spreadsheet_default_classcalc', 'spreadsheet_default_studentcalc', 'spreadsheet_default_assesscalc','hideemptyrows'], @@ -309,8 +478,6 @@ sub handler { 'bridgetasks' => { text => 'Bridge tasks', help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], ordered => ['task_messages','task_grading', 'suppress_embed_prompt'], itemtext => { @@ -371,11 +538,15 @@ sub print_config_box { &Apache::loncommon::help_open_topic($item->{'help'}).''; if (($action eq 'feedback') || ($action eq 'classlists')) { $output .= ' -
'.&mt($item->{'header'}->[0]->{'col1'}).' | '.&mt($item->{'header'}->[0]->{'col2'}).' | -
'.&mt($item->{'header'}->[2]->{'col1'}).' | -'.&mt($item->{'header'}->[2]->{'col2'}).' | -
'.&mt($item->{'header'}->[0]->{'col1'}).' | +'.&mt($item->{'header'}->[0]->{'col2'}).' | +
'.&mt($item->{'header'}->[0]->{'col1'}).' | '.&mt($item->{'header'}->[0]->{'col2'}).' | -'.
- &mt('Domain:').' '.$udom.
+ &mt('Any user in domain:').' '.$udom.
' '. ' | '.
&Apache::loncommon::end_data_table_row();
$num ++;
- } else {
- push(@cloners,$entry);
+ } elsif (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') {
+ unless (grep(/^\Q$entry\E$/,@cloners)) {
+ push(@cloners,$entry);
+ }
}
}
}
@@ -1468,6 +1836,38 @@ sub print_courseinfo {
$datatable .= ''.
&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');
+ }
+ 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});
}
@@ -1625,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').' | '; + 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')) { @@ -1750,16 +2272,20 @@ sub print_feedback { my %sections = &Apache::loncommon::get_sections($cdom,$cnum); my @sections = sort( { $a <=> $b } keys(%sections)); my %lt = &Apache::lonlocal::texthash ( - currone => 'Current recipient:', - curmult => 'Current recipients:', - add => 'Additional recipient:', - del => 'Delete?', - sec => 'Sections:', + currone => 'Current recipient:', + currmult => 'Current recipients:', + add => 'Additional recipient:', + del => 'Delete?', + sec => 'Sections:', ); foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + if ($position eq 'top') { + $datatable .= &item_table_row_start($items{$item}{text},$count); + } else { + $datatable .= &item_table_row_start($items{$item}{text}."
';
- if ($num > 1) {
+ if ($num == 1) {
$output .= $lt->{'currone'};
} else {
$output .= $lt->{'currmult'};
@@ -1935,11 +2461,11 @@ sub print_discussion {
my %sections = &Apache::loncommon::get_sections($cdom,$cnum);
my @sections = sort( { $a <=> $b } keys(%sections));
my %lt = &Apache::lonlocal::texthash (
- currone => 'Disallowed:',
- curmult => 'Disallowed:',
- add => 'Disallow more:',
- del => 'Delete?',
- sec => 'Sections:',
+ currone => 'Disallowed:',
+ currmult => 'Disallowed:',
+ add => 'Disallow more:',
+ del => 'Delete?',
+ sec => 'Sections:',
);
foreach my $item (@{$ordered}) {
@@ -2098,7 +2624,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;
@@ -2137,8 +2664,8 @@ sub print_classlists {
options => \%lt,
order => ['disabled','all','section'],
},
- 'student_opt_in' => {
- text => ''.&mt($itemtext->{'student_opt_in'}).'',
+ 'student_classlist_opt_in' => {
+ text => ''.&mt($itemtext->{'student_classlist_opt_in'}).'',
input => 'radio',
},
@@ -2435,15 +2962,13 @@ sub get_other_items {
}
sub item_table_row_start {
- my ($text,$count) = @_;
+ my ($text,$count,$add_class) = @_;
my $output;
- if ($count%2) {
- $output .= ''.$text.
- ' | ';
+ ' | ';
return $output;
}
@@ -2639,9 +3164,9 @@ sub print_hdrfmt_row {
$currstr .= ''.&mt('Current print header:').' '.
$settings->{$item}.' | '; my @current = split(/(%\d*[nca])/,$settings->{$item}); - foreach my $item (@current) { - unless ($item eq '') { - push(@curr,$item); + foreach my $val (@current) { + unless ($val eq '') { + push(@curr,$val); } } $currnum = @curr; @@ -2794,4 +3319,66 @@ sub substitution_selector { return $output; } +sub change_clone { + my ($cdom,$cnum,$clonelist,$oldcloner) = @_; + my $clone_crs = $cnum.':'.$cdom; + if ($cnum && $cdom) { + my $clone_crs = $cnum.':'.$cdom; + my @allowclone; + if ($clonelist =~ /,/) { + @allowclone = split(',',$clonelist); + } else { + $allowclone[0] = $clonelist; + } + foreach my $currclone (@allowclone) { + if (!grep(/^$currclone$/,@$oldcloner)) { + if ($currclone ne '*') { + my ($uname,$udom) = split(/:/,$currclone); + if ($uname && $udom && $uname ne '*') { + if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable'); + if ($currclonecrs{'cloneable'} !~ /\Q$clone_crs\E/) { + if ($currclonecrs{'cloneable'} eq '') { + $currclonecrs{'cloneable'} = $clone_crs; + } else { + $currclonecrs{'cloneable'} .= ','.$clone_crs; + } + &Apache::lonnet::put('environment',\%currclonecrs,$udom,$uname); + } + } + } + } + } + } + foreach my $oldclone (@$oldcloner) { + if (!grep(/^\Q$oldclone\E$/,@allowclone)) { + if ($oldclone ne '*') { + my ($uname,$udom) = split(/:/,$oldclone); + if ($uname && $udom && $uname ne '*' ) { + if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable'); + my %newclonecrs = (); + if ($currclonecrs{'cloneable'} =~ /\Q$clone_crs\E/) { + if ($currclonecrs{'cloneable'} =~ /,/) { + my @currclonecrs = split/,/,$currclonecrs{'cloneable'}; + foreach my $crs (@currclonecrs) { + if ($crs ne $clone_crs) { + $newclonecrs{'cloneable'} .= $crs.','; + } + } + $newclonecrs{'cloneable'} =~ s/,$//; + } else { + $newclonecrs{'cloneable'} = ''; + } + &Apache::lonnet::put('environment',\%newclonecrs,$udom,$uname); + } + } + } + } + } + } + } + return; +} + 1; |