# The LearningOnline Network with CAPA # Handler to set configuration settings for a course # # $Id: courseprefs.pm,v 1.4 2009/05/17 00:54:38 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA# # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # # ############################################################### ############################################################## package Apache::courseprefs; use strict; use Apache::Constants qw(:common :http); use Apache::lonnet; use Apache::loncommon(); use Apache::lonhtmlcommon(); use Apache::lonconfigsettings; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); sub handler { my $r=shift; if ($r->header_only) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK; } my $context = 'course'; my $cid = $env{'request.course.id'}; my ($cnum,$cdom) = &get_course($cid); my $crstype = &Apache::loncommon::course_type(); my $parm_permission = &Apache::lonnet::allowed('opa',$cid); my $navmap = Apache::lonnavmaps::navmap->new(); if ($parm_permission && $navmap) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; } else { if ($navmap) { $env{'user.error.msg'}= "/adm/courseprefs:opa:0:0:Cannot modify course settings"; } else { $env{'user.error.msg'}= "/adm/courseprefs::0:1:Course environment gone, reinitialize the course"; } return HTTP_NOT_ACCEPTABLE; } &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['phase','actions','origin']); &Apache::lonhtmlcommon::clear_breadcrumbs(); if ($env{'form.origin'} eq 'params') { &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset", text=>"Parameter Manager"}); } &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/courseprefs', text=>"Course Configuration"}); my $breadcrumbs = &Apache::lonhtmlcommon::breadcrumbs('Edit Course Configuration'); my $phase = 'pickactions'; if ( exists($env{'form.phase'}) ) { $phase = $env{'form.phase'}; } if ($phase eq 'categorizecourse') { &assign_course_categories($r); return OK; } my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', 'spreadsheet','bridgetasks','other'); my %prefs = ( 'courseinfo' => { text => 'General course settings', help => 'Course_Environment', header => [{col1 => 'Setting', col2 => 'Value'}], ordered => ['description','courseid','categories', 'hidefromcat','cloners','externalsyllabus', 'url','rolenames'], itemtext => { description => 'Course Description', courseid => 'Course ID or number', categories => 'Categorize course', hidefromcat => 'Exclude from course catalog', cloners => 'Users allowed to clone course', externalsyllabus => 'URL of Syllabus', url => 'Top Level Map', rolenames => 'Replacement titles for standard course roles', }, }, 'localization' => { text => 'Language/TimeZone/Locale', help => 'Course_Environment', header => [{col1 => 'Setting', col2 => 'Value',}], ordered => ['languages','timezone','datelocale'], itemtext => { languages => 'Languages used', timezone => 'Timezone in which the course takes place', datelocale => 'Locale used for course calendar', }, }, 'feedback' => { text => 'Feedback messages', help => 'Course_Environment', header => [{col1 => 'Questions about:', col2 => 'Recipients'}, {col1 => 'Questions about:', col2 => 'Custom Text'}], ordered => ['question.email','comment.email','policy.email'], itemtext => { 'question.email' => 'Resource Content', 'comment.email' => 'Course Content', 'policy.email' => 'Course Policy', }, }, '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' => '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', allow_discussion_post_editing => 'Users can edit/delete own discussion posts', }, }, 'classlists' => { text => 'Classlists and Staff Listing', help => 'Course_Environment', header => [{col1 => 'Type', col2 => 'Default dates for student access'}, {col1 => 'Setting', col2 => 'Privileged users (Domain Coordinators) in staff listing'}, {col1 => 'Setting', col2 => 'Student-viewable classlist options'}], ordered => ['default_enrollment_start_date', 'default_enrollment_end_date', 'nothideprivileged','student_classlist_view', 'student_opt_in','student_classlist_portfiles'], itemtext => { default_enrollment_start_date => 'Start date', default_enrollment_end_date => 'End date', nothideprivileged => 'Domain Coodinators in course', student_classlist_view => 'Student-viewable classlist', student_opt_in => 'Student agreement needed to be listed', 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'], itemtext => { 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.', 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', rndseed => 'Randomization algorithm used', receiptalg => 'Receipt algorithm used', disablesigfigs => 'Disable checking of Significant Figures', }, }, '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'], 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', }, }, 'spreadsheet' => { text => 'Spreadsheets', help => 'Course_Environment', header => [{col1 => 'Setting', col2 => 'Value'}], ordered => ['spreadsheet_default_classcalc', 'spreadsheet_default_studentcalc', 'spreadsheet_default_assesscalc','hideemptyrows'], itemtext => { spreadsheet_default_classcalc => 'Default Course Spreadsheet', spreadsheet_default_studentcalc => 'Default Student Spreadsheet', spreadsheet_default_assesscalc => 'Default Assessment Spreadsheet', hideemptyrows => 'Hide Empty Rows in Spreadsheets', }, }, 'bridgetasks' => { text => 'Bridge tasks', help => 'Course_Environment', header => [{col1 => 'Setting', col2 => 'Value'}], ordered => ['task_messages','task_grading', 'suppress_embed_prompt'], itemtext => { task_messages => 'Send message to student when clicking Done on Tasks', task_grading => 'Bridge Task grading by instructors and TAs in sections' , suppress_embed_prompt => 'Hi$de upload references prompt if uploading file to portfolio', }, }, 'other' => { text => 'Other settings', help => 'Course_Environment', header => [ {col1 => 'Item', col2 => 'Value', }], }, ); if ($phase eq 'process') { my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context, \@prefs_order,\%prefs,\%values, $cnum,undef,\@allitems); } elsif ($phase eq 'display') { my $jscript = &get_jscript($cdom,$phase); my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems); } else { &Apache::lonconfigsettings::display_choices($r,$phase,$context, \@prefs_order,\%prefs); } return OK; } sub get_allitems { my (%prefs) = @_; my @allitems; foreach my $item (keys(%prefs)) { if (ref($prefs{$item}) eq 'HASH') { if (ref($prefs{$item}{'ordered'}) eq 'ARRAY') { push(@allitems,@{$prefs{$item}{'ordered'}}); if ($item eq 'feedback') { push(@allitems,(map { $_.'.text'; } @{$prefs{$item}{'ordered'}})); } } } } return @allitems; } sub print_config_box { my ($r,$cdom,$phase,$action,$item,$settings,$allitems) = @_; my $ordered = $item->{'ordered'}; my $itemtext = $item->{'itemtext'}; my $rowtotal = 0; my $output = ''."\n". ''; if (($action eq 'feedback') || ($action eq 'classlists')) { $output .= ' '. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). '
'. &mt($item->{text}).' '. &Apache::loncommon::help_open_topic($item->{'help'}).'
'; $rowtotal ++; if ($action eq 'feedback') { $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'classlists') { $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).' '.&mt($item->{'header'}->[0]->{'col2'}).'
'; $output .= ' '; if ($action eq 'classlists') { $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal). '
'.&mt($item->{'header'}->[1]->{'col1'}).''.&mt($item->{'header'}->[1]->{'col2'}).'
'; } } else { $output .= '
'.&mt($item->{'header'}->[2]->{'col1'}).' '.&mt($item->{'header'}->[2]->{'col2'}).'
'; } $rowtotal ++; if ($action eq 'courseinfo') { $output .= &print_courseinfo($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'localization') { $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'feedback') { $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'discussion') { $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'classlists') { $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal); } elsif ($action eq 'appearance') { $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'grading') { $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'printouts') { $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'spreadsheet') { $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'bridgetasks') { $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'other') { $output .= &print_other($cdom,$settings,$allitems,\$rowtotal); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).' '.&mt($item->{'header'}->[0]->{'col2'}).'

