--- loncom/interface/courseprefs.pm 2010/01/18 20:14:25 1.21 +++ loncom/interface/courseprefs.pm 2018/05/08 01:48:18 1.87 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.21 2010/01/18 20:14:25 raeburn Exp $ +# $Id: courseprefs.pm,v 1.87 2018/05/08 01:48:18 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,$noedit +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; @@ -36,9 +215,15 @@ use Apache::lonnet; use Apache::loncommon(); use Apache::lonhtmlcommon(); use Apache::lonconfigsettings; +use Apache::lonrelrequtils; +use Apache::lonparmset; +use Apache::courseclassifier; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); +my $registered_cleanup; +my $modified_courses; + sub handler { my $r=shift; if ($r->header_only) { @@ -48,11 +233,11 @@ sub handler { } my $context = 'course'; my $cid = $env{'request.course.id'}; - my ($cnum,$cdom) = &get_course($cid); + my ($cnum,$cdom,$chome) = &get_course($cid); my $crstype = &Apache::loncommon::course_type(); - my $parm_permission = &Apache::lonnet::allowed('opa',$cid); + my ($parm_permission,$allowed) = &get_permission($cid); my $navmap = Apache::lonnavmaps::navmap->new(); - if ($parm_permission && $navmap) { + if ($allowed && $navmap) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; } else { @@ -77,6 +262,9 @@ sub handler { return HTTP_NOT_ACCEPTABLE; } + $registered_cleanup=0; + @{$modified_courses}=(); + &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['phase','actions','origin']); &Apache::lonhtmlcommon::clear_breadcrumbs(); @@ -88,11 +276,14 @@ sub handler { my %lt; if ($crstype eq 'Community') { %lt = ( - conf => 'Community Configuration', - edit => 'Edit Community Configuration', + conf => 'Community Settings', + edit => 'Edit Community Settings', gens => 'General community settings', idnu => 'Community ID or number', + unco => 'Unique code', desc => 'Community Description', + ownr => 'Community Owner', + cown => 'Community Co-owners', catg => 'Categorize community', excc => 'Exclude from community catalog', clon => 'Users allowed to clone community', @@ -105,19 +296,23 @@ sub handler { defd => 'Default dates for member access', stuv => 'Member-viewable membership list options', stul => 'Member agreement needed to be listed', - clas => 'Membership and Facilitator Listing', - priv => 'Privileged users (Domain Coordinators) in facilitator listing', + clas => 'Membership and facilitator listing', + prus => 'Privileged users (Domain Coordinators) in facilitator listing', defc => 'Default Community Spreadsheet', defs => 'Default User Spreadsheet', seme => 'Send message to member when clicking Done on Tasks' ); } else { %lt = ( - conf => 'Course Configuration', - edit => 'Edit Course Configuration', + conf => 'Course Settings', + edit => 'Edit Course Settings', gens => 'General course settings', idnu => 'Course ID or number', + unco => 'Unique code', desc => 'Course Description', + cred => 'Student credits', + ownr => 'Course Owner', + cown => 'Course Co-owners', catg => 'Categorize course', excc => 'Exclude from course catalog', clon => 'Users allowed to clone course', @@ -130,13 +325,15 @@ sub handler { defd => 'Default dates for student access', stuv => 'Student-viewable classlist options', stul => 'Student agreement needed to be listed', - clas => 'Classlists and Staff Listing', - priv => 'Privileged users (Domain Coordinators) in staff listing', + clas => 'Classlists and staff listing', + prus => 'Privileged users (Domain Coordinators) in staff listing', + prdo => "Domains to check for privileged users (besides course's domain)", defc => 'Default Course Spreadsheet', defs => 'Default Student Spreadsheet', 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 = @@ -147,37 +344,58 @@ sub handler { $phase = $env{'form.phase'}; } - if ($phase eq 'categorizecourse') { + if (($phase eq 'categorizecourse') && ($parm_permission->{'categorizecourse'})) { &assign_course_categories($r,$crstype); return OK; } + if (($phase eq 'releaseinfo') && ($parm_permission->{'releaseinfo'})) { + my $loncaparev = $env{'course.'.$cid.'.internal.releaserequired'}; + if ($loncaparev) { + if (&display_loncaparev_constraints($r,$navmap,$loncaparev,$crstype)) { + push(@{$modified_courses},[$cdom,$cnum,$chome,$crstype]); + unless ($registered_cleanup) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\&update_releasereq,@{$handlers}]); + $registered_cleanup=1; + } + } + return OK; + } + } + my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', - 'spreadsheet','bridgetasks','other'); + 'spreadsheet','bridgetasks','lti','other'); my %prefs = ( 'courseinfo' => { text => $lt{'gens'}, - help => 'Course_Environment', - ordered => ['description','courseid','categories', - 'hidefromcat','externalsyllabus', - 'cloners','url','rolenames'], + help => 'Course_Prefs_General', + ordered => ['owner','co-owners','loncaparev','description', + 'clonedfrom','courseid','uniquecode','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'}, + 'uniquecode' => $lt{'unco'}, + 'categories' => $lt{'catg'}, + 'hidefromcat' => $lt{'excc'}, + 'cloners' => $lt{'clon'}, + 'externalsyllabus' => 'Syllabus status', + 'url' => 'Top Level Map', + 'rolenames' => $lt{'rept'}, + 'loncaparev' => $lt{'lcrv'}, + 'clonedfrom' => 'Cloned from', }, }, 'localization' => - { text => 'Language & Time Localization', - help => 'Course_Environment', + { text => 'Language and time localization', + help => 'Course_Prefs_Language', ordered => ['languages','timezone','datelocale'], itemtext => { languages => 'Languages used', @@ -187,7 +405,7 @@ sub handler { }, 'feedback' => { text => 'Feedback messages', - help => 'Course_Environment', + help => 'Course_Prefs_Feedback', header => [{col1 => 'Questions about:', col2 => 'Recipients'}], ordered => ['question.email','comment.email','policy.email'], @@ -199,23 +417,28 @@ sub handler { }, 'discussion' => { text => 'Discussion and Chat', - help => 'Course_Environment', - ordered => ['plc.roles.denied','plc.users.denied', - 'pch.roles.denied','pch.users.denied', + help => 'Course_Prefs_Discussions', + ordered => ['pch.roles.denied','pch.users.denied', + 'pac.roles.denied','pac.users.denied', + 'plc.roles.denied','plc.users.denied', 'allow_limited_html_in_feedback', - 'allow_discussion_post_editing'], + 'allow_discussion_post_editing', + 'discussion_post_fonts'], itemtext => { - 'plc.roles.denied' => 'No Resource Discussion', - 'plc.users.denied' => 'No Resource Discussion', - 'pch.roles.denied' => 'No Chat room use', - 'pch.users.denied' => 'No Chat room use', + 'pch.roles.denied' => 'No Resource Discussion', + 'pch.users.denied' => 'No Resource Discussion', + 'plc.roles.denied' => 'No Chat room use', + 'plc.users.denied' => 'No Chat room use', + 'pac.roles.denied' => 'No Anonymous Resource Discussion', + 'pac.users.denied' => 'No Anonymous Resource Discussion', allow_limited_html_in_feedback => 'Allow limited HTML in discussion', allow_discussion_post_editing => 'Users can edit/delete own discussion posts', + discussion_post_fonts => 'Discussion post fonts based on likes/unlikes', }, }, 'classlists' => { text => $lt{'clas'}, - help => 'Course_Environment', + help => 'Course_Prefs_Classlists', header => [{col1 => 'Type', col2 => $lt{'defd'}}, {col1 => 'Setting', @@ -224,34 +447,40 @@ sub handler { col2 => $lt{'stuv'}}], ordered => ['default_enrollment_start_date', 'default_enrollment_end_date', - 'nothideprivileged','student_classlist_view', - 'student_opt_in','student_classlist_portfiles'], + 'defaultcredits', + 'nothideprivileged','checkforpriv', + 'student_classlist_view', + 'student_classlist_opt_in','student_classlist_portfiles'], itemtext => { default_enrollment_start_date => 'Start date', default_enrollment_end_date => 'End date', - nothideprivileged => $lt{'priv'}, + nothideprivileged => $lt{'prus'}, + checkforpriv => $lt{'prdo'}, 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', + defaultcredits => $lt{'cred'}, }, }, 'appearance' => { text => 'Display of resources ', - help => 'Course_Environment', + help => 'Course_Prefs_Display', ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', - 'tthoptions'], + 'tthoptions','uselcmath','usejsme'], 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', + uselcmath => 'Student formula entry uses inline preview, not DragMath pop-up', + usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)', }, }, 'grading' => { text => 'Grading', - help => 'Course_Environment', + help => 'Course_Prefs_Grading', ordered => ['grading','rndseed', 'receiptalg','disablesigfigs'], itemtext => { @@ -264,7 +493,7 @@ sub handler { }, 'printouts' => { text => 'Printout generation', - help => 'Course_Environment', + help => 'Course_Prefs_Printouts', ordered => ['problem_stream_switch','suppress_tries', 'default_paper_size','print_header_format', 'disableexampointprint','canuse_pdfforms'], @@ -273,13 +502,13 @@ sub handler { 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', + disableexampointprint => 'Disable automatically printing point values on bubblesheet exams', canuse_pdfforms => 'Users can print problems as PDF forms and upload later for grading', }, }, 'spreadsheet' => { text => 'Spreadsheets', - help => 'Course_Environment', + help => 'Course_Prefs_Spreadsheet', ordered => ['spreadsheet_default_classcalc', 'spreadsheet_default_studentcalc', 'spreadsheet_default_assesscalc','hideemptyrows'], @@ -292,7 +521,7 @@ sub handler { }, 'bridgetasks' => { text => 'Bridge tasks', - help => 'Course_Environment', + help => 'Course_Prefs_Bridgetasks', ordered => ['task_messages','task_grading', 'suppress_embed_prompt'], itemtext => { @@ -301,31 +530,72 @@ sub handler { suppress_embed_prompt => 'Hide upload references prompt if uploading file to portfolio', }, }, + 'lti' => + { + text => 'LTI provider settings', + help => 'Course_Prefs_LTIProvider', + ordered => ['lti.override','lti.topmenu','lti.inlinemenu','lti.lcmenu'], + itemtext => { + 'lti.override' => 'Override domain defaults', + 'lti.topmenu' => 'Display LON-CAPA page header', + 'lti.inlinemenu' => 'Display LON-CAPA inline menu', + 'lti.lcmenu' => 'Menu items', + }, + }, 'other' => { text => 'Other settings', - help => 'Course_Environment', + help => 'Course_Prefs_Other', header => [ {col1 => 'Item', col2 => 'Value', }], }, ); - if ($phase eq 'process') { + if (($phase eq 'process') && ($parm_permission->{'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,$crstype); + $cnum,undef,\@allitems, + 'coursepref',$parm_permission); + } elsif (($phase eq 'display') && ($parm_permission->{'display'})) { + my $jscript = &get_jscript($cid,$cdom,$phase,$crstype,\%values); my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, - \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype); + \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype, + 'coursepref',$parm_permission); } else { &Apache::lonconfigsettings::display_choices($r,$phase,$context, - \@prefs_order,\%prefs); + \@prefs_order,\%prefs, + 'coursepref',$parm_permission); } return OK; } +sub get_permission { + my ($cid) = @_; + my %permission; + my $allowed = 0; + return (\%permission,$allowed) unless ($cid); + if (&Apache::lonnet::allowed('opa',$cid)) { + %permission= ( + 'pickactions' => 1, + 'categorizecourse' => 1, + 'releaseinfo' => 1, + 'process' => 1, + 'display' => 1, + ); + } elsif (&Apache::lonnet::allowed('vpa',$env{'request.course.id'})) { + %permission = ( + 'pickactions' => 1, + 'releaseinfo' => 1, + 'display' => 1, + ); + } + foreach my $perm (values(%permission)) { + if ($perm) { $allowed=1; last; } + } + return (\%permission,$allowed); +} + sub get_allitems { my (%prefs) = @_; my @allitems; @@ -343,92 +613,140 @@ sub get_allitems { } sub print_config_box { - my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype) = @_; + my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype,$parm_permission) = @_; my $ordered = $item->{'ordered'}; my $itemtext = $item->{'itemtext'}; + my $noedit; + if (ref($parm_permission) eq 'HASH') { + unless ($parm_permission->{'process'}) { + $noedit = 1; + } + } my $rowtotal = 0; my $output = - '

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