'; return ($output,$rowtotal); } sub process_changes { my ($cdom,$action,$values,$item,$changes,$allitems,$disallowed) = @_; my %newvalues; if (ref($item) eq 'HASH') { if (ref($changes) eq 'HASH') { my @ordered; if ($action eq 'other') { @ordered = &get_other_items($cdom,$values,$allitems); if ($env{'form.newp_name'} ne '') { my $newp = $env{'form.newp_name'}; if ($env{'form.newp_value'} ne '') { if (ref($allitems) eq 'ARRAY') { unless ((grep(/^\Q$newp\E$/,@ordered)) || (grep(/^\Q$newp\E$/,@{$allitems}))) { $changes->{$newp} = $env{'form.newp_value'}; } } } } } elsif (ref($item->{'ordered'}) eq 'ARRAY') { @ordered = @{$item->{'ordered'}}; } if (@ordered > 0) { if ($action eq 'feedback') { foreach my $entry (@ordered) { my $userstr = ''; my $total = $env{'form.'.$entry.'_total'}; if ($total) { my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); for (my $i=0; $i<$total; $i++) { unless (grep(/^$i$/,@deletes)) { $userstr .= $env{'form.'.$entry.'_user_'.$i}. &get_sec_str($entry,$i).','; } } } else { $total = 0; } if ($env{'form.'.$entry.'_uname_'.$total} ne '') { my $uname = $env{'form.'.$entry.'_uname_'.$total}; my $udom = $env{'form.'.$entry.'_udom_'.$total}; if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { $userstr =~ s/,$//; $disallowed->{'feedback'}{$entry} = $uname.':'.$udom; } else { $userstr .= $uname.':'.$udom.&get_sec_str($entry,$total); } } else { $userstr =~ s/,$//; } $newvalues{$entry} = $userstr; if ($newvalues{$entry} ne $values->{$entry}) { $changes->{$entry} = $newvalues{$entry}; } my $ext_entry = $entry.'.text'; $newvalues{$ext_entry} = $env{'form.'.$ext_entry}; if ($newvalues{$ext_entry} ne $values->{$ext_entry}) { $changes->{$ext_entry} = $newvalues{$ext_entry}; } } } else { foreach my $entry (@ordered) { if ($entry eq 'cloners') { if ($env{'form.cloners_all'}) { $newvalues{$entry} = '*'; } else { my @clonedoms; 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 (&check_clone($clonedom,$disallowed) eq 'ok') { $newvalues{$entry} = '*:'.$clonedom; push(@clonedoms,$newvalues{$entry}); } } } } else { my $num = $env{'form.cloners_total'}; my @deletes = &Apache::loncommon::get_env_multiple('form.cloners_delete'); for (my $i=0; $i<$num; $i++) { if (!grep(/^$i$/,@deletes)) { my $clonedom = $env{'form.cloners_dom_'.$i}; if (&check_clone($clonedom,$disallowed) eq 'ok') { if (!grep(/^\*:\Q$clonedom\E$/,@clonedoms)) { push (@clonedoms,'*:'.$clonedom); } } } } if (@clonedoms) { $newvalues{$entry}=join(',',@clonedoms); } } if ($env{'form.cloners_newdom'} ne '') { my $clonedom = $env{'form.cloners_newdom'}; if (&check_clone($clonedom,$disallowed) eq 'ok') { my $newdom = '*:'.$env{'form.cloners_newdom'}; if (@clonedoms) { if (!grep(/^\Q$newdom\E$/,@clonedoms)) { $newvalues{$entry} .= ','.$newdom; } } else { $newvalues{$entry} = $newdom; } } } if ($env{'form.'.$entry} ne '') { my @cloners = split(',',$env{'form.'.$entry}); my @okcloners; foreach my $cloner (@cloners) { my ($uname,$udom) = split(':',$cloner); if (&check_clone($udom,$disallowed,$uname) eq 'ok') { if (!grep(/^\Q$cloner\E$/,@okcloners)) { push(@okcloners,$cloner); } } } if (@okcloners) { my $okclonestr = join(',',@okcloners); if ($newvalues{$entry} ne '') { $newvalues{$entry} .= ','.$okclonestr; } else { $newvalues{$entry} = $okclonestr; } } } } if (ref($disallowed) eq 'HASH') { if (ref($disallowed->{'cloners'}) eq 'HASH') { foreach my $key (keys(%{$disallowed->{'cloners'}})) { $disallowed->{'cloners'}{$key} =~ s/,$//; } } } } elsif ($entry =~ /^default_enrollment_(start|end)_date$/) { $newvalues{$entry}=&Apache::lonhtmlcommon::get_date_from_form($entry); } elsif ($entry eq 'rolenames') { my $crstype = &Apache::loncommon::course_type(); my %adv_roles = &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1); my @stds = ('cc','in','ta','ep','ad','st'); my (@replacements,@regulars); foreach my $role (@stds) { if ($values->{$role.'.plaintext'} ne '') { push(@replacements,$role); } else { push(@regulars,$role); } } foreach my $stdrole (@stds) { my $ext_entry = $entry.'_'.$stdrole; my $stdname = &Apache::lonnet::plaintext($stdrole,$crstype, $env{'request.course.id'},1); if ($env{'form.'.$ext_entry} eq $stdname) { $newvalues{$ext_entry} = ''; } else { $newvalues{$ext_entry} = $env{'form.'.$ext_entry}; } if ($newvalues{$ext_entry} ne $values->{$stdrole.'.plaintext'}) { my $dupname = 0; if ($newvalues{$ext_entry} ne '') { my $dupname = 0; if (grep(/^\Q$newvalues{$ext_entry}\E$/,@replacements)) { $dupname = 1; push(@{$disallowed->{'rolenames'}{'replacements'}},$newvalues{$ext_entry}); } if (!$dupname) { if (grep(/^\Q$newvalues{$ext_entry}\E$/,@regulars)) { $dupname = 1; push(@{$disallowed->{rolenames}{'regulars'}},$newvalues{$ext_entry}); } } if (!$dupname) { foreach my $role (keys(%adv_roles)) { if ($role =~ m{^cr/$match_domain/$match_name/\Q$newvalues{$ext_entry}\E$}) { $dupname = 1; push(@{$disallowed->{rolenames}{'customrole'}},$newvalues{$ext_entry}); last; } } } } if (!$dupname) { $changes->{$ext_entry} = $newvalues{$ext_entry}; } } } } elsif (($entry eq 'plc.roles.denied') || ($entry eq 'pch.roles.denied')) { my @denied = &Apache::loncommon::get_env_multiple('form.'.$entry); @denied = sort(@denied); my $deniedstr = ''; if (@denied > 0) { $deniedstr = join(',',@denied); } $newvalues{$entry} = $deniedstr; } elsif (($entry eq 'plc.users.denied') || ($entry eq 'pch.users.denied')) { my $total = $env{'form.'.$entry.'_total'}; my $userstr = ''; my @denied; if ($total > 0) { my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); for (my $i=0; $i<$total; $i++) { unless (grep(/^$i$/,@deletes)) { $userstr .= $env{'form.'.$entry.'_user_'.$i}.','; push(@denied,$env{'form.'.$entry.'_user_'.$i}); } } } else { $total = 0; } if ($env{'form.'.$entry.'_uname_'.$total} ne '') { my $uname = $env{'form.'.$entry.'_uname_'.$total}; my $udom = $env{'form.'.$entry.'_udom_'.$total}; if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { $userstr =~ s/,$//; $disallowed->{'discussion'}{$entry} = $uname.':'.$udom; } else { my $newuser .= $uname.':'.$udom; if (grep(/^\Q$newuser\E$/,@denied)) { $userstr =~ s/,$//; } else { $userstr .= $newuser; } } } else { $userstr =~ s/,$//; } $newvalues{$entry} = $userstr; } elsif ($entry eq 'allow_discussion_post_editing') { my @canedit = &Apache::loncommon::get_env_multiple('form.'.$entry); @canedit = sort(@canedit); foreach my $role (@canedit) { my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$role); if ((grep(/^\s*$/,@secs)) || (@secs == 0)) { $newvalues{$entry} .= $role.','; } else { foreach my $sec (@secs) { $newvalues{$entry} .= $role.':'.$sec.','; } } } $newvalues{$entry} =~ s/,$//; } elsif ($entry eq 'nothideprivileged') { my @curr_nothide; my @new_nothide; if ($values->{$entry} ne '') { foreach my $user (split(/\s*\,\s*/,$values->{$entry})) { my $nothide; if ($user !~ /:/) { $nothide = join(':',split(/[\@]/,$user)); } else { $nothide = $user; } if ((defined($nothide)) && (!grep(/^\Q$nothide\E$/,@curr_nothide))) { push(@curr_nothide,$nothide); } } } foreach my $key (keys(%env)) { if ($key =~ /^form\.\Q$entry\E_($match_username:$match_domain)$/) { if ($env{'form.'.$key}) { my $nothide = $1; if (!grep(/^\Q$nothide\E$/,@new_nothide)) { push(@new_nothide,$nothide); } } } } @new_nothide = sort(@new_nothide); my @differences = &Apache::loncommon::compare_arrays(\@curr_nothide, \@new_nothide); if (@differences > 0) { if (@new_nothide > 0) { $newvalues{$entry} = join(',',@new_nothide); } else { $newvalues{$entry} = ''; } } else { $newvalues{$entry} = $values->{$entry}; } } elsif ($entry eq 'print_header_format') { my $maxnum = $env{'form.printfmthdr_maxnum'}; my @newhdr; if ($maxnum > 2) { for (my $i=0; $i<$maxnum-2; $i++) { if ($env{'form.printfmthdr_del_'.$i}) { $newhdr[$env{'form.printfmthdr_pos_'.$i}] = ''; } else { my $hdr; if ($env{'form.printfmthdr_sub_'.$i} =~ /^[nca]$/) { $hdr = '%'; if ($env{'form.printfmthdr_limit_'.$i} =~ /^\d+$/) { $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}; } $newhdr[$env{'form.printfmthdr_pos_'.$i}] = $hdr; } } } my $newsub = $maxnum-2; if ($env{'form.printfmthdr_sub_'.$newsub} =~ /^[nca]$/) { my $hdr = '%'; if ($env{'form.printfmthdr_limit_'.$newsub} =~ /^\d+$/) { $hdr .= $env{'form.printfmthdr_limit_'.$newsub}; } $hdr .= $env{'form.printfmthdr_sub_'.$newsub}; $newhdr[$env{'form.printfmthdr_pos_'.$newsub}] = $hdr; } my $newtext = $maxnum-1; $newhdr[$env{'form.printfmthdr_pos_'.$newtext}] = $env{'form.printfmthdr_text_'.$newtext}; $newvalues{$entry} = join('',@newhdr); } elsif ($entry eq 'languages') { my $langstr; my $total = $env{'form.'.$entry.'_total'}; if ($total) { my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); for (my $i=0; $i<$total; $i++) { unless (grep(/^$i$/,@deletes)) { $langstr .= $env{'form.'.$entry.'_'.$i}.','; } } } else { $total = 0; } if ($env{'form.'.$entry.'_'.$total} ne '') { my $newlang = $env{'form.'.$entry.'_'.$total}; my %langchoices = &get_lang_choices(); if ($langchoices{$newlang}) { $langstr .= $newlang; } else { $langstr =~ s/,$//; $disallowed->{'localization'}{$entry} = $newlang; } } else { $langstr =~ s/,$//; } $newvalues{$entry} = $langstr; } else { $newvalues{$entry} = $env{'form.'.$entry}; } if ($newvalues{$entry} ne $values->{$entry}) { $changes->{$entry} = $newvalues{$entry}; } } } } } } return; } sub get_sec_str { my ($entry,$num) = @_; my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$num); my $secstr; if (grep(/^\s*$/,@secs)) { $secstr = ''; } elsif (@secs > 0) { $secstr = join(';',@secs); } if ($secstr ne '') { return '('.$secstr.')'; } return; } sub check_clone { my ($clonedom,$disallowed,$clonename) = @_; return if (ref($disallowed) ne 'HASH'); if ($clonedom !~ /^$match_domain$/) { $disallowed->{'cloners'}{'format'} .= $clonedom.','; return; } elsif (!&Apache::lonnet::domain($clonedom)) { $disallowed->{'cloners'}{'domain'} .= $clonedom.','; return; } if ($clonename ne '') { if ($clonename !~ /^$match_username$/) { $disallowed->{'cloners'}{'format'} .= $clonename.':'.$clonedom.','; return; } else { if (&Apache::lonnet::homeserver($clonename,$clonedom) eq 'no_host') { $disallowed->{'cloners'}{'newuser'} .= $clonename.':'.$clonedom.','; return; } } } return 'ok'; } sub store_changes { my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes) = @_; my ($chome,$output); my (%storehash,@delkeys,@need_env_update); if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) { %storehash = %{$values}; } else { $output = &mt('No changes made to course settings.'); return; } my %yesno = ( hidefromcat => '1', problem_stream_switch => '1', suppress_tries => '1', disableexampointprint => '1', hideemptyrows => '1', suppress_embed_prompt => '1', ); foreach my $item (@{$prefs_order}) { if (grep(/^\Q$item\E$/,@{$actions})) { $output .= '

'.&mt($prefs->{$item}{'text'}).'

'; if (ref($changes->{$item}) eq 'HASH') { if (keys(%{$changes->{$item}}) > 0) { $output .= &mt('Changes made:').'
    '; 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 .= '
  • '.&mt('Deleted setting for [_1]',''.$key.'').'
  • '; } else { $output .= '
  • '.&mt('[_1] set to [_2]',''.$key.'', "'$storehash{$key}'").'
  • '; } } } else { if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') { my @settings = @{$prefs->{$item}->{'ordered'}}; if ($item eq 'feedback') { push(@settings,(map { $_.'.text'; } @settings)); } foreach my $key (@settings) { if ($key eq 'rolenames') { my $displayname = $prefs->{$item}->{'itemtext'}{$key}; my $crstype = &Apache::loncommon::course_type(); my $msg; foreach my $role ('cc','in','ta','ep','ad','st') { next if (!exists($changes->{$item}{$key.'_'.$role})); my $stdname = &Apache::lonnet::plaintext($role,$crstype,undef,1); my $newname = $changes->{$item}{$key.'_'.$role}; $storehash{$role.'.plaintext'} = $newname; if ($newname eq '') { $newname = $stdname; } $msg .= '
  • '.&mt('[_1] set to [_2]',''.$stdname.'', "'".$newname."'").'
  • '; } if ($msg ne '') { $output .= '
  • '.&mt($displayname).'
      '.$msg.'
  • '; } } else { next if (!exists($changes->{$item}{$key})); my ($displayname,$text); $text = $prefs->{$item}->{'itemtext'}{$key}; my $displayval = $changes->{$item}{$key}; if ($item eq 'feedback') { if ($key =~ /^(question|policy|comment)(\.email)\.text$/) { $text = $prefs->{$item}->{'itemtext'}{$1.$2}; $displayname = &mt('Custom text for '.$text.' questions'); } else { $displayname = &mt('Recipients of '.$text.' questions'); } } elsif ($item eq 'discussion') { if ($key =~ /^p(lc|ch)\.roles\.denied/) { $displayname = &mt("$text (role-based)"); if ($displayval ne '') { my @roles = split(',',$displayval); @roles = map { &Apache::lonnet::plaintext($_); } @roles; $displayval = join(', ',@roles); } } elsif ($key =~ /^p(lc|ch)\.users\.denied/) { $displayname = &mt("$text (specific user(s))"); } else { if ($key eq 'allow_discussion_post_editing') { if ($displayval ne '') { my @roles = split(',',$displayval); my @longroles; foreach my $role (@roles) { my ($trole,$sec) = split(':',$role); my $rolename = &Apache::lonnet::plaintext($trole); if ($sec ne '') { $rolename .= ':'.$sec; } push(@longroles,$rolename); } $displayval = join(', ',@longroles); } } $displayname = &mt($text); } } elsif ($item eq 'spreadsheet') { if ($key =~ /^spreadsheet_default_(studentcalc|assesscalc)$/x) { my $sheettype = $1; if ($sheettype eq 'studentcalc') { &Apache::lonnet::expirespread('','','studentcalc'); } else { &Apache::lonnet::expirespread('','','assesscalc'); &Apache::lonnet::expirespread('','','studentcalc'); } } $displayname = &mt($text); } else { $displayname = &mt($text); } if (defined($yesno{$key})) { $displayval = 'no'; if ($changes->{$item}{$key} eq 'yes') { $displayval = '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 '') { push(@delkeys,$key); $output .= '
  • '.&mt('Deleted setting for [_1]', ''.$displayname.'').'
  • '; } else { $output .= '
  • '.&mt('[_1] set to [_2]', ''.$displayname.'', "'$displayval'"); if ($key eq 'url') { my $bkuptime=time; $output .= (' 'x2).&mt('(Previous URL backed up)').': '. $storehash{'top level map backup '.$bkuptime} => $values->{$key}; } $output .= '
  • '; } $storehash{$key} = $changes->{$item}{$key}; } if (($key eq 'description') || ($key eq 'cloners') || ($key eq 'hidefromcat') || ($key eq 'categories')) { push(@need_env_update,$key); } } } } $output .= '
'; } else { $output = &mt('No changes made to course settings.'); } } } } if (&Apache::lonnet::put('environment',\%storehash,$cdom,$cnum) eq 'ok') { if (@delkeys) { if (&Apache::lonnet::del('environment',\@delkeys,$cdom,$cnum) ne 'ok') { $output .= '
'. &mt('An error occurred when removing course settings which are no longer in use.').''; } } if (@need_env_update) { $chome = &Apache::lonnet::homeserver($cnum,$cdom); &update_env($cnum,$cdom,$chome,\@need_env_update,\%storehash); } &Apache::lonnet::coursedescription($env{'request.course.id'}, {'freshen_cache' => 1}); } else { $output = ''. &mt('An error occurred when saving changes to course settings, which remain unchanged.').''; } return $output; } sub update_env { my ($cnum,$cdom,$chome,$need_env_update,$storehash) = @_; my $count = 0; if ((ref($need_env_update) eq 'ARRAY') && (ref($storehash) eq 'HASH')) { my %crsinfo = &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.'); if (ref($crsinfo{$env{'request.course.id'}}) eq 'HASH') { foreach my $key (@{$need_env_update}) { if ($key eq 'description' && defined($storehash->{$key})) { &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.description' => $storehash->{$key}}); $crsinfo{$env{'request.course.id'}}{'description'} = $storehash->{$key}; $count ++; } elsif (($key eq 'cloners') || ($key eq 'hidefromcat') || ($key eq 'categories')) { &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.'.$key => $storehash->{$key}}); $crsinfo{$env{'request.course.id'}}{$key} = $storehash->{$key}; $count ++; } } if ($count) { my $putresult = &Apache::lonnet::courseidput($cdom,\%crsinfo,$chome,'notime'); } } } return; } sub display_disallowed { my ($item,$disallowed,$prefs) = @_; my $output; if ((ref($disallowed) eq 'HASH') && (ref($prefs) eq 'HASH')) { if (keys(%{$disallowed})) { if ($item eq 'cloners') { my @fails; my %lt = &Apache::lonlocal::texthash ( format => 'Invalid format', domain => 'Domain does not exist', newuser => 'LON-CAPA user(s) do(es) not exist.', ); foreach my $error ('format','domain','newuser') { if (defined($disallowed->{$error})) { my $msg = ''.$disallowed->{$error}.', '.&mt('reason').' - '. $lt{$error}; if ($error eq 'newuser') { $msg .= '
'.&mt('Please [_1]add the user(s)[_2] before returning to the [_3]Course Configuration[_2] to add as potential cloners.','','',''); } push(@fails,$msg); } } if (@fails) { $output .= ''.&mt('Unable to add to allowed cloners: '). ''.join(';  ',@fails).'.
'; } } elsif ($item eq 'rolenames') { my %lt = &Apache::lonlocal::texthash ( replacements => 'Name already used to replace a different standard role name', regulars => 'Name already used as a standard role name', customrole => 'Name already used as the name of a custom role', ); my @fails; foreach my $error ('replacements','regulars','customrole') { if (ref($disallowed->{$error}) eq 'ARRAY') { push(@fails,''.join(', ',@{$disallowed->{$error}}). ', '.&mt('reason').' - '.$lt{'error'}); } } if (@fails) { $output .= ''. &mt('Unable to include amongst replacements for role names: '). ''.join(';  ',@fails).'.
'; } } elsif (($item eq 'feedback') || ($item eq 'discussion') || ($item eq 'localization')) { $output .= ''; if ($item eq 'feedback') { $output .= &mt('Unable to include as a recipient of course feedback for:'); } elsif ($item eq 'discussion') { $output .= &mt('Unable to include in user-based access control for:'); } elsif ($item eq 'localization') { $output .= &mt('Unable to include in course localization:'); } $output .= '
    '; foreach my $key (sort(keys(%{$disallowed}))) { my $itemtext = $prefs->{$item}{'itemtext'}{$key}; $output .= '
  • '.$itemtext.' - '; if ($item eq 'localization') { $output .= &mt('reason - unsupported language: [_1]', ''.$disallowed->{$key}.''); } else { $output .= &mt('reason - invalid user: [_1]', ''.$disallowed->{$key}.'').'
  • '; } } $output .= '

'; } } } return $output; } sub get_course { my ($courseid) = @_; if (!defined($courseid)) { $courseid = $env{'request.course.id'}; } my $cdom=$env{'course.'.$courseid.'.domain'}; my $cnum=$env{'course.'.$courseid.'.num'}; return ($cnum,$cdom); } sub get_jscript { my ($cdom,$phase) = @_; my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom); my ($jscript,$categorize_js); my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript(); my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset'); my $cloners_js = &cloners_javascript($phase); if ($can_categorize) { $categorize_js = <'. "\n".$stubrowse_js."\n"; return $jscript; } sub cloners_javascript { my ($formname) = @_; return <<"ENDSCRIPT"; function update_cloners(caller,num) { var delidx = getIndexByName('cloners_delete'); var actidx = getIndexByName('cloners_activate'); if (caller == 'cloners_all') { var selall; for (var i=0; i{'categories'})."\n"; } } if (!defined($categoriesform)) { $categoriesform = &mt('No categories defined for this domain'); } my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom); my %items = ( 'url' => { text => ''.&mt($itemtext->{'url'}).''.(' 'x2). '
". &mt('Select Map').'
'. &mt('Modification may make assessment data inaccessible!'). '', input => 'textbox', size => '40', }, 'description' => { text => ''.&mt($itemtext->{'description'}).'', input => 'textbox', size => '25', }, 'courseid' => { text => ''.&mt($itemtext->{'courseid'}).'
'.'('. &mt('internal, optional').')', input => 'textbox', size => '25', }, 'cloners' => { text => ''.&mt($itemtext->{'cloners'}).'
'. &mt('Course Coordinators included automatically'), input => 'textbox', size => '40', }, 'rolenames' => { text => ''.&mt($itemtext->{'rolenames'}).'
'. '('.&mt('To replace the standard title for a course role, enter a title, otherwise leave blank').')', input => 'textbox', size => '20', }, 'externalsyllabus' => { text => ''.&mt($itemtext->{'externalsyllabus'}).'
('. &mt('not using syllabus template)'), input => 'textbox', size => '40', }, 'hidefromcat' => { text => ''.&mt($itemtext->{'hidefromcat'}).'
'. ' ('.&mt('included by default if assigned institutional code, or categorized').')', input => 'radio', }, 'categories' => { text => ''.&mt($itemtext->{'categories'}).' '. &mt('Display Categories').'', input => 'textbox', size => '25', }, ); my $datatable; my $count = 0; foreach my $item (@{$ordered}) { if ($item eq 'hidefromcat') { next if (!$can_toggle_cat); } elsif ($item eq 'categories') { next if (!$can_categorize); } $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') { my $includeempty = 1; my $num = 0; $datatable .= &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). '
'. (' 'x2).'{$item} ne '*') { $datatable .= ' checked="checked" '; } $datatable .= ' onchange="javascript:update_cloners('. "'cloners_all'".');"/>'.&mt('No').'
'.&mt('Or'). '
'. &Apache::loncommon::start_data_table(); my @cloners; if ($settings->{$item} eq '') { $datatable .= &new_cloners_dom_row($cdom,'0'); } elsif ($settings->{$item} ne '*') { my @entries = split(/,/,$settings->{$item}); if (@entries > 0) { foreach my $entry (@entries) { my ($uname,$udom) = split(/:/,$entry); if ($uname eq '*') { $datatable .= &Apache::loncommon::start_data_table_row(). ''. &mt('Domain:').' '.$udom. '
'. ''. &Apache::loncommon::end_data_table_row(); $num ++; } else { push(@cloners,$entry); } } } } my $add_domtitle = &mt('Any user in additional domain:'); if ($settings->{$item} eq '*') { $add_domtitle = &mt('Any user in specific domain:'); } elsif ($settings->{$item} eq '') { $add_domtitle = &mt('Any user in other domain:'); } my $cloners_str = join(',',@cloners); $datatable .= &Apache::loncommon::start_data_table_row(). ''. $add_domtitle.'
'. &Apache::loncommon::select_dom_form('','cloners_newdom', $includeempty). ''. ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). '
'.&mt('And'). '
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''. &mt('Specific users').' ('. &mt('user:domain,user:domain').')
'. &Apache::lonhtmlcommon::textbox($item,$cloners_str, $items{$item}{'size'}). ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); } elsif ($item eq 'rolenames') { $datatable .= &Apache::loncommon::start_data_table(); foreach my $role ('cc','in','ta','ep','ad','st') { $datatable .= &Apache::loncommon::start_data_table_row(). ''. &Apache::lonnet::plaintext($role,$crstype,undef,1). ''. &Apache::lonhtmlcommon::textbox('rolenames_'.$role, $settings->{$role.'.plaintext'}, $items{$item}{size}).''. &Apache::loncommon::end_data_table_row(); } $datatable .= &Apache::loncommon::end_data_table().''; } elsif ($item eq 'categories') { my $launcher = 'onFocus="this.blur();javascript:catsbrowser();";'; $datatable .= ''. &Apache::lonhtmlcommon::textbox($item.'_display',$settings->{$item}, $items{$item}{size},$launcher); } else { $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub new_cloners_dom_row { my ($newdom,$num) = @_; my $output; if ($newdom ne '') { $output .= &Apache::loncommon::start_data_table_row(). ''. &mt('Any user in domain:').' '.$newdom.''. (' 'x2).''.(' 'x2). ''. &Apache::loncommon::end_data_table_row(); } return $output; } sub can_modify_catsettings { my ($dom) = @_; my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$dom); my ($can_toggle_cat,$can_categorize); if (ref($domconf{'coursecategories'}) eq 'HASH') { if ($domconf{'coursecategories'}{'togglecats'} eq 'crs') { $can_toggle_cat = 1; } if ($domconf{'coursecategories'}{'categorize'} eq 'crs') { $can_categorize = 1; } } return ($can_toggle_cat,$can_categorize); } sub assign_course_categories { my ($r) = @_; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $hascats = 0; my $cathash; my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$cdom); if (ref($domconf{'coursecategories'}) eq 'HASH') { $cathash = $domconf{'coursecategories'}{'cats'}; if (ref($cathash) eq 'HASH') { $hascats = 1; } } my $catwin_js; if ($hascats) { my $alert = &mt('Use \"Save\" in the main window to save course categories'); $catwin_js = < function updateCategories() { var newcategories = ''; var unescapedcats = ''; if (document.chgcats.usecategory.length) { for (var i=0; i 0) { newcategories = newcategories.slice(0,-1); } if (unescapedcats.length > 0) { unescapedcats = unescapedcats.slice(0,-3); } } else { if (document.chgcats.usecategory.checked == true) { newcategories = document.chgcats.usecategory.value; unescapedcats = document.chgcats.catname.value; } } opener.document.display.categories.value = newcategories; opener.document.display.categories_display.value = unescapedcats; alert("$alert"); self.close(); return; } ENDSCRIPT } else { my $onload; } my $start_page = &Apache::loncommon::start_page('Course Categories',$catwin_js, {'only_body' => 1,}); my $end_page = &Apache::loncommon::end_page(); my $categoriesform = '

'.&mt('Categorize Course').'

'; if ($hascats) { my %currsettings = &Apache::lonnet::get('environment',['hidefromcat','categories'],$cdom,$cnum); $categoriesform .= &mt('Assign one or more categories to this course.').'

'. '
'."\n". &Apache::loncommon::assign_categories_table($cathash, $currsettings{'categories'})."\n". '

'; } else { $categoriesform .= &mt('No categories defined for this domain'); } $r->print($start_page.$categoriesform.$end_page); return; } sub print_localization { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( languages => { text => &mt($itemtext->{'languages'}).'
'. &mt("(will override user's preference)"), input => 'selectbox', }, timezone => { text => &mt($itemtext->{'timezone'}), input => 'selectbox', }, datelocale => { text => &mt($itemtext->{'datelocale'}), input => 'selectbox', }, ); my $datatable; my $count = 0; foreach my $item (@{$ordered}) { $count ++; $datatable .= &item_table_row_start($items{$item}{text},$count); if ($item eq 'timezone') { my $includeempty = 1; my $timezone = &Apache::lonlocal::gettimezone(); $datatable .= &Apache::loncommon::select_timezone($item,$timezone,undef, $includeempty); } elsif ($item eq 'datelocale') { my $includeempty = 1; my $locale_obj = &Apache::lonlocal::getdatelocale(); my $currdatelocale; if (ref($locale_obj)) { $currdatelocale = $locale_obj->id(); } $datatable .= &Apache::loncommon::select_datelocale($item,$currdatelocale, undef,$includeempty); } else { if ($settings->{$item} eq '') { $datatable .= &Apache::loncommon::select_language('languages_0','',1); } else { my $num = 0; my @languages = split(/\s*[,;:]\s*/,$settings->{$item}); $datatable .= &Apache::loncommon::start_data_table(); if (@languages > 0) { my %langchoices = &get_lang_choices(); foreach my $lang (@languages) { my $showlang = $lang; if (exists($langchoices{$lang})) { $showlang = $langchoices{$lang}; } $datatable .= &Apache::loncommon::start_data_table_row(). ''. &mt('Language:').' '.$showlang. '
'. ''. &Apache::loncommon::end_data_table_row(); $num ++; } } $datatable .= &Apache::loncommon::start_data_table_row(). ''. &mt('Additional language:'). '
'. &Apache::loncommon::select_language('languages_'.$num,'',1). ''. ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); } } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub get_lang_choices { my %langchoices; foreach my $id (&Apache::loncommon::languageids()) { my $code = &Apache::loncommon::supportedlanguagecode($id); if ($code) { $langchoices{$code} = &Apache::loncommon::plainlanguagedescription($id); } } return %langchoices; } sub print_feedback { my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'question.email' => { text => ''.&mt($itemtext->{'question.email'}).'', input => 'textbox', size => '50', }, 'comment.email' => { text => ''.&mt($itemtext->{'comment.email'}).'', input => 'textbox', size => '50', }, 'policy.email' => { text => ''.&mt($itemtext->{'policy.email'}).'', input => 'textbox', size => '50', }, ); my $datatable; my $count = 0; my ($cnum) = &get_course(); 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:', ); foreach my $item (@{$ordered}) { $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}); } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub user_table { my ($cdom,$item,$sections,$currvalue,$lt) = @_; my $output; if ($currvalue eq '') { $output .= &select_recipient($item,'0',$cdom,$sections); } else { my $num = 0; my @curr = split(/,/,$currvalue); $output .= &Apache::loncommon::start_data_table(); my ($currusers); foreach my $val (@curr) { next if ($val eq ''); my ($uname,$udom,$seclist) = ($val =~ /^($match_username):($match_domain)(\(?[^\)]*\)?)$/); my @selsec; if ($seclist) { $seclist =~ s/(^\(|\)$)//g; @selsec = split(/\s*;\s*/,$seclist); } $currusers .= ''. ''. ''. ''.(' 'x2). &Apache::loncommon::aboutmewrapper( &Apache::loncommon::plainname($uname,$udom,'firstname'), $uname,$udom,'aboutuser'); if (ref($sections) eq 'ARRAY') { if (@{$sections}) { $currusers.= (' 'x3).$lt->{'sec'}.' '. &select_sections($item,$num,$sections, \@selsec); } } $currusers .= ''; $num ++; } if ($num) { $output .= &Apache::loncommon::start_data_table_row(). ''; if ($num > 1) { $output .= $lt->{'currone'}; } else { $output .= $lt->{'currmult'}; } $output .= '
'. ''.$currusers.'
'. &Apache::loncommon::end_data_table_row(); } $output .= &Apache::loncommon::start_data_table_row(). ''. $lt->{'add'}.'
'. &select_recipient($item,$num,$cdom,$sections). ''. ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); } return $output; } sub select_recipient { my ($item,$num,$cdom,$sections,$selected,$includeempty) = @_; my $domform = &Apache::loncommon::select_dom_form($cdom,$item.'_udom_'.$num,$includeempty); my $selectlink = &Apache::loncommon::selectstudent_link('display',$item.'_uname_'.$num, $item.'_udom_'.$num,1); my $css_class = ($num % 2)?'LC_even_row':'LC_odd_row'; my $output = ''. ''; if (ref($sections) eq 'ARRAY') { if (@{$sections}) { $output .= ''; } } $output .= '
'.&mt('Username').'
'. '
'.&mt('Domain').'
'.$domform.'
'.&mt('Sections').'
'. &select_sections($item,$num,$sections,$selected).'
'. $selectlink.'
'; return $output; } sub select_sections { my ($item,$num,$sections,$selected) = @_; my ($output,@currsecs,$allsec); if (ref($selected) eq 'ARRAY') { @currsecs = @{$selected}; } if (!@currsecs) { $allsec = ' selected="selected"'; } if (ref($sections) eq 'ARRAY') { if (@{$sections}) { my $mult; if (@{$sections} > 1) { $mult = ' multiple="multiple"'; if (@{$sections} > 3) { $mult .= ' size="4"'; } } $output = ''; } } return $output; } sub print_discussion { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'plc.roles.denied' => { text => ''.&mt($itemtext->{'plc.roles.denied'}).''. &Apache::loncommon::help_open_topic("Course_Disable_Discussion"). &mt('(roles-based)'), input => 'checkbox', }, 'plc.users.denied' => { text => ''.&mt($itemtext->{'plc.users.denied'}).'
'. &mt('(specific user(s))'), input => 'checkbox', }, 'pch.roles.denied' => { text => ''.&mt($itemtext->{'pch.roles.denied'}).''. &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'
'. &mt('(role-based)'), input => 'checkbox', }, 'pch.users.denied' => { text => ''.&mt($itemtext->{'pch.users.denied'}).'
'. &mt('(specific user(s))'), input => 'checkbox', }, 'allow_limited_html_in_feedback' => { text => ''.&mt($itemtext->{'allow_limited_html_in_feedback'}).'', input => 'radio', }, 'allow_discussion_post_editing' => { text => ''.&mt($itemtext->{'allow_discussion_post_editing'}).'', input => 'checkbox', }, ); my $datatable; my $count; my ($cnum) = &get_course(); 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:', ); foreach my $item (@{$ordered}) { $count ++; $datatable .= &item_table_row_start($items{$item}{text},$count); if ($item eq 'plc.roles.denied') { $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). '
'; } elsif ($item eq 'plc.users.denied') { $datatable .= &user_table($cdom,$item,undef, $settings->{$item},\%lt); } elsif ($item eq 'pch.roles.denied') { $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). '
'; } elsif ($item eq 'pch.users.denied') { $datatable .= &user_table($cdom,$item,undef, $settings->{$item},\%lt); } elsif ($item eq 'allow_limited_html_in_feedback') { $datatable .= &yesno_radio($item,$settings); } elsif ($item eq 'allow_discussion_post_editing') { $datatable .= &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''.&mt('Role').''. &mt('Sections').''. &Apache::loncommon::end_data_table_row(). &role_checkboxes($cdom,$cnum,$item,$settings,1). &Apache::loncommon::end_data_table(); } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub role_checkboxes { my ($cdom,$cnum,$item,$settings,$showsections) = @_; my @roles = ('st','ad','ta','ep','in','cc'); my $output; my (@current,@curr_roles,%currsec,@sections); if ($showsections) { my %sections = &Apache::loncommon::get_sections($cdom,$cnum); @sections = sort( { $a <=> $b } keys(%sections)); } if (ref($settings) eq 'HASH') { if ($settings->{$item}) { @current = split(',',$settings->{$item}); if ($showsections) { foreach my $role (@current) { if ($role =~ /:/) { my ($trole,$sec) = split(':',$role); push(@curr_roles,$trole); if (ref($currsec{$trole}) eq 'ARRAY') { if (!grep(/^\Q$sec\E/,@{$currsec{$trole}})) { push(@{$currsec{$trole}},$sec); } } else { $currsec{$trole} = [$sec]; } } else { push(@curr_roles,$role); } } @current = @curr_roles; } } } my $numinrow = 3; my $count = 0; foreach my $role (@roles) { my $checked = ''; if (grep(/^\Q$role\E$/,@current)) { $checked = ' checked="checked" '; } my $plrole=&Apache::lonnet::plaintext($role); if ($showsections) { $output .= &Apache::loncommon::start_data_table_row(); } else { my $rem = $count%($numinrow); if ($rem == 0) { if ($count > 0) { $output .= ''; } $output .= ''; } } $output .= ''; if ($showsections) { $output .= ''. &select_sections($item,$role,\@sections,$currsec{$role}). ''; } $count ++; } my %adv_roles = &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1); my $total = @roles; foreach my $role (sort(keys(%adv_roles))) { if ($role =~ m{^cr/($match_domain)/($match_name)/\w$}) { my $rolename = $3; my $value = 'cr_'.$1.'_'.$2.'_'.$rolename; my $checked = ''; if (grep(/^\Q$value\E$/,@current)) { $checked = ' checked="checked" '; } if ($showsections) { $output .= &Apache::loncommon::start_data_table_row(); } else { my $rem = $count%($numinrow); if ($rem == 0) { if ($count > 0) { $output .= ''; } $output .= ''; } } $output .= ''; if ($showsections) { $output .= ''. &select_sections($item,$role,\@sections,$currsec{$role}). ''.&Apache::loncommon::end_data_table_row(); } $total ++; $count ++; } } if (!$showsections) { my $rem = $total%($numinrow); my $colsleft = $numinrow - $rem; if ($colsleft > 1 ) { $output .= ''. ' '; } elsif ($colsleft == 1) { $output .= ' '; } $output .= ''; } return $output; } sub print_classlists { my ($position,$cdom,$settings,$itemtext,$rowtotal) = @_; my @ordered; if ($position eq 'top') { @ordered = ('default_enrollment_start_date', 'default_enrollment_end_date'); } elsif ($position eq 'middle') { @ordered = ('nothideprivileged'); } else { @ordered = ('student_classlist_view', 'student_opt_in','student_classlist_portfiles'); } my %items = ( 'default_enrollment_start_date' => { text => ''.&mt($itemtext->{'default_enrollment_start_date'}).'', input => 'dates', }, 'default_enrollment_end_date' => { text => ''.&mt($itemtext->{'default_enrollment_end_date'}).'', input => 'dates', }, 'nothideprivileged' => { text => ''.&mt($itemtext->{'nothideprivileged'}).'', input => 'checkbox', }, 'student_classlist_view' => { text => ''.&mt($itemtext->{'student_classlist_view'}).'', input => 'selectbox', options => { disabled => &mt('No viewable classlist'), section => &mt("Classlist of viewer's section"), all => &mt('Classlist of all students'), }, order => ['disabled','all','section'], }, 'student_opt_in' => { text => ''.&mt($itemtext->{'student_opt_in'}).'', input => 'radio', }, 'student_classlist_portfiles' => { text => ''.&mt($itemtext->{'student_classlist_portfiles'}).'', input => 'radio', }, ); unless (($settings->{'student_classlist_view'} eq 'all') || ($settings->{'student_classlist_view'} eq 'section')) { $settings->{'student_classlist_view'} = 'disabled'; } return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal); } sub print_appearance { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'default_xml_style' => { text => ''.&mt($itemtext->{'default_xml_style'}).' '. ''.&mt('Select Style File').'', input => 'textbox', size => 35, }, 'pageseparators' => { text => ''.&mt($itemtext->{'pageseparators'}).'', input => 'radio', }, 'disable_receipt_display' => { text => ''.&mt($itemtext->{'disable_receipt_display'}).'', input => 'radio', }, 'texengine' => { text => ''.&mt($itemtext->{'texengine'}).'', input => 'selectbox', options => { jsMath => 'jsMath', mimetex => &mt('Convert to Images'), tth => &mt('TeX to HTML'), }, order => ['jsMath','mimetex','tth'], nullval => &mt("None specified - use student's choice"), }, 'tthoptions' => { text => ''.&mt($itemtext->{'tthoptions'}).'', input => 'textbox', size => 40, }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); } sub print_grading { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'grading' => { text => ''.&mt($itemtext->{'grading'}).''. &Apache::loncommon::help_open_topic('GradingOptions'), input => 'selectbox', options => { standard => &mt('Standard: shows points'), external => &mt('External: shows number of completed parts'), spreadsheet => &mt('Spreadsheet: (with link to detailed scores)'), }, order => ['standard','external','spreadsheet'], }, 'rndseed' => { text => ''.&mt($itemtext->{'rndseed'}).''. ''.'
'. &mt('Modifying this will make problems have different numbers and answers!'). '
', input => 'selectbox', options => { '32bit' => '32bit', '64bit' => '64bit', '64bit2' => '64bit2', '64bit3' => '64bit3', '64bit4' => '64bit4', '64bit5' => '64bit5', }, order => ['32bit','64bit','64bit2','64bit3','64bit4','64bit5'], }, 'receiptalg' => { text => ''.&mt($itemtext->{'receiptalg'}).'
'. &mt('This controls how receipt numbers are generated.'), input => 'selectbox', options => { receipt => 'receipt', receipt2 => 'receipt2', receipt3 => 'receipt3', }, order => ['receipt','receipt2','receipt3'], }, 'disablesigfigs' => { text => ''.&mt($itemtext->{'disablesigfigs'}).'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); } sub print_printouts { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( problem_stream_switch => { text => ''.&mt($itemtext->{'problem_stream_switch'}).'', input => 'radio', }, suppress_tries => { text => ''.&mt($itemtext->{'suppress_tries'}).'', input => 'radio', }, default_paper_size => { text => ''.&mt($itemtext->{'default_paper_size'}).'', input => 'selectbox', options => { Letter => &mt('Letter').' [8 1/2x11 in]', Legal => &mt('Legal').' [8 1/2x14 in]', Tabloid => &mt('Tabloid').' [11x17 in]', Executive => &mt('Executive').' [7 1/2x10 in]', A2 => &mt('A2').' [420x594 mm]', A3 => &mt('A3').' [297x420 mm]', A4 => &mt('A4').' [210x297 mm]', A5 => &mt('A5').' [148x210 mm]', A6 => &mt('A6').' [105x148 mm]', }, order => ['Letter','Legal','Tabloid','Executive','A2','A3','A4','A5','A6'], nullval => 'None specified', }, print_header_format => { text => ''.&mt($itemtext->{'print_header_format'}).'', input => 'checkbox', }, disableexampointprint => { text => ''.&mt($itemtext->{'disableexampointprint'}).'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); } sub print_spreadsheet { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my $SelectSpreadsheetFile=&mt('Select Spreadsheet File'); my %items = ( spreadsheet_default_classcalc => { text => ''.&mt($itemtext->{'spreadsheet_default_classcalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, spreadsheet_default_studentcalc => { text => ''.&mt($itemtext->{'spreadsheet_default_studentcalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, spreadsheet_default_assesscalc => { text => ''.&mt($itemtext->{'spreadsheet_default_assesscalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, hideemptyrows => { text => ''.&mt($itemtext->{'hideemptyrows'}).'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); } sub print_bridgetasks { my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( task_messages => { text => ''.&mt($itemtext->{'task_messages'}).'', input => 'selectbox', options => { only_student => &mt('Send message to student'), student_and_user_notes_screen => &mt('Message to student and add to user notes'), }, order => ['only_student','student_and_user_notes_screen'], nullval => &mt('No message or record in user notes'), }, task_grading => { text => ''.&mt($itemtext->{'task_grading'}).'', input => 'selectbox', options => { any => &mt('Grade BTs in any section'), section => &mt('Grade BTs only in own section') }, order => ['any','section'], }, suppress_embed_prompt => { text => ''.&mt($itemtext->{'suppress_embed_prompt'}).''. ' '.&mt('(applies when current role is student)').'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); } sub print_other { my ($cdom,$settings,$allitems,$rowtotal) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } my @ordered = &get_other_items($cdom,$settings,$allitems); my %items; foreach my $parameter (@ordered) { $items{$parameter} = { text => ''.$parameter.'', input => 'textbox', size => '15', }, } push (@ordered,'newp_value'); $items{'newp_value'} = { text => ''.&mt('Create New Environment Variable').'
'. '', input => 'textbox', size => '30', }; my $output = &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal); } sub get_other_items { my ($cdom,$settings,$allitems) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } my @ordered; if (ref($settings) eq 'HASH') { foreach my $parameter (sort(keys(%{$settings}))) { next if (grep/^\Q$parameter\E$/,@{$allitems}); next if (($parameter eq 'course.helper.not.run') && (!exists($env{'user.role.dc./'.$env{'request.role.domain'}.'/'}))); unless (($parameter =~ m/^internal\./)||($parameter =~ m/^metadata\./) || ($parameter =~ m/^selfenroll_/) || ($parameter =~ /_selfenroll$/) || ($parameter eq 'type') || ($parameter =~ m/^(cc|in|ta|ep|ad|st)\.plaintext$/)) { push(@ordered,$parameter); } } } return @ordered; } sub item_table_row_start { my ($text,$count) = @_; my $output; if ($count%2) { $output .= ''; } else { $output .= ''; } $output .= ''.$text. ''; return $output; } sub item_table_row_end { return ''; } sub yesno_radio { my ($item,$settings) = @_; my $itemon = ' '; my $itemoff = ' checked="checked" '; if (ref($settings) eq 'HASH') { if ($settings->{$item} eq 'yes') { $itemon = $itemoff; $itemoff = ' '; } } return ' '. ''; } sub select_from_options { my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange) = @_; my $output; if ((ref($order) eq 'ARRAY') && (ref($options) eq 'HASH')) { $output=''.&mt('Hidden').' '. ''. ''; } $datatable .= ''; } else { $datatable .= &mt('No Domain Coordinators have course roles'); } return $datatable; } sub print_hdrfmt_row { my ($item,$settings) = @_; my @curr; my $currnum = 0; my $maxnum = 2; my $currstr; if ($settings->{$item} ne '') { $currstr .= ''.&mt('Current print header:').' '. $settings->{$item}.'
'; my @current = split(/(%\d*[nca])/,$settings->{$item}); foreach my $item (@current) { unless ($item eq '') { push(@curr,$item); } } $currnum = @curr; $maxnum += $currnum; } my $output = < function reOrder(chgnum) { var maxnum = $maxnum; var oldidx = 'printfmthdr_oldpos_'+chgnum; var newidx = 'printfmthdr_pos_'+chgnum; oldidx = getIndexByName(oldidx); newidx = getIndexByName(newidx); var oldpos = document.display.elements[oldidx].value; var newpos = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value; document.display.elements[oldidx].value = newpos; var chgtype = 'up'; if (newpos < oldpos) { chgtype = 'down'; } for (var j=0; j oldpos) && (currpos <= newpos)) { document.display.elements[newidx].selectedIndex = currsel-1; document.display.elements[oldidx].value = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value; } } else { if ((currpos >= newpos) && (currpos < oldpos)) { document.display.elements[newidx].selectedIndex = currsel+1; document.display.elements[oldidx].value = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value; } } } } return; } function getIndexByName(item) { for (var i=0;i ENDJS $output .= $currstr.&Apache::loncommon::start_data_table(); if (@curr > 0) { for (my $i=0; $i<@curr; $i++) { my $pos = $i+1; $output .= &Apache::loncommon::start_data_table_row(). ''. &position_selector($pos,$i,$maxnum).&mt('Delete:'). ''; if ($curr[$i] =~ /^%\d*[nca]$/) { my ($limit,$subst) = ($curr[$i] =~ /^%(\d*)([nca])$/); $output .= ''. &substitution_selector($i,$subst,$limit).''; } else { $output .= ''.&mt('Text').'
'. ''; } $output .= &Apache::loncommon::end_data_table_row(); } } my $pos = $currnum+1; $output .= &Apache::loncommon::start_data_table_row(). ''. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''. &substitution_selector($currnum).''. &Apache::loncommon::end_data_table_row(); $pos ++; $currnum ++; $output .= &Apache::loncommon::start_data_table_row(). ''. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''. ''.&mt('Text').'
'. ''. ''. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); return $output; } sub position_selector { my ($pos,$num,$maxnum) = @_; my $output = ''; return $output; } sub substitution_selector { my ($num,$subst,$limit) = @_; my %lt = &Apache::lonlocal::texthash( n => 'student name', c => 'course ID', a => 'assignment note', ); my $output .= &mt('Substitution').'
'. ''.&mt('Size limit').'
'. ''; return $output; } 1;