-
 '. - &Apache::loncommon::help_open_topic($item->{'help'}).''; + ' + + '."\n". + ''; if (($action eq 'feedback') || ($action eq 'classlists')) { $output .= ' + + + + + + + + '. + "'cloners_all'".');"'.$disabled.' />'.&mt('No').''. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). - '
'. + &mt($item->{text}); + if ($item->{'help'}) { + $output .= ' '. + &Apache::loncommon::help_open_topic($item->{'help'}); + } + $output .= '
'; if (exists $item->{'header'}->[0]->{'col1'} || exists $item->{'header'}->[0]->{'col2'}) { $output .= ' - - + '; + if ($action eq 'feedback') { + $output .= ' + '; } $rowtotal ++; if ($action eq 'feedback') { - $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'classlists') { - $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype); + $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).''.&mt($item->{'header'}->[0]->{'col1'}).''; + } else { + $output .= ' + '; + } + $output .= &mt($item->{'header'}->[0]->{'col2'}).'
+
'; - $output .= ' - + if ($action eq 'classlists') { + $output .= ' + '; if ($action eq 'classlists') { - $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal,$crstype). + $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit). '
'.&mt($item->{'header'}->[1]->{'col1'}).''.&mt($item->{'header'}->[1]->{'col2'}).''; + } else { + $output .= ' + '; + } + $output .= &mt($item->{'header'}->[1]->{'col2'}).'
+
'; - if (exists $item->{'header'}->[0]->{'col1'} || - exists $item->{'header'}->[0]->{'col2'}) { + if (exists $item->{'header'}->[2]->{'col1'} || + exists $item->{'header'}->[2]->{'col2'}) { $output .= ' - - + + '; } } } else { $output .= ' + + + +
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).''.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
'; if (exists $item->{'header'}->[0]->{'col1'} || exists $item->{'header'}->[0]->{'col2'}) { $output .= ' - - + '; + if (($action eq 'courseinfo') || ($action eq 'localization') || + ($action eq 'print_discussion')) { + $output .= ''; } } $rowtotal ++; if ($action eq 'courseinfo') { - $output .= &print_courseinfo($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); + $output .= &print_courseinfo($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'localization') { - $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'feedback') { - $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'discussion') { - $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal); - } elsif ($action eq 'classlists') { - $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype); + $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); + } elsif (($action eq 'classlists') || ($action eq 'viewableroster')) { + $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'appearance') { - $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); + $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'grading') { - $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); + $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'printouts') { - $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); + $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'spreadsheet') { - $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); + $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'bridgetasks') { - $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); + $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); + } elsif ($action eq 'lti') { + $output .= &print_lti($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'other') { - $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype); + $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype,$noedit); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).''.&mt($item->{'header'}->[0]->{'col1'}).''; + } else { + $output .= ''; + } + $output .= &mt($item->{'header'}->[0]->{'col2'}).'
-'; +

'; return ($output,$rowtotal); } @@ -452,7 +770,27 @@ sub process_changes { } } } elsif (ref($item->{'ordered'}) eq 'ARRAY') { - @ordered = @{$item->{'ordered'}}; + if ($action eq 'courseinfo') { + my ($can_toggle_cat,$can_categorize) = + &can_modify_catsettings($cdom,$crstype); + foreach my $entry (@{$item->{'ordered'}}) { + next if (($entry eq 'hidefromcat') && + (!$can_toggle_cat)); + next if (($entry eq 'categories') && + (!$can_categorize)); + next if (($entry eq 'loncaparev') || + ($entry eq 'owner') || + ($entry eq 'clonedfrom')); + push(@ordered,$entry); + } + } elsif ($action eq 'classlists') { + foreach my $entry (@{$item->{'ordered'}}) { + next if ($entry eq 'defaultcredits'); + push(@ordered,$entry); + } + } else { + @ordered = @{$item->{'ordered'}}; + } } if (@ordered > 0) { if ($action eq 'feedback') { @@ -501,9 +839,9 @@ sub process_changes { 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 ($actnum ne '-1') { + 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}); @@ -519,7 +857,7 @@ sub process_changes { my $clonedom = $env{'form.cloners_dom_'.$i}; if (&check_clone($clonedom,$disallowed) eq 'ok') { if (!grep(/^\*:\Q$clonedom\E$/,@clonedoms)) { - push (@clonedoms,'*:'.$clonedom); + push(@clonedoms,'*:'.$clonedom); } } } @@ -545,10 +883,14 @@ sub process_changes { 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); + $cloner =~ s/^\s+//; + $cloner =~ s/\s+$//; + unless ($cloner eq '') { + my ($uname,$udom) = split(':',$cloner); + if (&check_clone($udom,$disallowed,$uname) eq 'ok') { + if (!grep(/^\Q$cloner\E$/,@okcloners)) { + push(@okcloners,$cloner); + } } } } @@ -561,6 +903,37 @@ sub process_changes { } } } + if (ref($values) eq 'HASH') { + my (@code_order,%codedefaults); + &Apache::lonnet::auto_instcode_defaults($cdom,\%codedefaults, + \@code_order); + my $clonebycode; + if ($env{'form.cloners_instcode'}) { + if (@code_order > 0) { + my @standardnames = &Apache::loncommon::get_standard_codeitems(); + my %local_to_standard; + for (my $i=0; $i<@code_order; $i++) { + $local_to_standard{$code_order[$i]} = $standardnames[$i]; + } + foreach my $item (@code_order) { + my $key = $local_to_standard{$item}; + if ($key ne '') { + if ($env{'form.'.$key}) { + $clonebycode .= $key.'='.&escape($env{'form.'.$key}).'&'; + } + } + } + $clonebycode =~ s/\&$//; + } + } + if ($clonebycode) { + if ($newvalues{$entry}) { + $newvalues{$entry} .= ','.$clonebycode; + } else { + $newvalues{$entry} = $clonebycode; + } + } + } } if (ref($disallowed) eq 'HASH') { if (ref($disallowed->{'cloners'}) eq 'HASH') { @@ -569,6 +942,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') { @@ -626,7 +1073,8 @@ sub process_changes { } } } - } elsif (($entry eq 'plc.roles.denied') || ($entry eq 'pch.roles.denied')) { + } elsif (($entry eq 'plc.roles.denied') || ($entry eq 'pch.roles.denied') || + ($entry eq 'pac.roles.denied')) { my @denied = &Apache::loncommon::get_env_multiple('form.'.$entry); @denied = sort(@denied); my $deniedstr = ''; @@ -634,7 +1082,8 @@ sub process_changes { $deniedstr = join(',',@denied); } $newvalues{$entry} = $deniedstr; - } elsif (($entry eq 'plc.users.denied') || ($entry eq 'pch.users.denied')) { + } elsif (($entry eq 'plc.users.denied') || ($entry eq 'pch.users.denied') || + ($entry eq 'pac.users.denied')) { my $total = $env{'form.'.$entry.'_total'}; my $userstr = ''; my @denied; @@ -682,6 +1131,35 @@ sub process_changes { } } $newvalues{$entry} =~ s/,$//; + } elsif ($entry eq 'discussion_post_fonts') { + my ($classorder,$classtitles) = &discussion_vote_classes(); + my $fontchange = 0; + foreach my $class (@{$classorder}) { + my $ext_entry = $entry.'_'.$class; + my $size = $env{'form.'.$ext_entry.'_size'}; + my $unit = $env{'form.'.$ext_entry.'_unit'}; + my $weight = $env{'form.'.$ext_entry.'_weight'}; + my $style = $env{'form.'.$ext_entry.'_style'}; + my $other = $env{'form.'.$ext_entry.'_other'}; + $size =~ s/,//g; + $unit =~ s/,//g; + $weight =~ s/,//g; + $style =~ s/,//g; + $other =~ s/[^\w;:\s\-\%.]//g; + $other =~ s/(^\s+|\s+$)//g; + $newvalues{$ext_entry} = join(',',($size.$unit,$weight,$style,$other)); + my $current = $values->{$ext_entry}; + if ($values->{$ext_entry} eq '') { + $current = ',,,'; + } + if ($newvalues{$ext_entry} ne $current) { + $changes->{$ext_entry} = $newvalues{$ext_entry}; + $fontchange ++; + } + } + if ($fontchange) { + $changes->{$entry} = 1; + } } elsif ($entry eq 'nothideprivileged') { my @curr_nothide; my @new_nothide; @@ -737,8 +1215,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; } @@ -756,37 +1234,82 @@ sub process_changes { 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; + } elsif (($entry eq 'languages') || + ($entry eq 'checkforpriv')) { + my $settings; 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}.','; + $settings .= $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; + my $new = $env{'form.'.$entry.'_'.$total}; + if ($entry eq 'languages') { + my %langchoices = &get_lang_choices(); + if ($langchoices{$new}) { + $settings .= $new; + } else { + $settings =~ s/,$//; + $disallowed->{'localization'}{$entry} = $new; + } } else { - $langstr =~ s/,$//; - $disallowed->{'localization'}{$entry} = $newlang; + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + if ($domains{$new}) { + $settings .= $new; + } else { + $settings =~ s/,$//; + $disallowed->{'classlists'}{$entry} = $new; + } } } else { - $langstr =~ s/,$//; + $settings =~ s/,$//; + } + $newvalues{$entry} = $settings; + } elsif ($action eq 'lti') { + if ($entry eq 'lti.override') { + $newvalues{$entry} = $env{'form.'.$entry}; + } elsif (($entry eq 'lti.topmenu') || ($entry eq 'lti.inlinemenu')) { + if ($env{'form.lti.override'}) { + $newvalues{$entry} = $env{'form.'.$entry}; + } else { + $newvalues{$entry} = ''; + } + } elsif ($entry eq 'lti.lcmenu') { + if (($env{'form.lti.override'}) && + (($env{'form.lti.topmenu'}) || ($env{'form.lti.inlinemenu'}))) { + my @lcmenu = &Apache::loncommon::get_env_multiple('form.lti.lcmenu'); + my @newlcmenu; + if (@lcmenu) { + my @menuitems = ('fullname','coursetitle','role','logout','grades'); + foreach my $item (@menuitems) { + next if (($item eq 'grades') && (!$newvalues{'lti.inlinemenu'})); + if (grep(/^\Q$item\E$/,@lcmenu)) { + push(@newlcmenu,$item); + } + } + } + if (@newlcmenu) { + $newvalues{$entry} = join(',',@newlcmenu); + } else { + $newvalues{$entry} = 'none'; + } + } else { + $newvalues{$entry} = ''; + } } - $newvalues{$entry} = $langstr; } else { $newvalues{$entry} = $env{'form.'.$entry}; } - if ($newvalues{$entry} ne $values->{$entry}) { - $changes->{$entry} = $newvalues{$entry}; + unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts')) { + if ($newvalues{$entry} ne $values->{$entry}) { + $changes->{$entry} = $newvalues{$entry}; + } } } } @@ -838,7 +1361,7 @@ sub check_clone { sub store_changes { my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes,$crstype) = @_; my ($chome,$output); - my (%storehash,@delkeys,@need_env_update); + my (%storehash,@delkeys,@need_env_update,@oldcloner); if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) { %storehash = %{$values}; } else { @@ -862,16 +1385,16 @@ sub store_changes { $output .= '

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

'; if (ref($changes->{$item}) eq 'HASH') { if (keys(%{$changes->{$item}}) > 0) { - $output .= &mt('Changes made:').'
    '; + $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.'').'
    • '; + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',''.$key.'')).'
    • '; } else { - $output .= '
    • '.&mt('[_1] set to [_2]',''.$key.'', - "'$storehash{$key}'").'
    • '; + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.$key.'', + "'$storehash{$key}'")).'
    • '; } } } else { @@ -903,13 +1426,16 @@ sub store_changes { "'".$newname."'").''; } if ($msg ne '') { - $output .= '
    • '.&mt($displayname).'
        '.$msg.'
    • '; + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt($displayname)).'
        '.$msg.'
    • '; } } 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') || ($key eq 'discussion_post_fonts')) { + $displayval = $changes->{$item}{$key}; + } if ($item eq 'feedback') { if ($key =~ /^(question|policy|comment)(\.email)\.text$/) { $text = $prefs->{$item}->{'itemtext'}{$1.$2}; @@ -943,6 +1469,36 @@ sub store_changes { } $displayval = join(', ',@longroles); } + } elsif ($key eq 'discussion_post_fonts') { + my ($classorder,$classtitles)=&discussion_vote_classes(); + my ($styleorder,$styleitems)=&discussion_vote_styles(); + my $count = 1; + my $total = scalar(keys(%{$changes->{$item}})); + foreach my $class (@{$classorder}) { + $count ++; + next unless ($changes->{$item}{$key.'_'.$class}); + my @vals = split(/,/,$changes->{$item}{$key.'_'.$class}); + my $showval = ''; + for (my $i=0; $i<@{$styleorder}; $i++) { + if ($vals[$i] ne '') { + $showval .= 'font-'.$styleorder->[$i].': '.$vals[$i].'; '; + } + } + if ($vals[3] ne '') { + $showval .= $vals[3]; + } + if ($showval ne '') { + $displayval .= $classtitles->{$class}.':{ '. + $showval.'}'; + $storehash{$key.'_'.$class} = $changes->{$item}{$key.'_'.$class}; + } else { + $displayval .= $classtitles->{$class}.': '.&mt('None'); + push(@delkeys,$key.'_'.$class); + } + unless ($count == $total) { + $displayval .= (' 'x2); + } + } } $displayname = &mt($text); } @@ -957,6 +1513,22 @@ sub store_changes { } } $displayname = &mt($text); + } elsif ($item eq 'lti') { + if ($key eq 'lti.lcmenu') { + if ($changes->{$item}{$key} eq 'none') { + $displayval = &mt('None of the configurable menu items displayed'); + } else { + my %ltititles = <imenu_titles(); + $displayval = join(', ', map { $ltititles{$_}; } split(/,/,$changes->{$item}{$key})); + } + } else { + if ($changes->{$item}{$key} eq '1') { + $displayval = &mt('Yes'); + } elsif ($changes->{$item}{$key} eq '') { + $displayval = &mt('No'); + } + } + $displayname = &mt($text); } else { $displayname = &mt($text); } @@ -969,32 +1541,114 @@ sub store_changes { $displayval = &Apache::lonlocal::locallocaltime($displayval); } elsif ($key eq 'categories') { $displayval = $env{'form.categories_display'}; - } elsif ($key eq 'canuse_pdfforms') { + } elsif (($key eq 'canuse_pdfforms') || ($key eq 'usejsme') || ($key eq 'uselcmath')) { if ($changes->{$item}{$key} eq '1') { $displayval = &mt('Yes'); } elsif ($changes->{$item}{$key} eq '0') { $displayval = &mt('No'); } } - if ($changes->{$item}{$key} eq '') { + if ($key eq 'co-owners') { + if (ref($changes->{$item}{$key}) eq 'HASH') { + if (ref($changes->{$item}{$key}{'changed'}) eq 'ARRAY') { + foreach my $type ('co-owners','pendingco-owners') { + next unless (grep(/^\Q$type\E$/,@{$changes->{$item}{$key}{'changed'}})); + if ($type eq 'pendingco-owners') { + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $displayname = &mt('Invited as co-owners, pending acceptance'); + } + } + if ($changes->{$item}{$key}{$type} eq '') { + push(@delkeys,'internal.'.$type); + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + ''.$displayname.'')).'
    • '; + } + } elsif (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + $displayval = join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } split(',',$changes->{$item}{$key}{$type})); + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + ''.$displayname.'', + "'$displayval'")).'
    • '; + } + } + } + unless (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + if ($env{'form.pending_coowoner'} eq 'accept') { + $displayval = &mt('on'); + } elsif ($env{'form.pending_coowoner'} eq 'decline') { + $displayval = ''; + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('Invitation to be co-owner declined')).'
    • '; + } elsif ($env{'form.remove_coowoner'}) { + $displayval = &mt('off'); + } + if ($displayval) { + $displayname = &mt('Your co-ownership status'); + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + ''.$displayname.'', + "'$displayval'")).'
    • '; + } + } + } + } elsif ($changes->{$item}{$key} eq '') { push(@delkeys,$key); - $output .= '
    • '.&mt('Deleted setting for [_1]', - ''.$displayname.'').'
    • '; + if ($item eq 'lti') { + if (($key eq 'lti.override') || (($key ne 'lti.override') && ($env{'form.lti.override'} ne ''))) { + if (($key eq 'lti.lcmenu') && + ((!$env{'form.lti.topmenu'}) && (!$env{'form.lti.inlinemenu'}))) { + $output .= '
    • '.&mt('LTI settings for menu items only saved if page header and/or inline menu is set to be displayed').'
    • '; + } else { + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + ''.$displayname.'', + "'$displayval'")).'
    • '; + } + } elsif (!exists($changes->{$item}{'lti.override'})) { + $output .= '
    • '.&mt('LTI settings only saved if Override is set to "Yes"').'
    • '; + } + } else { + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + ''.$displayname.'')).'
    • '; + } } else { - $output .= '
    • '.&mt('[_1] set to [_2]', + $output .= '
    • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', ''.$displayname.'', - "'$displayval'"); + "'$displayval'")); 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 .= '
    • '; } - $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 { + unless ($key eq 'discussion_post_fonts') { + $storehash{$key} = $changes->{$item}{$key}; + } + } + } + if ($key eq 'cloners') { + # Get existing cloners + my %clonenames = + &Apache::lonnet::dump('environment',$cdom,$cnum,'cloners'); + if ($clonenames{'cloners'} =~ /,/) { + @oldcloner = split(/\s*\,\s*/,$clonenames{'cloners'}); + } else { + $oldcloner[0] = $clonenames{'cloners'}; + } } if (($key eq 'description') || ($key eq 'cloners') || - ($key eq 'hidefromcat') || ($key eq 'categories')) { + ($key eq 'hidefromcat') || ($key eq 'categories') || + ($key eq 'co-owners') || ($key eq 'lti.override') || + ($key eq 'lti.topmenu') || ($key eq 'lti.inlinemenu') || + ($key eq 'lti.lcmenu')) { push(@need_env_update,$key); } } @@ -1003,15 +1657,23 @@ sub store_changes { $output .= '
    '; } else { if ($crstype eq 'Community') { - $output = &mt('No changes made to community settings.'); + $output .= &mt('No changes made to community settings.'); } else { - $output = &mt('No changes made to course settings.'); + $output .= &mt('No changes made to course settings.'); } } } } } if (&Apache::lonnet::put('environment',\%storehash,$cdom,$cnum) eq 'ok') { + if (ref($changes) eq 'HASH') { + if (ref($changes->{'courseinfo'}) eq 'HASH') { + if (exists($changes->{'courseinfo'}{'cloners'})) { + &change_clone($cdom,$cnum,$changes->{'courseinfo'}{'cloners'}, + \@oldcloner); + } + } + } if (@delkeys) { if (&Apache::lonnet::del('environment',\@delkeys,$cdom,$cnum) ne 'ok') { $output .= '
    '; @@ -1060,6 +1722,18 @@ 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 ++; + } elsif ($key =~ /^lti\./) { + &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.'.$key => $storehash->{$key}}); } } if ($count) { @@ -1158,16 +1832,98 @@ sub get_course { } my $cdom=$env{'course.'.$courseid.'.domain'}; my $cnum=$env{'course.'.$courseid.'.num'}; - return ($cnum,$cdom); + my $chome=$env{'course.'.$courseid.'.home'}; + return ($cnum,$cdom,$chome); } sub get_jscript { - my ($cdom,$phase,$crstype) = @_; + my ($cid,$cdom,$phase,$crstype,$settings) = @_; my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype); - my ($jscript,$categorize_js); + my ($jscript,$categorize_js,$loncaparev_js,$instcode_js); my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript(); my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset'); my $cloners_js = &cloners_javascript($phase); + my @code_order; + if ($crstype ne 'Community') { + if (ref($settings) eq 'HASH') { + my %codedefaults; + &Apache::lonnet::auto_instcode_defaults($cdom,\%codedefaults, + \@code_order); + if (@code_order > 0) { + if ($phase eq 'display') { + my @actions = &Apache::loncommon::get_env_multiple('form.actions'); + if (grep(/^courseinfo$/,@actions)) { + if ($settings->{'cloners'} ne '') { + unless ($settings->{'cloners'} eq '*') { + my @cloners = split(/,/,$settings->{'cloners'}); + my @standardnames = &Apache::loncommon::get_standard_codeitems(); + my %local_to_standard; + for (my $i=0; $i<@code_order; $i++) { + $local_to_standard{$code_order[$i]} = $standardnames[$i]; + } + foreach my $cloner (@cloners) { + if (($cloner !~ /^\Q*:\E$match_domain$/) && + ($cloner !~ /^$match_username\:$match_domain$/)) { + foreach my $item (split(/\&/,$cloner)) { + my ($key,$val) = split(/\=/,$item); + $val = &unescape($val); + foreach my $code (@code_order) { + if ($key eq $local_to_standard{$code}) { + $env{'form.'.$key} = $val; + } + } + } + } + } + } + } + } + } + my @codetitles; + (undef,$instcode_js) = + &Apache::courseclassifier::instcode_selectors($cdom,'display',undef, + \@codetitles); + $instcode_js .= <'. - "\n".$stubrowse_js."\n"; + '// '."\n". + ''."\n".$stubrowse_js."\n"; return $jscript; } @@ -1217,7 +2002,7 @@ function update_cloners(caller,num) { if (document.$formname.cloners_activate[i].value == '0') { document.$formname.cloners_activate[i].checked = false; } - if (document.$formname.cloners_activate[i].value == '') { + if (document.$formname.cloners_activate[i].value == '-1') { document.$formname.cloners_activate[i].checked = true; } } @@ -1270,26 +2055,82 @@ ENDSCRIPT sub print_courseinfo { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } - my ($cathash,$categoriesform); + my ($cathash,$categoriesform,$autocoowner,$clonedefaults,$disabled); + if ($noedit) { + $disabled = ' disabled="disabled"'; + } my %domconf = - &Apache::lonnet::get_dom('configuration',['coursecategories'],$cdom); + &Apache::lonnet::get_dom('configuration', + ['coursecategories','autoenroll','coursedefaults'],$cdom); if (ref($domconf{'coursecategories'}) eq 'HASH') { $cathash = $domconf{'coursecategories'}{'cats'}; if (ref($cathash) eq 'HASH') { $categoriesform = &Apache::loncommon::assign_categories_table($cathash, - $settings->{'categories'},$crstype)."\n"; + $settings->{'categories'},$crstype,$disabled)."\n"; + } + } + if (ref($domconf{'autoenroll'}) eq 'HASH') { + $autocoowner = $domconf{'autoenroll'}{'co-owners'}; + } + my ($currcanclone,@code_order,$cloner_instcode); + my %codedefaults; + &Apache::lonnet::auto_instcode_defaults($cdom,\%codedefaults, + \@code_order); + if ($settings->{'cloners'}) { + unless ($settings->{'cloners'} eq '*') { + my @currclone = split(/,/,$settings->{'cloners'}); + foreach my $item (@currclone) { + unless ($item eq '*') { + if (($item !~ /\:/) && ($item =~ /=/)) { + $cloner_instcode = 1; + } + } + } + } + } + if (ref($domconf{'coursedefaults'}) eq 'HASH') { + my $canclone = $domconf{'coursedefaults'}{'canclone'}; + if (ref($canclone) eq 'HASH') { + if (ref($canclone->{'instcode'}) eq 'ARRAY') { + if ($settings->{'internal.coursecode'}) { + my @posscodes; + if (@code_order > 0) { + $currcanclone = 'instcode'; + foreach my $item (@{$canclone->{'instcode'}}) { + if (grep(/^\Q$item\E$/,@code_order)) { + push(@posscodes,$item); + } + } + my $codestr = join(' + ',@posscodes); + $clonedefaults = &mt('Default for official courses is to also allow cloning if [_1] match in cloner and cloned.', + '"'.$codestr.'"').'
    '; + } + } + } + } elsif ($canclone eq 'domain') { + $clonedefaults = &mt('Default is for any course requester in [_1] domain to be able to clone.', + ''.$cdom.'').'
    '; + $currcanclone = 'domain'; + } + if ($clonedefaults) { + if ($settings->{'cloners'} ne '') { + $clonedefaults .= '
    '.&mt('Default does [_1]not[_2] currently apply because values have been set in the course.','',''); + } else { + $clonedefaults .= &mt('Default is disregarded if [_1]any[_2] values are set here in the course.','',''); + } + $clonedefaults = '

    '.$clonedefaults; } } if (!defined($categoriesform)) { $categoriesform = &mt('No categories defined in this domain.'); } - my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype); + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $replace; if ($crstype eq 'Community') { @@ -1297,22 +2138,37 @@ sub print_courseinfo { } else { $replace = &mt('To replace the standard title for a course role, enter a title, otherwise leave blank'); } + my ($editmap,$editsyllabus); + unless ($noedit) { + $editmap = (' 'x2). + '". + &mt('Select Map').'
    '. + &mt('Modification may make assessment data inaccessible!'). + ''; + $editsyllabus = &mt('[_1]Edit[_2]','', + ''); + } my %items = ( 'url' => { - text => ''.&mt($itemtext->{'url'}).''.(' 'x2). - '". - &mt('Select Map').'
    '. - &mt('Modification may make assessment data inaccessible!'). - '', + text => ''.&mt($itemtext->{'url'}).''.$editmap, input => 'textbox', - size => '40', + size => '55', advanced => 1 }, 'description' => { text => ''.&mt($itemtext->{'description'}).'', input => 'textbox', - size => '25', + size => '55', + }, + 'owner' => { + text => ''.&mt($itemtext->{'owner'}).'', + }, + 'co-owners' => { + text => ''.&mt($itemtext->{'co-owners'}).'', + }, + 'clonedfrom' => { + text => ''.&mt($itemtext->{'clonedfrom'}).'', }, 'courseid' => { text => ''.&mt($itemtext->{'courseid'}).'
    '.'('. @@ -1320,12 +2176,15 @@ sub print_courseinfo { input => 'textbox', size => '25', }, + 'uniquecode' => { + text => ''.&mt($itemtext->{'uniquecode'}).'', + }, 'cloners' => { text => ''.&mt($itemtext->{'cloners'}).'
    '. - &mt('Coordinators included automatically'), + &mt('Owner and Coordinators included automatically'). + $clonedefaults, input => 'textbox', - size => '40', - advanced => 1 + size => '40' }, 'rolenames' => { text => ''.&mt($itemtext->{'rolenames'}).'
    '. @@ -1335,10 +2194,9 @@ sub print_courseinfo { advanced => 1 }, 'externalsyllabus' => { - text => ''.&mt($itemtext->{'externalsyllabus'}).'
    ('. - &mt('not using syllabus template)'), - input => 'textbox', - size => '40', + text => ''.&mt($itemtext->{'externalsyllabus'}).'
    '. + &mt('(Syllabus type in use)').(' ' x2). + $editsyllabus, }, 'hidefromcat' => { text => ''.&mt($itemtext->{'hidefromcat'}).'
    '. @@ -1351,27 +2209,40 @@ sub print_courseinfo { input => 'textbox', size => '25', }, + 'loncaparev' => { + text => ''.&mt($itemtext->{'loncaparev'}).'', + }, + 'defaultcredits' => { + text => ''.&mt($itemtext->{'defaultcredits'}).'', + }, ); my $datatable; my $count = 0; foreach my $item (@{$ordered}) { + my $colspan; if ($item eq 'hidefromcat') { next if (!$can_toggle_cat); } elsif ($item eq 'categories') { next if (!$can_categorize); + } elsif ($item eq 'uniquecode') { + next if (!$env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'}); + } + unless (($item eq 'cloners') || ($item eq 'rolenames')) { + $colspan = 2; } $count ++; if (exists $items{$item}{advanced} && $items{$item}{advanced} == 1) { - $datatable .= &item_table_row_start($items{$item}{text},$count,"advanced"); + $datatable .= &item_table_row_start($items{$item}{text},$count,"advanced",$colspan); } else { - $datatable .= &item_table_row_start($items{$item}{text},$count); + $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); } if ($items{$item}{input} eq 'radio') { - $datatable .= &yesno_radio($item,$settings); + $datatable .= &yesno_radio($item,$settings,undef,undef,undef,$noedit); } elsif ($item eq 'cloners') { my $includeempty = 1; my $num = 0; - $datatable .= &Apache::loncommon::start_data_table(). + $datatable .= '
'. + &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''. - (' 'x2).''.&mt('Yes').''. + (' 'x2).'
'.&mt('Or'). - '
'. + '
'.&mt('Or'). + '
'. &Apache::loncommon::start_data_table(); my @cloners; if ($settings->{$item} eq '') { - $datatable .= &new_cloners_dom_row($cdom,'0'); + unless ($noedit) { + my $default; + if ($currcanclone eq 'domain') { + $default = '0'; + } + $datatable .= &new_cloners_dom_row($cdom,'0',$default); + } } elsif ($settings->{$item} ne '*') { my @entries = split(/,/,$settings->{$item}); if (@entries > 0) { foreach my $entry (@entries) { my ($uname,$udom) = split(/:/,$entry); + if ($udom =~ /^$match_domain$/) { + unless (&Apache::lonnet::domain($udom)) { + next; + } + } else { + next; + } if ($uname eq '*') { $datatable .= &Apache::loncommon::start_data_table_row(). ''. - &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); + } } } } @@ -1429,23 +2316,56 @@ sub print_courseinfo { ''. $add_domtitle.'
'. &Apache::loncommon::select_dom_form('','cloners_newdom', - $includeempty). + $includeempty,undef,undef, + undef,undef,$noedit). ''. ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). - '
'.&mt('And'). - '
'. + '
'.&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'}). + $items{$item}{'size'},$disabled). ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); + if (@code_order > 0) { + my (%cat_items,@codetitles,%cat_titles,%cat_order); + my ($jscript,$totcodes,$numtitles,$lasttitle) = + &Apache::courseclassifier::instcode_selectors_data($cdom,'display', + \%cat_items,\@codetitles, + \%cat_titles,\%cat_order); + my $showncodes = 'off'; + my $checkedoff = ' checked="checked"'; + my $checkedon = ''; + if ($cloner_instcode) { + $checkedon = $checkedoff; + $checkedoff = ''; + $showncodes = 'on'; + } + $datatable .= '
'.&mt('And'). + '
'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row(). + ''. + &mt('Cloning by official course(s) based on course category').(' 'x2). + ''. + (' '). + ''. + &Apache::courseclassifier::build_instcode_selectors($numtitles, + $lasttitle,\%cat_items,\@codetitles,\%cat_titles,\%cat_order, + $showncodes,'LC_cloners_instcodes','LC_cloners_instcode',$noedit). + ''.&Apache::loncommon::end_data_table_row(). + &Apache::loncommon::end_data_table(); + } } elsif ($item eq 'rolenames') { - $datatable .= &Apache::loncommon::start_data_table(); + $datatable .= ''. + &Apache::loncommon::start_data_table(); my @roles; if ($crstype eq 'Community') { @roles = ('co'); @@ -1460,17 +2380,107 @@ sub print_courseinfo { ''. &Apache::lonhtmlcommon::textbox('rolenames_'.$role, $settings->{$role.'.plaintext'}, - $items{$item}{size}).''. + $items{$item}{size},$disabled).''. &Apache::loncommon::end_data_table_row(); } $datatable .= &Apache::loncommon::end_data_table().''; } elsif ($item eq 'categories') { - my $launcher = 'onFocus="this.blur();javascript:catsbrowser();";'; + my $launcher; + if ($noedit) { + $launcher = $disabled; + } else { + $launcher = 'onfocus="this.blur();javascript:catsbrowser();"'; + } $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'); + } + $datatable .= $owner; + } elsif ($item eq 'clonedfrom') { + my $clonesrc = $env{'course.'.$env{'request.course.id'}.'.clonedfrom'}; + my $clonedfrom = &mt('None'); + if ($clonesrc =~ m{/$match_domain/$match_courseid}) { + my %clonesrcinfo = &Apache::lonnet::coursedescription($clonesrc); + if ($clonesrcinfo{'description'}) { + $clonedfrom = $clonesrcinfo{'description'}.' '.($clonesrc); + } + } + $datatable .= $clonedfrom; + } elsif ($item eq 'uniquecode') { + my $code = $env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'}; + if ($code) { + $datatable .= $code; + } + } elsif ($item eq 'co-owners') { + 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,$noedit); + } + } 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,$noedit); + } + } + } elsif ($item eq 'externalsyllabus') { + my $external = $env{'course.'.$env{'request.course.id'}.'.externalsyllabus'}; + my $uploaded = $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}; + my $minimal = $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}; + if (($minimal =~/\w/) || ($uploaded =~/\w/)) { + if ($minimal =~/\w/) { + if ($external =~ m{\Q$minimal\E$}) { + undef($external); + } + } elsif ($uploaded =~/\w/) { + if ($external =~ m{\Q$uploaded\E$}) { + undef($external); + } + } + } elsif ($external!~/\w/) { + undef($external); + } + if ($external) { + $datatable .= &mt('External URL'); + } elsif ($minimal) { + $datatable .= &mt('Minimal template'); + } elsif ($uploaded) { + $datatable .= &mt('Uploaded file'); + } else { + $datatable .= &mt('Standard template'); + } + $datatable .= (' ' x 2). + &mt('[_1]View[_2]', + '', + ''); + } elsif ($item eq 'loncaparev') { + my $loncaparev = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'}; + my $showreqd; + if ($loncaparev) { + $showreqd = &mt('[_1] or newer',$loncaparev).' '. + &mt('Details').''; + } else { + $showreqd = &mt('No specific version required'); + } + $datatable .= $showreqd; } else { - $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); + $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size},$disabled); } $datatable .= &item_table_row_end(); } @@ -1479,19 +2489,24 @@ sub print_courseinfo { } sub new_cloners_dom_row { - my ($newdom,$num) = @_; - my $output; + my ($newdom,$num,$default) = @_; + my ($output,$checkedon,$checkedoff); if ($newdom ne '') { + if ($num eq $default) { + $checkedon = 'checked="checked" '; + } else { + $checkedoff = 'checked="checked" '; + } $output .= &Apache::loncommon::start_data_table_row(). ''. &mt('Any user in domain:').' '.$newdom.''. (' 'x2).''.(' 'x2). ' @@ -1626,8 +2642,879 @@ ENDSCRIPT return; } +sub display_loncaparev_constraints { + my ($r,$navmap,$loncaparev,$crstype) = @_; + my ($reqdmajor,$reqdminor); + 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', + ); + &Apache::lonrelrequtils::init_global_hashes(); + if (defined($Apache::lonrelrequtils::checkcrstypes{$crstype})) { + ($reqdmajor,$reqdminor) = split(/\./,$Apache::lonrelrequtils::checkcrstypes{$crstype}); + $output .= '

'.&mt('Course type: [_1] requires [_2] or newer',$crstype, + $Apache::lonrelrequtils::checkcrstypes{$crstype}).'

'; + } + my (%fromparam,%rowspan,%bymap,%byresource,@scopeorder,%toshow,%allmaps, + %byresponsetype,%bysubmission,%fromblocks,%bycrsrestype); + @scopeorder = ('all','section/group','user'); + my $now = time; + my $resourcedata = &Apache::lonparmset::readdata($cnum,$cdom); + if (ref($resourcedata) eq 'HASH') { + foreach my $key (keys(%{$resourcedata})) { + my %found; + foreach my $item (keys(%Apache::lonrelrequtils::checkparms)) { + if ($key =~ /(\Q$item\E)$/) { + if (ref($Apache::lonrelrequtils::checkparms{$item}) eq 'ARRAY') { + my $value = $resourcedata->{$key}; + if ($item eq 'examcode') { + if (&Apache::lonnet::validCODE($value)) { + $value = 'valid'; + } else { + $value = ''; + } + } elsif ($item eq 'printstartdate') { + if ($value =~ /^\d+$/) { + if ($value > $now) { + $value = 'future'; + } + } + } elsif ($item eq 'printenddate') { + if ($value =~ /^\d+$/) { + if ($value < $now) { + $value = 'past'; + } + } + } + if (grep(/^\Q$value\E$/,@{$Apache::lonrelrequtils::checkparms{$item}})) { + my $stdtype = &Apache::lonparmset::standard_parameter_types($item); + $found{$item}{'valname'} = &get_param_description($stdtype,$value); + $found{$item}{'rev'} = $Apache::lonnet::needsrelease{'parameter:'.$item.':'.$value.'::'}; + } + } + } + } + foreach my $item (keys(%Apache::lonrelrequtils::checkparmvalsmatch)) { + if (ref($Apache::lonrelrequtils::checkparmvalsmatch{$item}) eq 'ARRAY') { + my $value = $resourcedata->{$key}; + foreach my $valuematch (@{$Apache::lonrelrequtils::checkparmvalsmatch{$item}}) { + if ($value =~ /$valuematch/) { + my $stdtype = &Apache::lonparmset::standard_parameter_types($item); + $found{$item}{'valname'} = &get_param_description($stdtype,$value,1); + $found{$item}{'rev'} = + $Apache::lonnet::needsrelease{'parameter:'.$item.'::'.$valuematch.':'}; + last; + } + } + } + } + foreach my $item (keys(%Apache::lonrelrequtils::checkparmnamesmatch)) { + my $regexp; + if ($item eq 'maplevelrecurse') { + $regexp = '\.(?:sequence|page)___\(rec\)\.'; + } + if ($regexp ne '') { + if ($key =~ /$regexp.*\.(\w+)$/) { + my $name = $1; + my $value = $resourcedata->{$key}; + if ($name eq 'type') { + last unless (($value eq 'problem') || ($value eq 'practice') || ($value eq 'exam') || + ($value eq 'survey') || ($value eq 'surveycred') || ($value eq 'anonsurvey') || + ($value eq 'anonsurveycred') || ($value eq 'randomizetry') || ($value eq 'library')); + } + my $stdtype = &Apache::lonparmset::standard_parameter_types($name); + $found{$name}{'valname'} = &get_param_description($stdtype,$value); + $found{$name}{'extra'} = &mt('Recursive into sub-folders'); + $found{$name}{'rev'} = + $Apache::lonnet::needsrelease{'parameter::::'.$item}; + } + } + } + foreach my $item (keys(%found)) { + my $stdname = &Apache::lonparmset::standard_parameter_names($item); + my $rev = $found{$item}{'rev'}; + my $valname = $found{$item}{'valname'}; + my $extra = $found{$item}{'extra'}; + my ($middle,$scope,$which,$level,$map,$resource); + 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 ($extra) { + $what .= "
$extra
"; + } + 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|rec)\).\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 .= '

'.&mt('Requirements from general settings').'

'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''.&mt('Release').''.&mt('Scope').''. + ''.&mt('Extent').''.&mt('Setting').''. + &Apache::loncommon::end_data_table_header_row(); + foreach my $rev (keys(%fromparam)) { + my ($major,$minor) = split(/\./,$rev); + ($reqdmajor,$reqdminor) = + &Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor); + $output .= &Apache::loncommon::start_data_table_row(). + ''.$rev.''; + my $newrow; + foreach my $scope (@scopeorder) { + if (ref($fromparam{$rev}{$scope}) eq 'HASH') { + if ($newrow) { + $output .= &Apache::loncommon::continue_data_table_row(); + } + $output .= ''.$lt{$scope}.''; + foreach my $which (sort(keys(%{$fromparam{$rev}{$scope}}))) { + $output .= ''.$which.''. + join('
',@{$fromparam{$rev}{$scope}{$which}}).''; + } + $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 .= ''.$lt{$scope}.' '. + join('
',@{$fromparam{$rev}{$scope}}).''. + &Apache::loncommon::end_data_table_row(); + $newrow = 1; + } + } + } + $output .= &Apache::loncommon::end_data_table().'
'; + } + } + + my %comm_blocks = &Apache::lonnet::dump('comm_block',$cdom,$cnum); + my $now = time; + if (keys(%comm_blocks) > 0) { + foreach my $block (keys(%comm_blocks)) { + if ($block =~ /^firstaccess____(.+)$/) { + my $rev = $Apache::lonnet::needsrelease{'course:commblock:timer'}; + if (ref($comm_blocks{$block}) eq 'HASH') { + push(@{$fromblocks{'timer'}{$rev}},&unescape($comm_blocks{$block}{'event'}). + ' '.&mt('set by [_1]', + &Apache::loncommon::plainname(split(/:/,$comm_blocks{$block}{'setter'})))); + } + next; + } elsif ($block =~ /^(\d+)____(\d+)$/) { + my ($start,$end) = ($1,$2); + next if ($end < $now); + } + if (ref($comm_blocks{$block}) eq 'HASH') { + if (ref($comm_blocks{$block}{'blocks'}) eq 'HASH') { + if (ref($comm_blocks{$block}{'blocks'}{'docs'}) eq 'HASH') { + if (keys(%{$comm_blocks{$block}{'blocks'}{'docs'}}) > 0) { + my $rev = $Apache::lonnet::needsrelease{'course:commblock:docs'}; + push(@{$fromblocks{'docs'}{$rev}},&unescape($comm_blocks{$block}{'event'}). + ' '. + &mt('set by [_1]', + &Apache::loncommon::plainname(split(/:/,$comm_blocks{$block}{'setter'})))); + } + } elsif ($comm_blocks{$block}{'blocks'}{'printout'} eq 'on') { + my $rev = $Apache::lonnet::needsrelease{'course:commblock:printout'}; + push(@{$fromblocks{'printout'}{$rev}},&unescape($comm_blocks{$block}{'event'}). + ' '. + &mt('set by [_1]', + &Apache::loncommon::plainname(split(/:/,$comm_blocks{$block}{'setter'})))); + + } + } + } + } + if (keys(%fromblocks)) { + my %lt = ( + docs => 'Content blocking', + printout => 'Printout generation', + timer => 'Timed quiz trigger', + ); + $output .= '

'.&mt('Requirements from exam blocking').'

'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_header_row(). + ''.&mt('Release').''.&mt('Setting').''. + ''.&mt('Event(s)').''. + &Apache::loncommon::end_data_table_header_row(); + foreach my $type ('docs','printout','timer') { + if (ref($fromblocks{$type}) eq 'HASH') { + foreach my $rev (keys(%{$fromblocks{$type}})) { + my ($major,$minor) = split(/\./,$rev); + ($reqdmajor,$reqdminor) = + &Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor,$reqdmajor,$reqdminor); + $output .= &Apache::loncommon::start_data_table_row(). + ''.$rev.''.$lt{$type}.''; + foreach my $event (sort(@{$fromblocks{$type}{$rev}})) { + $output .= $event.'
'; + } + $output =~ s{\Q
\E$}{}; + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + } + $output .= &Apache::loncommon::end_data_table().'
'; + } + } + + 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 $rev_exttool=$Apache::lonnet::needsrelease{'course:courserestype:exttool'}; + 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'); + my %checkedrev; + foreach my $res ($navmap->retrieveResources(undef,sub { $_[0]->is_problem() || $_[0]->is_tool() },1,0)) { + my @parts = @{$res->parts()}; + my $symb = $res->symb(); + my $enclosing_map = &Apache::lonnet::declutter($res->enclosing_map_src()); + if ($res->is_tool()) { + my $rev = $rev_exttool; + $bycrsrestype{$symb}{$rev} = &mt('External Tool'); + $allmaps{$enclosing_map} = 1; + next; + } + 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; + unless ($checkedrev{'anonsurvey'}) { + my ($major,$minor) = split(/\./,$rev); + ($reqdmajor,$reqdminor) = + &Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor, + $reqdmajor,$reqdminor); + $checkedrev{'anonsurvey'} = 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; + unless ($checkedrev{'randomizetry'}) { + my ($major,$minor) = split(/\./,$rev); + ($reqdmajor,$reqdminor) = + &Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor, + $reqdmajor,$reqdminor); + $checkedrev{'randomizetry'} = 1; + } + } + } + my %responses = $res->responseTypes(); + foreach my $key (keys(%responses)) { + if (exists($Apache::lonrelrequtils::checkresponsetypes{$key})) { + my $rev = $Apache::lonrelrequtils::checkresponsetypes{$key}; + unless ($checkedrev{$key}) { + my ($major,$minor) = split(/\./,$rev); + ($reqdmajor,$reqdminor) = + &Apache::lonrelrequtils::update_reqd_loncaparev($major,$minor, + $reqdmajor,$reqdminor); + $checkedrev{$key} = 1; + } + push(@{$byresponsetype{$symb}{$rev}},$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); + if (ref($mapres)) { + my $mapsymb = $mapres->symb(); + $toshow{$mapsymb} = 1; + 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 $suppmap = 'supplemental.sequence'; + my ($suppcount,$supptools,$errors) = (0,0,0); + ($suppcount,$supptools,$errors) = &Apache::loncommon::recurse_supplemental($cnum,$cdom, + $suppmap,$suppcount,$supptools,$errors); + my $mapres_header = '

'. + &mt('Requirements for specific folders or resources'). + '

'; + if ((keys(%toshow) > 0) || (keys(%byresource) > 0) || + (keys(%bysubmission) > 0) || (keys(%byresponsetype))) { + $output .= $mapres_header; + } + my $top_header = '

'.&mt('LON-CAPA version dependencies').'

'; + 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) || $supptools) { + &show_contents_view($r,$navmap,$cid,\%toshow,\%bymap,\%byresource,\%bysubmission, + \%byresponsetype,\%bycrsrestype,\@scopeorder,\%lt,$supptools); + } + $r->print('

'); + } else { + $r->print('

'. + &mt('No version requirements from resource content or settings.'). + '

'); + } + $r->print(&Apache::loncommon::end_page()); + my ($currmajor,$currminor) = split(/\./,$loncaparev); + if (($currmajor != $reqdmajor) || ($currminor != $reqdminor)) { + return 1; + } + return; +} + +sub show_contents_view { + my ($r,$navmap,$cid,$toshow,$bymap,$byresource,$bysubmission,$byresponsetype, + $bycrsrestype,$scopeorder,$lt,$supptools) = @_; + my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons"); + my $whitespace = ''; + my $showmaincontent; + if ((ref($navmap)) && + ((keys(%{$toshow}) > 0) || (keys(%{$byresource}) > 0) || + (keys(%{$bysubmission}) > 0) || (keys(%{$byresponsetype}) > 0) || + (keys(%{$bycrsrestype}) > 0))) { + $showmaincontent = 1; + } + if ($showmaincontent || $supptools) { + $r->print(&Apache::loncommon::start_data_table()); + } + if ($showmaincontent) { + my $icon = ''; + my $topmap = $env{'course.'.$cid.'.url'}; + $r->print(&Apache::loncommon::start_data_table_header_row(). + ''.&mt('Location').''.&mt('Release').''. + ''.&mt('Attribute/Setting').''. + &Apache::loncommon::end_data_table_header_row(). + &Apache::loncommon::start_data_table_row(). + ' '.$icon.' '.&mt('Main Content').''); + &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 = ''; + if ($curRes->is_page()) { + $icon = ''; + } + my $rowspan = 1; + if (ref($bymap->{$url}) eq 'HASH') { + $rowspan = scalar(keys(%{$bymap->{$url}})); + } + $r->print(&Apache::loncommon::start_data_table_row(). + ''.$indent.$icon.' '.$title.''); + &releases_by_map($r,$bymap,$url,$scopeorder,$lt); + $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}})); + } + if (ref($bycrsrestype->{$symb}) eq 'HASH') { + $rowspan += scalar(keys(%{$bycrsrestype->{$symb}})); + } + next if (!$rowspan); + $icon = ''.
+                            &mt('Problem').''; + $r->print(&Apache::loncommon::start_data_table_row(). + ''.$indent.$icon.' '.$title.''); + 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(''.$rev.''); + if (ref($byresource->{$symb}{$rev}) eq 'HASH') { + $r->print(''); + foreach my $scope (@{$scopeorder}) { + if (ref($byresource->{$symb}{$rev}{$scope}) eq 'HASH') { + $r->print(''); + foreach my $which (sort(keys(%{$byresource->{$symb}{$rev}{$scope}}))) { + $r->print(''); + } + $r->print(''); + } elsif (ref($byresource->{$symb}{$rev}{$scope}) eq 'ARRAY') { + $r->print(''. + ''); + } + } + $r->print('
'.&mt('Setting - scope: [_1]',$lt->{$scope}).''.$which.''. + join('
',@{$byresource->{$symb}{$rev}{$scope}{$which}}). + '
'.&mt('Setting - scope: [_1]',$lt->{$scope}).' '. + join('
',@{$byresource->{$symb}{$rev}{$scope}}).'
'); + } + $r->print(''); + $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(''.$rev.''); + if (ref($bysubmission->{$symb}{$rev}) eq 'ARRAY') { + $r->print(&mt('Submissions to: ').' '. + join(', ',@{$bysubmission->{$symb}{$rev}})); + } + $r->print(''); + $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(''.$rev.''); + if (ref($byresponsetype->{$symb}{$rev}) eq 'ARRAY') { + $r->print(&mt('Response Type(s): ').' '. + join('
',@{$byresponsetype->{$symb}{$rev}})); + } + $r->print(''); + } + $r->print(&Apache::loncommon::end_data_table_row()); + $newrow = 1; + } + if (ref($bycrsrestype->{$symb}) eq 'HASH') { + foreach my $rev (sort(keys(%{$bycrsrestype->{$symb}}))) { + if ($newrow) { + $r->print(&Apache::loncommon::continue_data_table_row()); + } + $r->print(''.$rev.''.$bycrsrestype->{$symb}{$rev}.''); + } + $r->print(&Apache::loncommon::end_data_table_row()); + } + } + } + } + } + if ($supptools) { + my $icon = ''; + $r->print(&Apache::loncommon::start_data_table_header_row(). + ''.&mt('Location').''.&mt('Release').''. + ''.&mt('Resource Type').''. + &Apache::loncommon::end_data_table_header_row(). + &Apache::loncommon::start_data_table_row(). + ' '.$icon.' '.&mt('Supplemental Content').''. + ''. + $Apache::lonrelrequtils::exttool{'major'}.'.'. + $Apache::lonrelrequtils::exttool{'minor'}. + ''.&mt('[quant,_1,External Tool,External Tools]', + $supptools).''. + &Apache::loncommon::end_data_table_row()); + } + if ($showmaincontent || $supptools) { + $r->print(&Apache::loncommon::end_data_table()); + } + return; +} + +sub releases_by_map { + my ($r,$bymap,$url,$scopeorder,$lt) = @_; + return unless ((ref($bymap) eq 'HASH') && (ref($scopeorder) eq 'ARRAY')); + my $newrow = 0; + if (ref($bymap->{$url}) eq 'HASH') { + foreach my $rev (sort(keys(%{$bymap->{$url}}))) { + if ($newrow) { + $r->print(&Apache::loncommon::end_data_table_row(). + &Apache::loncommon::continue_data_table_row()); + } + $r->print(''.$rev.''); + if (ref($bymap->{$url}{$rev}) eq 'HASH') { + $r->print(''); + foreach my $scope (@{$scopeorder}) { + if (ref($bymap->{$url}{$rev}{$scope}) eq 'HASH') { + $r->print(''); + foreach my $which (sort(keys(%{$bymap->{$url}{$rev}{$scope}}))) { + $r->print(''); + } + $r->print(''); + } elsif (ref($bymap->{$url}{$rev}{$scope}) eq 'ARRAY') { + $r->print(''); + } + } + $r->print('
'.&mt('Setting - scope: [_1]',$lt->{$scope}).''.$which.''. + join('
',@{$bymap->{$url}{$rev}{$scope}{$which}}). + '
'.&mt('Setting - scope: [_1]',$lt->{$scope}). + ' '. + join('
',@{$bymap->{$url}{$rev}{$scope}}).'
'); + } + $r->print(''); + $newrow = 1; + } + } else { + $r->print(' '); + } + return; +} + +sub get_param_description { + my ($stdtype,$value,$regexp) = @_; + my ($name,$parammatches,$paramstrings,@possibles); + if ($stdtype =~ /^string/) { + $paramstrings = &Apache::lonparmset::standard_string_options($stdtype); + } elsif ($stdtype eq 'date_interval') { + $paramstrings = &Apache::lonparmset::standard_interval_options($stdtype); + } + if ($regexp) { + if ($stdtype =~ /^string/) { + $parammatches = &Apache::lonparmset::standard_string_matches($stdtype); + } elsif ($stdtype eq 'date_interval') { + $parammatches = &Apache::lonparmset::standard_interval_matches($stdtype); + } + if (ref($parammatches) eq 'ARRAY') { + @possibles = @{$parammatches}; + } else { + undef($regexp); + $name = $value; + } + } + unless ($regexp) { + $name = $value; + if (ref($paramstrings) eq 'ARRAY') { + @possibles = @{$paramstrings}; + } else { + if (($stdtype eq 'date_start') || ($stdtype eq 'date_end')) { + if ($name == 0) { + $name = &mt('Never'); + } elsif (($name ne '') && ($name !~ /\D/)) { + $name = &Apache::lonlocal::locallocaltime($name); + } + } + return $name; + } + } + foreach my $possibilities (@possibles) { + next unless (ref($possibilities) eq 'ARRAY'); + my $gotregexmatch = ''; + if ($regexp) { + last if ($gotregexmatch); + my ($item,$pattern) = @{ $possibilities }; + if ($value =~ /$pattern/) { + if (ref($paramstrings) eq 'ARRAY') { + foreach my $possibles (@{$paramstrings}) { + next unless (ref($possibles) eq 'ARRAY'); + my ($thing,$description) = @{$possibles}; + if ($thing eq $item) { + $name = $description; + $gotregexmatch = 1; + last; + } + } + last if ($gotregexmatch); + } + } + } else { + my ($thing,$description) = @{ $possibilities }; + if ($thing eq $value) { + $name = $description; + last; + } + } + } + return $name; +} + +sub update_releasereq { + my $readmap = 1; + my $getrelreq = 1; + if (ref($modified_courses) eq 'ARRAY') { + foreach my $item (@{$modified_courses}) { + if (ref($item) eq 'ARRAY') { + my ($cdom,$cnum,$chome,$crstype) = @{$item}; + &Apache::lonrelrequtils::modify_course_relreq(undef,undef,$cnum,$cdom, + $chome,$crstype,$cdom.'_'.$cnum, + $readmap,$getrelreq); + } + } + $modified_courses = []; + } + undef($registered_cleanup); + return; +} + +sub show_autocoowners { + my (@currcoown) = @_; + my $output = ''.&mt('Co-ownership is set automatically when a Course Coordinator role[_1] is assigned to official course personnel (from institutional data).','
').'
'; + if (@currcoown > 0) { + $output .= '
'.&mt('Current co-owners are:').' '. + join(', ',map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + } else { + $output .= '
'.&mt('Currently no co-owners.'); + } + return $output; +} + +sub coowner_invitations { + my ($cnum,$cdom,$currcoownref,$noedit) = @_; + my ($output,@pendingcoown,@othercoords,@currcoown); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + if (ref($currcoownref) eq 'ARRAY') { + @currcoown == @{$currcoownref}; + } + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + my $ccrole = 'cc'; + my %ccroles = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,undef,[$ccrole]); + foreach my $key (sort(keys(%ccroles))) { + my ($ccname,$ccdom,$role) = split(':',$key); + next if ($key eq $env{'user.name'}.':'.$env{'user.domain'}.':'.$ccrole); + unless (grep(/^\Q$ccname\E:\Q$ccdom\E$/,@currcoown,@pendingcoown)) { + push(@othercoords,$ccname.':'.$ccdom); + } + } + my $coowner_rows = @currcoown + @pendingcoown + @othercoords; + if ($coowner_rows) { + $output .= &Apache::loncommon::start_data_table(); + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Current co-owners').''; + foreach my $person (@currcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if ($pendingcoowners) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invited as co-owners [_1](agreement pending)','
').'
'; + foreach my $person (@pendingcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if (@othercoords) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invite other Coordinators [_1]to become co-owners','
').'
'; + foreach my $person (@othercoords) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + } else { + $output = &mt('There are no coordinators to select as co-owners'); + } + return $output; +} + +sub manage_coownership { + my ($cnum,$cdom,$currcoownref,$noedit) = @_; + my (@pendingcoown,@currcoown); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + if (ref($currcoownref) eq 'ARRAY') { + @currcoown == @{$currcoownref}; + } + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + 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) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -1646,17 +3533,24 @@ sub print_localization { input => 'selectbox', }, ); - my $datatable; + my ($datatable,$disabled); my $count = 0; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + my $colspan; + unless ($item eq 'languages') { + $colspan = 2; + } + $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); if ($item eq 'timezone') { my $includeempty = 1; my $timezone = &Apache::lonlocal::gettimezone(); $datatable .= &Apache::loncommon::select_timezone($item,$timezone,undef, - $includeempty); + $includeempty,$disabled); } elsif ($item eq 'datelocale') { my $includeempty = 1; my $locale_obj = &Apache::lonlocal::getdatelocale(); @@ -1666,15 +3560,18 @@ sub print_localization { } $datatable .= &Apache::loncommon::select_datelocale($item,$currdatelocale, - undef,$includeempty); + undef,$includeempty,$disabled); } else { if ($settings->{$item} eq '') { - $datatable .= - &Apache::loncommon::select_language('languages_0','',1); + unless ($noedit) { + $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(); + $datatable .= '
'. + &Apache::loncommon::start_data_table(); if (@languages > 0) { my %langchoices = &get_lang_choices(); foreach my $lang (@languages) { @@ -1689,19 +3586,22 @@ sub print_localization { '

'. ''. &Apache::loncommon::end_data_table_row(); $num ++; } } - $datatable .= &Apache::loncommon::start_data_table_row(). + unless ($noedit) { + $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(); + ''.&Apache::loncommon::end_data_table_row(); + } + $datatable .= &Apache::loncommon::end_data_table().'
'; } } $datatable .= &item_table_row_end(); @@ -1722,7 +3622,7 @@ sub get_lang_choices { } sub print_feedback { - my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -1757,21 +3657,25 @@ sub print_feedback { del => 'Delete?', sec => 'Sections:', ); - + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $item (@{$ordered}) { $count ++; if ($position eq 'top') { $datatable .= &item_table_row_start($items{$item}{text},$count); } else { - $datatable .= &item_table_row_start($items{$item}{text}."
(Custom text)",$count, "advanced"); + $datatable .= &item_table_row_start($items{$item}{text}."
(Custom text)",$count, "advanced",2); } if ($position eq 'top') { my $includeempty = 0; - $datatable .= &user_table($cdom,$item,\@sections, - $settings->{$item},\%lt); + $datatable .= ''. + &user_table($cdom,$item,\@sections, + $settings->{$item},\%lt,$noedit); } else { $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text', - $settings->{$item.'.text'},$items{$item}{size}); + $settings->{$item.'.text'},$items{$item}{size},$disabled); } $datatable .= &item_table_row_end(); } @@ -1780,15 +3684,21 @@ sub print_feedback { } sub user_table { - my ($cdom,$item,$sections,$currvalue,$lt) = @_; + my ($cdom,$item,$sections,$currvalue,$lt,$noedit) = @_; my $output; if ($currvalue eq '') { - $output .= &select_recipient($item,'0',$cdom,$sections); + unless ($noedit) { + $output .= &select_recipient($item,'0',$cdom,$sections); + } } else { my $num = 0; my @curr = split(/,/,$currvalue); - $output .= ''; + $output .= '
'; my ($currusers); + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $val (@curr) { next if ($val eq ''); my ($uname,$udom,$seclist) = ($val =~ /^($match_username):($match_domain)(\(?[^\)]*\)?)$/); @@ -1800,7 +3710,7 @@ sub user_table { $currusers .= ''. ''; @@ -1829,12 +3739,16 @@ sub user_table { '
'. ''. ''.(' 'x2). @@ -1811,7 +3721,7 @@ sub user_table { if (@{$sections}) { $currusers.= (' 'x3).$lt->{'sec'}.' '. &select_sections($item,$num,$sections, - \@selsec); + \@selsec,$noedit); } } $currusers .= '
'.$currusers.'
'. ''; } - $output .= ''. + unless ($noedit) { + $output .= + ''. ''. $lt->{'add'}.'
'. &select_recipient($item,$num,$cdom,$sections). ''. - ''; + ''; + } + $output .= ''; } return $output; } @@ -1861,14 +3775,17 @@ sub select_recipient { } sub select_sections { - my ($item,$num,$sections,$selected) = @_; - my ($output,@currsecs,$allsec); + my ($item,$num,$sections,$selected,$noedit) = @_; + my ($output,@currsecs,$allsec,$disabled); if (ref($selected) eq 'ARRAY') { @currsecs = @{$selected}; } if (!@currsecs) { $allsec = ' selected="selected"'; } + if ($noedit) { + $disabled = ' disabled="disabled"'; + } if (ref($sections) eq 'ARRAY') { if (@{$sections}) { my $mult; @@ -1878,7 +3795,7 @@ sub select_sections { $mult .= ' size="4"'; } } - $output = ''. ' '; foreach my $sec (@{$sections}) { my $is_sel; @@ -1894,7 +3811,7 @@ sub select_sections { } sub print_discussion { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -1924,6 +3841,20 @@ sub print_discussion { &mt('(specific user(s))'), input => 'checkbox', }, + + 'pac.roles.denied' => { + text => ''.&mt($itemtext->{'pac.roles.denied'}).''. + &Apache::loncommon::help_open_topic("Course_Disable_Anonymous_Discussion").'
'. + &mt('(role-based)'), + input => 'checkbox', + }, + + 'pac.users.denied' => { + text => ''.&mt($itemtext->{'pac.users.denied'}).'
'. + &mt('(specific user(s))'), + input => 'checkbox', + }, + 'allow_limited_html_in_feedback' => { text => ''.&mt($itemtext->{'allow_limited_html_in_feedback'}).'', input => 'radio', @@ -1933,6 +3864,11 @@ sub print_discussion { text => ''.&mt($itemtext->{'allow_discussion_post_editing'}).'', input => 'checkbox', }, + 'discussion_post_fonts' => { + text => ''.&mt($itemtext->{'discussion_post_fonts'}).'', + input => 'textbox', + size => '20', + }, ); my $datatable; my $count; @@ -1946,32 +3882,60 @@ sub print_discussion { del => 'Delete?', sec => 'Sections:', ); - foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + my $colspan; + if ($item eq 'allow_limited_html_in_feedback') { + $colspan = 2; + } + $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); if ($item eq 'plc.roles.denied') { - $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). + $datatable .= ''."\n";; - $output .= ''."\n". + ''; + if ($colspan) { + $output .= ''. + &Apache::loncommon::end_data_table_row(); + $num ++; + unless (grep(/^\Q$currdom\E$/,@excdoms)) { + push(@excdoms,$currdom); + } + } + } + if ((scalar(keys(%domains)) - scalar(@excdoms)) > 0) { + $datatable .= + &Apache::loncommon::start_data_table_row(). + ''.&Apache::loncommon::end_data_table_row(); + } + $datatable .= &Apache::loncommon::end_data_table(). + ''. + '
'; + } + return $datatable; +} + sub print_hdrfmt_row { - my ($item,$settings) = @_; + my ($item,$settings,$noedit) = @_; my @curr; my $currnum = 0; my $maxnum = 2; @@ -2642,9 +4973,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; @@ -2704,37 +5035,45 @@ function getIndexByName(item) { ENDJS - $output .= $currstr.'
'. + ''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). '
'; } elsif ($item eq 'plc.users.denied') { - $datatable .= &user_table($cdom,$item,undef, - $settings->{$item},\%lt); + $datatable .= '
'. + &user_table($cdom,$item,undef, + $settings->{$item},\%lt,$noedit); } elsif ($item eq 'pch.roles.denied') { - $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). + $datatable .= ''. &Apache::loncommon::end_data_table_row(). - &role_checkboxes($cdom,$cnum,$item,$settings,1). - &Apache::loncommon::end_data_table(); + &role_checkboxes($cdom,$cnum,$item,$settings,1,undef,$noedit). + &Apache::loncommon::end_data_table().'
'; + } elsif ($item eq 'discussion_post_fonts') { + $datatable .= ''. + ''. + ''. + ''. + ''. + &Apache::loncommon::end_data_table_row(). + &set_discussion_fonts($cdom,$cnum,$item,$settings,$noedit). + &Apache::loncommon::end_data_table().'
'; } $datatable .= &item_table_row_end(); } @@ -1980,7 +3944,7 @@ sub print_discussion { } sub role_checkboxes { - my ($cdom,$cnum,$item,$settings,$showsections,$crstype) = @_; + my ($cdom,$cnum,$item,$settings,$showsections,$crstype,$noedit) = @_; my @roles = ('st','ad','ta','ep','in'); if ($crstype eq 'Community') { push(@roles,'co'); @@ -2018,6 +3982,10 @@ sub role_checkboxes { } my $numinrow = 3; my $count = 0; + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $role (@roles) { my $checked = ''; if (grep(/^\Q$role\E$/,@current)) { @@ -2035,12 +4003,12 @@ sub role_checkboxes { $output .= ''; } } - $output .= ''; if ($showsections) { $output .= ''; } $count ++; @@ -2067,12 +4035,12 @@ sub role_checkboxes { $output .= ''; } } - $output .= ''; if ($showsections) { $output .= ''.&Apache::loncommon::end_data_table_row(); } $total ++; @@ -2093,17 +4061,94 @@ sub role_checkboxes { return $output; } +sub set_discussion_fonts { + my ($cdom,$cnum,$item,$settings,$noedit) = @_; + my ($classorder,$classtitles) = &discussion_vote_classes(); + my ($styleorder,$styleitems) = &discussion_vote_styles(); + my $output; + if (ref($classorder) eq 'ARRAY') { + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + foreach my $cat (@{$classorder}) { + my %curr = (); + ($curr{'size'},$curr{'weight'},$curr{'style'},$curr{'other'}) = + split(/,/,$settings->{'discussion_post_fonts_'.$cat}); + $output .= &Apache::loncommon::start_data_table_row(). + ''; + if (ref($styleorder) eq 'ARRAY') { + foreach my $item (@{$styleorder}) { + $output .= ''; + } + $output .= &Apache::loncommon::end_data_table_row(); + } + return $output; +} + +sub discussion_vote_classes { + my $classorder = ['twoplus','oneplus','zero','oneminus','twominus']; + my %classtitles = &Apache::lonlocal::texthash( + 'twoplus' => 'Two sigma above mean', + 'oneplus' => 'One sigma above mean', + 'zero' => 'Within one sigma of mean', + 'oneminus' => 'One sigma below mean', + 'twominus' => 'Two sigma below mean', + ); + return ($classorder,\%classtitles); +} + +sub discussion_vote_styles { + my $styleorder = ['size','weight','style']; + my $styleitems = { + size => ['','px','%','xx-small','x-small','small','medium','large', + 'x-large','xx-large','smaller','larger'], + weight => ['','normal','bold','bolder','lighter','100','200','300','400', + '500','600','700','800','900'], + style => ['','normal','italic','oblique'], + }; + return ($styleorder,$styleitems); +} + sub print_classlists { - my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype) = @_; + my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype,$noedit) = @_; my @ordered; if ($position eq 'top') { @ordered = ('default_enrollment_start_date', 'default_enrollment_end_date'); + if ($crstype eq 'Course') { + push(@ordered,'defaultcredits'); + } } elsif ($position eq 'middle') { - @ordered = ('nothideprivileged'); + @ordered = ('nothideprivileged','checkforpriv'); } else { @ordered = ('student_classlist_view', - 'student_opt_in','student_classlist_portfiles'); + 'student_classlist_opt_in', + 'student_classlist_portfiles'); } my %lt; @@ -2130,20 +4175,28 @@ sub print_classlists { text => ''.&mt($itemtext->{'default_enrollment_end_date'}).'', input => 'dates', }, - + 'defaultcredits' => { + text => ''.&mt($itemtext->{'defaultcredits'}).'', + }, + 'nothideprivileged' => { text => ''.&mt($itemtext->{'nothideprivileged'}).'', input => 'checkbox', }, + 'checkforpriv' => { + text => ''.&mt($itemtext->{'checkforpriv'}).'', + input => 'selectbox', + }, + 'student_classlist_view' => { text => ''.&mt($itemtext->{'student_classlist_view'}).'', input => 'selectbox', 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', }, @@ -2156,11 +4209,11 @@ sub print_classlists { ($settings->{'student_classlist_view'} eq 'section')) { $settings->{'student_classlist_view'} = 'disabled'; } - return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype); + return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'classlists',$noedit); } sub print_appearance { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2192,11 +4245,11 @@ sub print_appearance { text => ''.&mt($itemtext->{'texengine'}).'', input => 'selectbox', options => { - jsMath => 'jsMath', + MathJax => 'MathJax', mimetex => &mt('Convert to Images'), tth => &mt('TeX to HTML'), }, - order => ['jsMath','mimetex','tth'], + order => ['MathJax','mimetex','tth'], nullval => $mathdef, }, 'tthoptions' => { @@ -2204,12 +4257,20 @@ sub print_appearance { input => 'textbox', size => 40, }, + 'uselcmath' => { + text => ''.&mt($itemtext->{'uselcmath'}).'', + input => 'radio', + }, + 'usejsme' => { + text => ''.&mt($itemtext->{'usejsme'}).'', + input => 'radio', + }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'appearance',$noedit); } sub print_grading { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2220,11 +4281,12 @@ sub print_grading { input => 'selectbox', options => { standard => &mt('Standard: shows points'), + categories => &mt('Categories: shows points according to categories'), external => &mt('External: shows number of completed parts and totals'), externalnototals => &mt('External: shows only number of completed parts'), spreadsheet => &mt('Spreadsheet: (with link to detailed scores)'), }, - order => ['standard','external','externalnototals','spreadsheet'], + order => ['standard','categories','external','externalnototals','spreadsheet'], }, 'rndseed' => { text => ''.&mt($itemtext->{'rndseed'}).''. @@ -2241,6 +4303,7 @@ sub print_grading { '64bit5' => '64bit5', }, order => ['32bit','64bit','64bit2','64bit3','64bit4','64bit5'], + advanced => 1 }, 'receiptalg' => { text => ''.&mt($itemtext->{'receiptalg'}).'
'. @@ -2252,17 +4315,18 @@ sub print_grading { receipt3 => 'receipt3', }, order => ['receipt','receipt2','receipt3'], + advanced => 1 }, 'disablesigfigs' => { text => ''.&mt($itemtext->{'disablesigfigs'}).'', input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'grading',$noedit); } sub print_printouts { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2290,7 +4354,7 @@ sub print_printouts { A6 => &mt('A6').' [105x148 mm]', }, order => ['Letter','Legal','Tabloid','Executive','A2','A3','A4','A5','A6'], - nullval => 'None specified', + nullval => &mt('None specified'), }, print_header_format => { text => ''.&mt($itemtext->{'print_header_format'}).'', @@ -2308,14 +4372,14 @@ sub print_printouts { 0 => &mt('No'), }, order => ['1','0'], - nullval => 'None specified - use domain default', + nullval => &mt('None specified - use domain default'), } ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'printouts',$noedit); } sub print_spreadsheet { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2347,11 +4411,11 @@ sub print_spreadsheet { input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'spreadsheet',$noedit); } sub print_bridgetasks { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2389,11 +4453,149 @@ sub print_bridgetasks { input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'bridgetasks',$noedit); +} + +sub print_lti { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; + unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { + return; + } + my @menuitems = ('fullname','coursetitle','role','logout','grades'); + my %menutitles = <imenu_titles(); + my ($domdefs,$displaydefs); + if ($env{'request.lti.login'}) { + my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider'); + my @domdefsmenu; + if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') { + if ($lti{$env{'request.lti.login'}}{'topmenu'}) { + $domdefs = &mt('Header shown').', '; + } + if ($lti{$env{'request.lti.login'}}{'inlinemenu'}) { + $domdefs .= &mt('Inline menu shown'); + } + $domdefs =~ s/,\s$//; + if (!$domdefs) { + $domdefs = &mt('No header or inline menu shown'); + } + $domdefs = ' ('.&mt('Domain default').': '.$domdefs.')'; + if (ref($lti{$env{'request.lti.login'}}{'lcmenu'}) eq 'ARRAY') { + @domdefsmenu = @{$lti{$env{'request.lti.login'}}{'lcmenu'}}; + } + } + $displaydefs = &mt('Domain defaults'); + if (@domdefsmenu) { + my @diffs = &Apache::loncommon::compare_arrays(\@menuitems,\@domdefsmenu); + if (@diffs) { + my $missing; + foreach my $item (@menuitems) { + unless (grep(/^\Q$item\E$/,@domdefsmenu)) { + $missing .= ' '.$menutitles{$item}.','; + } + } + $missing =~ s/,$//; + $displaydefs .= ': '.&mt('Not shown').' --'.$missing; + } else { + $displaydefs .= ': '.&mt('All shown'); + } + } else { + $displaydefs .= ': '.&mt('Not shown').' -- '.join(', ', map { $menutitles{$_}; } @menuitems); + } + } else { + $displaydefs = &mt('Domain defaults only available in LTI context'); + } + my %items = ( + 'lti.override' => { + text => ''.&mt($itemtext->{'lti.override'}).''.$domdefs, + input => 'radio', + }, + 'lti.topmenu' => { + text => ''.&mt($itemtext->{'lti.topmenu'}).'', + input => 'radio', + }, + 'lti.inlinemenu' => { + text => ''.&mt($itemtext->{'lti.inlinemenu'}).'', + input => 'radio', + }, + 'lti.lcmenu' => { + text => ''.&mt($itemtext->{'lti.lcmenu'}).'
'.$displaydefs, + input => 'custom', + }, + ); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'lti',$noedit); +} + +sub lcmenu_checkboxes { + my ($cdom,$caller,$settings,$crstype,$noedit) = @_; + my @menuitems = ('fullname','coursetitle','role','logout','grades'); + my %menutitles = <imenu_titles(); + my (@current,@domdefs); + if ($env{'request.lti.login'}) { + my %lti = &Apache::lonnet::get_domain_lti($cdom,'provider'); + if (ref($lti{$env{'request.lti.login'}}) eq 'HASH') { + if (ref($lti{$env{'request.lti.login'}}{'lcmenu'}) eq 'ARRAY') { + @domdefs = @{$lti{$env{'request.lti.login'}}{'lcmenu'}}; + } + } + } + if (ref($settings) eq 'HASH') { + if ($settings->{'lti.lcmenu'}) { + unless ($settings->{'lti.lcmenu'} eq 'none') { + @current = split(',',$settings->{'lti.lcmenu'}); + } + } else { + @current = @domdefs; + } + } else { + @current = @domdefs; + } + my $numinrow = 3; + my $count = 0; + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + my $output = '
'. + ''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). '
'; } elsif ($item eq 'pch.users.denied') { - $datatable .= &user_table($cdom,$item,undef, - $settings->{$item},\%lt); + $datatable .= '
'. + &user_table($cdom,$item,undef, + $settings->{$item},\%lt,$noedit); + } elsif ($item eq 'pac.roles.denied') { + $datatable .= ''. + ''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). + '
'; + } elsif ($item eq 'pac.users.denied') { + $datatable .= '
'. + &user_table($cdom,$item,undef, + $settings->{$item},\%lt,$noedit); } elsif ($item eq 'allow_limited_html_in_feedback') { - $datatable .= &yesno_radio($item,$settings); + $datatable .= &yesno_radio($item,$settings,undef,undef,undef,$noedit); } elsif ($item eq 'allow_discussion_post_editing') { - $datatable .= &Apache::loncommon::start_data_table(). + $datatable .= '
'. + &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). '
'.&mt('Role').''. &mt('Sections').'
'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row(). + '
'.&mt('Sum of likes/dislikes').''.&mt('font-size').''.&mt('font-weight').''.&mt('font-style').''.&mt('Other css').'
'. - &select_sections($item,$role,\@sections,$currsec{$role}). + &select_sections($item,$role,\@sections,$currsec{$role},$noedit). '
'. - &select_sections($item,$role,\@sections,$currsec{$role}). + &select_sections($item,$role,\@sections,$currsec{$role},$noedit). ''.$classtitles->{$cat}.''; + my $selitem = $item; + if ($item eq 'size') { + my ($currsize,$currunit); + if ($curr{'size'} =~ /^(\d+)(px|%)$/) { + ($currsize,$currunit) = ($1,$2); + $curr{'size'} = $currunit; + } + $output .= ''. + ' '; + $selitem = 'unit'; + } + if ((ref($styleitems) eq 'HASH') && (ref($styleitems->{$item}) eq 'ARRAY')) { + $output .= '
'; + foreach my $item (@menuitems) { + my $checked = ''; + if (grep(/^\Q$item\E$/,@current)) { + $checked = ' checked="checked" '; + } + my $rem = $count%($numinrow); + if ($rem == 0) { + if ($count > 0) { + $output .= ''; + } + $output .= ''; + } + $output .= ''; + $count ++; + } + my $rem = $count%($numinrow); + my $colsleft = $numinrow - $rem; + if ($colsleft > 1 ) { + $output .= ''; + } elsif ($colsleft == 1) { + $output .= ''; + } + $output .= '
'. + '  
'; +} + +sub ltimenu_titles { + return &Apache::lonlocal::texthash( + fullname => 'Full name', + coursetitle => 'Course title', + role => 'Role', + logout => 'Logout', + grades => 'Grades', + ); } sub print_other { - my ($cdom,$settings,$allitems,$rowtotal,$crstype) = @_; + my ($cdom,$settings,$allitems,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } @@ -2414,7 +4616,7 @@ sub print_other { input => 'textbox', size => '30', }; - my $output = &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype); + my $output = &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'other',$noedit); } sub get_other_items { @@ -2431,7 +4633,10 @@ sub get_other_items { unless (($parameter =~ m/^internal\./)||($parameter =~ m/^metadata\./) || ($parameter =~ m/^selfenroll_/) || ($parameter =~ /_selfenroll$/) || ($parameter eq 'type') || - ($parameter =~ m/^(cc|co|in|ta|ep|ad|st)\.plaintext$/)) { + ($parameter =~ m/^(cc|co|in|ta|ep|ad|st)\.plaintext$/) + || ($parameter =~ m/^discussion_post_fonts/) || + ($parameter =~ m{^(minimal|updated|uploaded|external)syllabus$}) || + ($parameter eq 'clonedfrom')) { push(@ordered,$parameter); } } @@ -2440,13 +4645,18 @@ sub get_other_items { } sub item_table_row_start { - my ($text,$count,$add_class) = @_; + my ($text,$count,$add_class,$colspan) = @_; my $output; - my $css_class = ($count % 2) ? 'LC_odd_row' : 'LC_even_row'; - $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); - $output .= '
'.$text. - ''; + my $css_class = ($count % 2) ? 'LC_odd_row' : 'LC_even_row'; + $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); + $output .= '
'.$text. + ''; + } else { + $output .= ''; + } return $output; } @@ -2455,25 +4665,43 @@ sub item_table_row_end { } sub yesno_radio { - my ($item,$settings) = @_; + my ($item,$settings,$unsetdefault,$valueyes,$valueno,$noedit) = @_; my $itemon = ' '; my $itemoff = ' checked="checked" '; + if (($valueyes eq '') && ($valueno eq '')) { + $valueyes = 'yes'; + $valueno = ''; + } if (ref($settings) eq 'HASH') { - if ($settings->{$item} eq 'yes') { + if ($settings->{$item} eq $valueyes) { $itemon = $itemoff; $itemoff = ' '; } + unless (exists($settings->{$item})) { + if ($unsetdefault eq $valueyes) { + $itemon = $itemoff; + $itemoff = ' '; + } + } + } + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; } return ' '. + $itemon.' value="'.$valueyes.'"'.$disabled.' />'.&mt('Yes').' '. ''; + $itemoff.' value="'.$valueno.'"'.$disabled.' />'.&mt('No').''; } sub select_from_options { - my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange) = @_; + my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange,$noedit) = @_; my $output; + my $disabled; + if ($noedit) { + $disabled = ' disabled=disabled"'; + } if ((ref($order) eq 'ARRAY') && (ref($options) eq 'HASH')) { $output=''; foreach my $user (sort(@privusers)) { my $hideon = ' checked="checked" '; @@ -2617,8 +4883,9 @@ sub nothidepriv_row { ''. + $hideon.' value=""'.$disabled.' />'.&mt('Hidden').' '. + ''. ''; } $datatable .= '
'. ' '. - '
'; @@ -2632,8 +4899,72 @@ sub nothidepriv_row { return $datatable; } +sub checkforpriv_row { + my ($cdom,$item,$settings,$crstype,$noedit) = @_; + my $datatable; + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + if (keys(%domains) == 1) { + $datatable = '
'. + &mt("Course's domain is only domain"); + return $datatable; + } + my @excdoms = ($cdom); + my $num = 0; + if ($settings->{$item} eq '') { + $datatable = ''. + &Apache::loncommon::select_dom_form('','checkforpriv_'.$num, + 1,1,undef,undef,\@excdoms, + $noedit); + } else { + my @privdoms = split(/,/,$settings->{$item}); + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + $datatable = '
'. + &Apache::loncommon::start_data_table(); + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + if (@privdoms > 0) { + foreach my $currdom (@privdoms) { + next unless ($domains{$currdom}); + my $domdesc = &Apache::lonnet::domain($currdom,'description'); + if ($domdesc eq '') { + $domdesc = $currdom; + } + $datatable .= + &Apache::loncommon::start_data_table_row(). + '
'. + &mt('Domain:').' '.$domdesc. + '
'. + '
'. + &mt('Additional domain:'). '
'. + &Apache::loncommon::select_dom_form('','checkforpriv_'.$num,1, + 1,undef,undef,\@excdoms,$noedit). + '
'; + $output .= ''; + } + $output .= '

'. + $currstr.''; + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } if (@curr > 0) { for (my $i=0; $i<@curr; $i++) { my $pos = $i+1; $output .= ''. ''; + '"'.$disabled.' />'; if ($curr[$i] =~ /^%\d*[nca]$/) { my ($limit,$subst) = ($curr[$i] =~ /^%(\d*)([nca])$/); $output .= ''; + &substitution_selector($i,$subst,$limit,$disabled).''; } else { $output .= ''; + ' value="'.$curr[$i].'" size="25"'.$disabled.' />'; } $output .= ''; } } - my $pos = $currnum+1; - $output .= ''. + my $pos = $currnum+1; + unless ($noedit) { + $output .= + ''. ''. ''; - $pos ++; - $currnum ++; - $output .= ''. + $pos ++; + $currnum ++; + $output .= + ''. ''. @@ -2743,14 +5082,15 @@ ENDJS '" value="" size ="25" />'. ''. - ''. - '
'. - &position_selector($pos,$i,$maxnum).&mt('Delete:'). + &position_selector($pos,$i,$maxnum,$disabled).&mt('Delete:'). ''. - &substitution_selector($i,$subst,$limit).''.&mt('Text').'
'. '
'. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''. &substitution_selector($currnum).'
'. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').'
'; + '

'; return $output; } sub position_selector { - my ($pos,$num,$maxnum) = @_; - my $output = ''; for (my $j=1; $j<=$maxnum; $j++) { my $sel = ''; if ($pos == $j) { @@ -2764,7 +5104,7 @@ sub position_selector { } sub substitution_selector { - my ($num,$subst,$limit,$crstype) = @_; + my ($num,$subst,$limit,$crstype,$disabled) = @_; my ($stunametxt,$crsidtxt); if ($crstype eq 'Community') { $stunametxt = 'member name'; @@ -2779,7 +5119,7 @@ sub substitution_selector { a => 'assignment note', ); my $output .= &mt('Substitution').'
'. - ''; if ($subst eq '') { $output .= ''; } @@ -2793,8 +5133,74 @@ sub substitution_selector { } $output .= ''.&mt('Size limit').'
'. '
'; + '" value="'.$limit.'" size="5"'.$disabled.' />'; 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 '*') { + if ($currclone =~ /:/) { + 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 '*') { + if ($oldclone =~ /:/) { + 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; 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.