# The LearningOnline Network with CAPA # Handler to set configuration settings for a course # # $Id: courseprefs.pm,v 1.97 2022/01/16 16:52:42 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA# # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # # ############################################################### ############################################################## =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; use Apache::Constants qw(:common :http); 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) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; return OK; } my $context = 'course'; my $cid = $env{'request.course.id'}; my ($cnum,$cdom,$chome) = &get_course($cid); my $crstype = &Apache::loncommon::course_type(); my ($parm_permission,$allowed) = &get_permission($cid); my $navmap = Apache::lonnavmaps::navmap->new(); if ($allowed && $navmap) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; } else { if ($navmap) { if ($crstype eq 'Community') { $env{'user.error.msg'}= "/adm/courseprefs:opa:0:0:Cannot modify community settings"; } else { $env{'user.error.msg'}= "/adm/courseprefs:opa:0:0:Cannot modify course settings"; } } else { if ($crstype eq 'Community') { $env{'user.error.msg'}= "/adm/courseprefs::0:1:Course environment gone, reinitialize the community"; } else { $env{'user.error.msg'}= "/adm/courseprefs::0:1:Course environment gone, reinitialize the course"; } } return HTTP_NOT_ACCEPTABLE; } $registered_cleanup=0; @{$modified_courses}=(); &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['phase','actions','origin']); &Apache::lonhtmlcommon::clear_breadcrumbs(); if ($env{'form.origin'} eq 'params') { &Apache::lonhtmlcommon::add_breadcrumb({href=>"/adm/parmset", text=>"Parameter Manager"}); } my ($brtext,$brtitle,$crsinfotext,$crsinfodesc,$crscateg,$crshide); my %lt; if ($crstype eq 'Community') { %lt = ( 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', rept => 'Replacement titles for standard community roles', time => 'Timezone where the community is located', date => 'Locale used for community calendar', coco => 'Community Content', copo => 'Community Policy', priv => 'Domain Coordinators in community', defd => 'Default dates for member access', stuv => 'Member-viewable membership list options', stul => 'Member agreement needed to be listed', 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 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', rept => 'Replacement titles for standard course roles', time => 'Timezone in which the course takes place', date => 'Locale used for course calendar', coco => 'Course Content', copo => 'Course Policy', priv => 'Domain Coordinators in course', defd => 'Default dates for student access', stuv => 'Student-viewable classlist options', stul => 'Student agreement needed to be listed', 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 = &Apache::lonhtmlcommon::breadcrumbs($lt{'edit'}); my $phase = 'pickactions'; if ( exists($env{'form.phase'}) ) { $phase = $env{'form.phase'}; } 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 %courselti=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); if ($courselti{'lock'}) { delete($courselti{'lock'}); } $values{'linkprotection'} = \%courselti; my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', 'menuitems','linkprotection','spreadsheet','bridgetasks', 'lti','other'); my %prefs = ( 'courseinfo' => { text => $lt{'gens'}, help => 'Course_Prefs_General', ordered => ['owner','co-owners','loncaparev','description', 'clonedfrom','courseid','uniquecode','categories', 'hidefromcat','syllabus','cloners','url', 'rolenames'], itemtext => { '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'}, 'syllabus' => 'Syllabus status', 'url' => 'Top Level Map', 'rolenames' => $lt{'rept'}, 'loncaparev' => $lt{'lcrv'}, 'clonedfrom' => 'Cloned from', }, }, 'localization' => { text => 'Language and time localization', help => 'Course_Prefs_Language', ordered => ['languages','timezone','datelocale'], itemtext => { languages => 'Languages used', timezone => $lt{'time'}, datelocale => $lt{'date'}, }, }, 'feedback' => { text => 'Feedback messages', help => 'Course_Prefs_Feedback', header => [{col1 => 'Questions about:', col2 => 'Recipients'}], ordered => ['question.email','comment.email','policy.email'], itemtext => { 'question.email' => 'Resource Content', 'comment.email' => $lt{'coco'}, 'policy.email' => $lt{'copo'}, }, }, 'discussion' => { text => 'Discussion and Chat', 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', 'discussion_post_fonts'], itemtext => { '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_Prefs_Classlists', header => [{col1 => 'Type', col2 => $lt{'defd'}}, {col1 => 'Setting', col2 => $lt{'priv'}}, {col1 => 'Setting', col2 => $lt{'stuv'}}], ordered => ['default_enrollment_start_date', 'default_enrollment_end_date', '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{'prus'}, checkforpriv => $lt{'prdo'}, student_classlist_view => $lt{'stuv'}, 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_Prefs_Display', ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', 'tthoptions','uselcmath','usejsme','inline_chem'], 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)', inline_chem => 'Chemical reaction response uses inline preview, not pop-up', }, }, 'grading' => { text => 'Grading', help => 'Course_Prefs_Grading', ordered => ['grading','rndseed', 'receiptalg','disablesigfigs'], itemtext => { grading => 'Grading', rndseed => 'Randomization algorithm used', receiptalg => 'Receipt algorithm used', disablesigfigs => 'Disable checking of Significant Figures', }, }, 'printouts' => { text => 'Printout generation', help => 'Course_Prefs_Printouts', ordered => ['problem_stream_switch','suppress_tries', 'default_paper_size','print_header_format', 'disableexampointprint','canuse_pdfforms'], itemtext => { problem_stream_switch => 'Allow problems to be split over pages', suppress_tries => 'Suppress number of tries in printing', default_paper_size => 'Default paper type', print_header_format => 'Print header format', disableexampointprint => 'Disable automatically printing point values on bubblesheet exams', canuse_pdfforms => 'Users can print problems as PDF forms and upload later for grading', }, }, 'spreadsheet' => { text => 'Spreadsheets', help => 'Course_Prefs_Spreadsheet', ordered => ['spreadsheet_default_classcalc', 'spreadsheet_default_studentcalc', 'spreadsheet_default_assesscalc','hideemptyrows'], itemtext => { spreadsheet_default_classcalc => $lt{'defc'}, spreadsheet_default_studentcalc => $lt{'defs'}, spreadsheet_default_assesscalc => 'Default Assessment Spreadsheet', hideemptyrows => 'Hide Empty Rows in Spreadsheets', }, }, 'bridgetasks' => { text => 'Bridge tasks', help => 'Course_Prefs_Bridgetasks', ordered => ['task_messages','task_grading', 'suppress_embed_prompt'], itemtext => { task_messages => $lt{'seme'}, task_grading => 'Bridge Task grading by instructors and TAs in sections' , 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', }, }, 'menuitems' => { text => 'Menu display', help => 'Course_Prefs_Menus', header => [{col1 => 'Default Menu', col2 => 'Value',}, {col1 => 'Menu collections', col2 => 'Settings', }], ordered => ['menudefault','menucollections'], itemtext => { menudefault => 'Choose default collection of menu items for course', menucollections => 'Menu collections', }, }, 'linkprotection' => { text => 'Link protection', help => 'Course_Prefs_Linkprotection', header => [{col1 => 'Item', col2 => 'Settings', }], }, 'other' => { text => 'Other settings', help => 'Course_Prefs_Other', header => [ {col1 => 'Item', col2 => 'Value', }], }, ); 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, 'coursepref',$parm_permission); } elsif (($phase eq 'display') && ($parm_permission->{'display'})) { my $noedit; if (ref($parm_permission) eq 'HASH') { unless ($parm_permission->{'process'}) { $noedit = 1; } } my $jscript = &get_jscript($cid,$cdom,$phase,$crstype,\%values,$noedit); my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype, 'coursepref',$parm_permission); } else { &Apache::lonconfigsettings::display_choices($r,$phase,$context, \@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; foreach my $item (keys(%prefs)) { if (ref($prefs{$item}) eq 'HASH') { if (ref($prefs{$item}{'ordered'}) eq 'ARRAY') { push(@allitems,@{$prefs{$item}{'ordered'}}); if ($item eq 'feedback') { push(@allitems,(map { $_.'.text'; } @{$prefs{$item}{'ordered'}})); } } } } return @allitems; } sub print_config_box { my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$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 = ''."\n". ''; if (($action eq 'feedback') || ($action eq 'classlists') || ($action eq 'menuitems')) { $output .= ' '. &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,$noedit); } elsif ($action eq 'classlists') { $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'menuitems') { $output .= &print_menuitems('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''; } else { $output .= ' '; } $output .= &mt($item->{'header'}->[0]->{'col2'}).'
'; if ($action eq 'classlists') { $output .= ' '; if ($action eq 'classlists') { $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit). '
'.&mt($item->{'header'}->[1]->{'col1'}).''; } else { $output .= ' '; } $output .= &mt($item->{'header'}->[1]->{'col2'}).'
'; if (exists $item->{'header'}->[2]->{'col1'} || exists $item->{'header'}->[2]->{'col2'}) { $output .= ' '; } } } else { $output .= '
'.&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,$noedit); } elsif ($action eq 'localization') { $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'feedback') { $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'discussion') { $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,$noedit); } elsif ($action eq 'grading') { $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'printouts') { $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'spreadsheet') { $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'bridgetasks') { $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 'menuitems') { $output .= &print_menuitems('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'linkprotection') { $output .= &print_linkprotection($cdom,$settings,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'other') { $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype,$noedit); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''; } else { $output .= ''; } $output .= &mt($item->{'header'}->[0]->{'col2'}).'

'; return ($output,$rowtotal); } sub process_changes { my ($cdom,$cnum,$action,$values,$item,$changes,$allitems,$disallowed,$crstype) = @_; my (%newvalues,%courselti,$errors); if (ref($item) eq 'HASH') { if (ref($changes) eq 'HASH') { my @ordered; if ($action eq 'other') { @ordered = &get_other_items($cdom,$values,$allitems); if ($env{'form.newp_name'} ne '') { my $newp = $env{'form.newp_name'}; if ($env{'form.newp_value'} ne '') { if (ref($allitems) eq 'ARRAY') { unless ((grep(/^\Q$newp\E$/,@ordered)) || (grep(/^\Q$newp\E$/,@{$allitems}))) { $changes->{$newp} = $env{'form.newp_value'}; } } } } } elsif ($action eq 'linkprotection') { if (ref($values->{'linkprotection'}) eq 'HASH') { foreach my $id (keys(%{$values->{'linkprotection'}})) { if ($id =~ /^\d+$/) { push(@ordered,$id); unless (ref($values->{'linkprotection'}->{$id}) eq 'HASH') { $courselti{$id} = ''; } } } } @ordered = sort { $a <=> $b } @ordered; if (($env{'form.linkprot_add'}) && ($env{'form.linkprot_maxnum'} =~ /^\d+$/)) { push(@ordered,$env{'form.linkprot_maxnum'}); } } elsif (ref($item->{'ordered'}) eq 'ARRAY') { 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') || ($entry eq 'syllabus')); 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') { foreach my $entry (@ordered) { my $userstr = ''; my $total = $env{'form.'.$entry.'_total'}; if ($total) { my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); for (my $i=0; $i<$total; $i++) { unless (grep(/^$i$/,@deletes)) { $userstr .= $env{'form.'.$entry.'_user_'.$i}. &get_sec_str($entry,$i).','; } } } else { $total = 0; } if ($env{'form.'.$entry.'_uname_'.$total} ne '') { my $uname = $env{'form.'.$entry.'_uname_'.$total}; my $udom = $env{'form.'.$entry.'_udom_'.$total}; if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { $userstr =~ s/,$//; $disallowed->{'feedback'}{$entry} = $uname.':'.$udom; } else { $userstr .= $uname.':'.$udom.&get_sec_str($entry,$total); } } else { $userstr =~ s/,$//; } $newvalues{$entry} = $userstr; if ($newvalues{$entry} ne $values->{$entry}) { $changes->{$entry} = $newvalues{$entry}; } my $ext_entry = $entry.'.text'; $newvalues{$ext_entry} = $env{'form.'.$ext_entry}; if ($newvalues{$ext_entry} ne $values->{$ext_entry}) { $changes->{$ext_entry} = $newvalues{$ext_entry}; } } } elsif ($action eq 'menuitems') { my (%current,@colls); my $next = 1; if ($values->{'menucollections'}) { foreach my $item (split(/;/,$values->{'menucollections'})) { my ($num,$value) = split(/\%/,$item); if ($num =~ /^\d+$/) { unless (grep(/^$num$/,@colls)) { push(@colls,$num); } my @entries = split(/\&/,$value); foreach my $entry (@entries) { my ($name,$fields) = split(/=/,$entry); $current{$num}{$name} = $fields; } } } } if (@colls) { @colls = sort { $a <=> $b } @colls; $next += $colls[-1]; } if ($env{'form.menucollections_add'} eq $next) { push(@colls,$next); } my $currdef = $values->{'menudefault'}; my $possdef = $env{'form.menudefault'}; if (($possdef =~ /^\d+$/) && (grep(/^$possdef$/,@colls))) { if ($currdef ne $possdef) { $changes->{'menudefault'} = $possdef; } } elsif ($currdef) { $changes->{'menudefault'} = ''; } my $menucoll; if (@colls) { my ($ordered,$cats) = &menuitems_categories(); my %shortcats = &menuitems_abbreviations(); foreach my $num (@colls) { my ($entry,%include); map { $include{$_}= 1; } &Apache::loncommon::get_env_multiple('form.menucollections_'.$num); foreach my $item (@{$ordered}) { if ($item eq 'shown') { foreach my $type (@{$cats->{$item}}) { $entry .= $type.'='; if ($include{$type}) { $entry .= 'y'; } else { $entry .= 'n'; } $entry .= '&'; } } else { $entry .= $shortcats{$item}.'='; foreach my $type (@{$cats->{$item}}) { if ($include{$type}) { $entry .= $type.','; } } $entry =~ s/,$//; $entry .= '&'; } } $entry =~ s/\&$//; if ($menucoll) { $menucoll .= ';'; } $menucoll .= $num.'%'.$entry; } if ($menucoll ne $values->{'menucollections'}) { $changes->{'menucollections'} = $menucoll; } } elsif ($values->{'menucollections'}) { $changes->{'menucollections'} = ''; } } elsif ($action eq 'linkprotection') { my %menutitles = <imenu_titles(); my (@items,%deletions,%itemids,%haschanges); if ($env{'form.linkprot_add'}) { my $name = $env{'form.linkprot_name_add'}; $name =~ s/(`)/'/g; my ($newid,$error) = &get_courselti_id($cdom,$cnum,$name); if ($newid) { $itemids{'add'} = $newid; push(@items,'add'); $haschanges{$newid} = 1; } else { $errors .= ''. &mt('Failed to acquire unique ID for link protection'). ''; } } if (ref($values->{'linkprotection'}) eq 'HASH') { my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_del'); my $maxnum = $env{'form.linkprot_maxnum'}; for (my $i=0; $i<=$maxnum; $i++) { my $itemid = $env{'form.linkprot_id_'.$i}; $itemid =~ s/\D+//g; if ($itemid) { if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') { push(@items,$i); $itemids{$i} = $itemid; if ((@todelete > 0) && (grep(/^$i$/,@todelete))) { $deletions{$itemid} = $values->{'linkprotection'}->{$itemid}->{'name'}; } } } } } foreach my $idx (@items) { my $itemid = $itemids{$idx}; next unless ($itemid); if (exists($deletions{$itemid})) { $courselti{$itemid} = $deletions{$itemid}; $haschanges{$itemid} = 1; next; } my %current; if (ref($values->{'linkprotection'}) eq 'HASH') { if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') { foreach my $key (keys(%{$values->{'linkprotection'}->{$itemid}})) { $current{$key} = $values->{'linkprotection'}->{$itemid}->{$key}; } } } foreach my $inner ('name','key','secret','lifetime','version') { my $formitem = 'form.linkprot_'.$inner.'_'.$idx; $env{$formitem} =~ s/(`)/'/g; if ($inner eq 'lifetime') { $env{$formitem} =~ s/[^\d.]//g; } unless ($idx eq 'add') { if ($current{$inner} ne $env{$formitem}) { $haschanges{$itemid} = 1; } } if ($env{$formitem} ne '') { $courselti{$itemid}{$inner} = $env{$formitem}; } } } if (keys(%haschanges)) { foreach my $entry (keys(%haschanges)) { $changes->{$entry} = $courselti{$entry}; } } } else { foreach my $entry (@ordered) { if ($entry eq 'cloners') { if ($env{'form.cloners_all'}) { $newvalues{$entry} = '*'; } else { my @clonedoms; if (exists($env{'form.cloners_activate'})) { my $actnum = $env{'form.cloners_activate'}; if ($actnum ne '-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}); } } } } else { my $num = $env{'form.cloners_total'}; my @deletes = &Apache::loncommon::get_env_multiple('form.cloners_delete'); for (my $i=0; $i<$num; $i++) { if (!grep(/^$i$/,@deletes)) { my $clonedom = $env{'form.cloners_dom_'.$i}; if (&check_clone($clonedom,$disallowed) eq 'ok') { if (!grep(/^\*:\Q$clonedom\E$/,@clonedoms)) { push(@clonedoms,'*:'.$clonedom); } } } } if (@clonedoms) { $newvalues{$entry}=join(',',@clonedoms); } } if ($env{'form.cloners_newdom'} ne '') { my $clonedom = $env{'form.cloners_newdom'}; if (&check_clone($clonedom,$disallowed) eq 'ok') { my $newdom = '*:'.$env{'form.cloners_newdom'}; if (@clonedoms) { if (!grep(/^\Q$newdom\E$/,@clonedoms)) { $newvalues{$entry} .= ','.$newdom; } } else { $newvalues{$entry} = $newdom; } } } if ($env{'form.'.$entry} ne '') { my @cloners = split(',',$env{'form.'.$entry}); my @okcloners; foreach my $cloner (@cloners) { $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); } } } } if (@okcloners) { my $okclonestr = join(',',@okcloners); if ($newvalues{$entry} ne '') { $newvalues{$entry} .= ','.$okclonestr; } else { $newvalues{$entry} = $okclonestr; } } } 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') { foreach my $key (keys(%{$disallowed->{'cloners'}})) { $disallowed->{'cloners'}{$key} =~ s/,$//; } } } } 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'}; } } if ($autocoowner) { $newvalues{'co-owners'} = $values->{'internal.co-owners'}; } else { 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_coowner'}) { foreach my $item (@pendingcoown) { unless ($item eq $uname.':'.$udom) { push(@newpending,$item); } } @newcoown = @currcoown; if ($env{'form.pending_coowner'} eq 'accept') { unless (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { push(@newcoown,$uname.':'.$udom); } } } elsif ($env{'form.remove_coowner'}) { foreach my $item (@currcoown) { unless ($item eq $uname.':'.$udom) { push(@newcoown,$item); } } if ($pendingcoowners ne '') { @newpending = @pendingcoown; } } else { @newcoown = @currcoown; } $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') { my %adv_roles = &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1); my @stds; if ($crstype eq 'Community') { @stds = ('co'); } else { @stds = ('cc'); } push(@stds,('in','ta','ep','ad','st')); my (@replacements,@regulars); foreach my $role (@stds) { if ($values->{$role.'.plaintext'} ne '') { push(@replacements,$role); } else { push(@regulars,$role); } } foreach my $stdrole (@stds) { my $ext_entry = $entry.'_'.$stdrole; my $stdname = &Apache::lonnet::plaintext($stdrole,$crstype, $env{'request.course.id'},1); if ($env{'form.'.$ext_entry} eq $stdname) { $newvalues{$ext_entry} = ''; } else { $newvalues{$ext_entry} = $env{'form.'.$ext_entry}; } if ($newvalues{$ext_entry} ne $values->{$stdrole.'.plaintext'}) { my $dupname = 0; if ($newvalues{$ext_entry} ne '') { if (grep(/^\Q$newvalues{$ext_entry}\E$/,@replacements)) { $dupname = 1; push(@{$disallowed->{'rolenames'}{'replacements'}},$newvalues{$ext_entry}); } if (!$dupname) { if (grep(/^\Q$newvalues{$ext_entry}\E$/,@regulars)) { $dupname = 1; push(@{$disallowed->{rolenames}{'regulars'}},$newvalues{$ext_entry}); } } if (!$dupname) { foreach my $role (keys(%adv_roles)) { if ($role =~ m{^cr/$match_domain/$match_name/\Q$newvalues{$ext_entry}\E$}) { $dupname = 1; push(@{$disallowed->{rolenames}{'customrole'}},$newvalues{$ext_entry}); last; } } } } if (!$dupname) { $changes->{$ext_entry} = $newvalues{$ext_entry}; } } } } elsif (($entry eq 'plc.roles.denied') || ($entry eq 'pch.roles.denied') || ($entry eq 'pac.roles.denied')) { my @denied = &Apache::loncommon::get_env_multiple('form.'.$entry); @denied = sort(@denied); my $deniedstr = ''; if (@denied > 0) { $deniedstr = join(',',@denied); } $newvalues{$entry} = $deniedstr; } elsif (($entry eq 'plc.users.denied') || ($entry eq 'pch.users.denied') || ($entry eq 'pac.users.denied')) { my $total = $env{'form.'.$entry.'_total'}; my $userstr = ''; my @denied; if ($total > 0) { my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); for (my $i=0; $i<$total; $i++) { unless (grep(/^$i$/,@deletes)) { $userstr .= $env{'form.'.$entry.'_user_'.$i}.','; push(@denied,$env{'form.'.$entry.'_user_'.$i}); } } } else { $total = 0; } if ($env{'form.'.$entry.'_uname_'.$total} ne '') { my $uname = $env{'form.'.$entry.'_uname_'.$total}; my $udom = $env{'form.'.$entry.'_udom_'.$total}; if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { $userstr =~ s/,$//; $disallowed->{'discussion'}{$entry} = $uname.':'.$udom; } else { my $newuser .= $uname.':'.$udom; if (grep(/^\Q$newuser\E$/,@denied)) { $userstr =~ s/,$//; } else { $userstr .= $newuser; } } } else { $userstr =~ s/,$//; } $newvalues{$entry} = $userstr; } elsif ($entry eq 'allow_discussion_post_editing') { my @canedit = &Apache::loncommon::get_env_multiple('form.'.$entry); @canedit = sort(@canedit); foreach my $role (@canedit) { my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$role); if ((grep(/^\s*$/,@secs)) || (@secs == 0)) { $newvalues{$entry} .= $role.','; } else { foreach my $sec (@secs) { $newvalues{$entry} .= $role.':'.$sec.','; } } } $newvalues{$entry} =~ s/,$//; } elsif ($entry eq '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; if ($values->{$entry} ne '') { foreach my $user (split(/\s*\,\s*/,$values->{$entry})) { my $nothide; if ($user !~ /:/) { $nothide = join(':',split(/[\@]/,$user)); } else { $nothide = $user; } if ((defined($nothide)) && (!grep(/^\Q$nothide\E$/,@curr_nothide))) { push(@curr_nothide,$nothide); } } } foreach my $key (keys(%env)) { if ($key =~ /^form\.\Q$entry\E_($match_username:$match_domain)$/) { if ($env{$key}) { my $nothide = $1; if (!grep(/^\Q$nothide\E$/,@new_nothide)) { push(@new_nothide,$nothide); } } } } @new_nothide = sort(@new_nothide); my @differences = &Apache::loncommon::compare_arrays(\@curr_nothide, \@new_nothide); if (@differences > 0) { if (@new_nothide > 0) { $newvalues{$entry} = join(',',@new_nothide); } else { $newvalues{$entry} = ''; } } else { $newvalues{$entry} = $values->{$entry}; } } elsif ($entry eq 'print_header_format') { my $maxnum = $env{'form.printfmthdr_maxnum'}; my @newhdr; if ($maxnum > 2) { for (my $i=0; $i<$maxnum-2; $i++) { if ($env{'form.printfmthdr_del_'.$i}) { $newhdr[$env{'form.printfmthdr_pos_'.$i}] = ''; } else { my $hdr; if ($env{'form.printfmthdr_sub_'.$i} =~ /^[nca]$/) { $hdr = '%'; if ($env{'form.printfmthdr_limit_'.$i} =~ /^\d+$/) { $hdr .= $env{'form.printfmthdr_limit_'.$i}; } $hdr .= $env{'form.printfmthdr_sub_'.$i}; } elsif ($env{'form.printfmthdr_text_'.$i} ne '') { $hdr = $env{'form.printfmthdr_text_'.$i}; } $newhdr[$env{'form.printfmthdr_pos_'.$i}] = $hdr; } } } my $newsub = $maxnum-2; if ($env{'form.printfmthdr_sub_'.$newsub} =~ /^[nca]$/) { my $hdr = '%'; if ($env{'form.printfmthdr_limit_'.$newsub} =~ /^\d+$/) { $hdr .= $env{'form.printfmthdr_limit_'.$newsub}; } $hdr .= $env{'form.printfmthdr_sub_'.$newsub}; $newhdr[$env{'form.printfmthdr_pos_'.$newsub}] = $hdr; } my $newtext = $maxnum-1; $newhdr[$env{'form.printfmthdr_pos_'.$newtext}] = $env{'form.printfmthdr_text_'.$newtext}; $newvalues{$entry} = join('',@newhdr); } elsif (($entry eq 'languages') || ($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)) { $settings .= $env{'form.'.$entry.'_'.$i}.','; } } } else { $total = 0; } if ($env{'form.'.$entry.'_'.$total} ne '') { 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 { my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); if ($domains{$new}) { $settings .= $new; } else { $settings =~ s/,$//; $disallowed->{'classlists'}{$entry} = $new; } } } else { $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} = ''; } } } else { $newvalues{$entry} = $env{'form.'.$entry}; } unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts')) { if ($newvalues{$entry} ne $values->{$entry}) { $changes->{$entry} = $newvalues{$entry}; } } } } } } } return $errors; } sub get_courselti_id { my ($cdom,$cnum,$name) = @_; # get lock on lti db in course my $lockhash = { lock => $env{'user.name'}. ':'.$env{'user.domain'}, }; my $tries = 0; my $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); my ($id,$error); while (($gotlock ne 'ok') && ($tries<10)) { $tries ++; sleep (0.1); $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); } if ($gotlock eq 'ok') { my %currids = &Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); if ($currids{'lock'}) { delete($currids{'lock'}); if (keys(%currids)) { my @curr = sort { $a <=> $b } keys(%currids); if ($curr[-1] =~ /^\d+$/) { $id = 1 + $curr[-1]; } else { $id = 1; } } else { $id = 1; } if ($id) { unless (&Apache::lonnet::newput('lti',{ $id => $name },$cdom,$cnum) eq 'ok') { $error = 'nostore'; } } else { $error = 'nonumber'; } } my $dellockoutcome = &Apache::lonnet::del('lti',['lock'],$cdom,$cnum); } else { $error = 'nolock'; } return ($id,$error); } sub get_sec_str { my ($entry,$num) = @_; my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$num); my $secstr; if (grep(/^\s*$/,@secs)) { $secstr = ''; } elsif (@secs > 0) { $secstr = join(';',@secs); } if ($secstr ne '') { return '('.$secstr.')'; } return; } sub check_clone { my ($clonedom,$disallowed,$clonename) = @_; return if (ref($disallowed) ne 'HASH'); if ($clonedom !~ /^$match_domain$/) { $disallowed->{'cloners'}{'format'} .= $clonedom.','; return; } elsif (!&Apache::lonnet::domain($clonedom)) { $disallowed->{'cloners'}{'domain'} .= $clonedom.','; return; } if ($clonename ne '') { if ($clonename !~ /^$match_username$/) { $disallowed->{'cloners'}{'format'} .= $clonename.':'.$clonedom.','; return; } else { if (&Apache::lonnet::homeserver($clonename,$clonedom) eq 'no_host') { $disallowed->{'cloners'}{'newuser'} .= $clonename.':'.$clonedom.','; return; } } } return 'ok'; } sub store_changes { my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes,$crstype) = @_; my ($chome,$output); my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot); if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) { if (ref($values->{'linkprotection'}) eq 'HASH') { %oldlinkprot = %{$values->{'linkprotection'}}; } delete($values->{'linkprotection'}); %storehash = %{$values}; } else { if ($crstype eq 'Community') { $output = &mt('No changes made to community settings.'); } else { $output = &mt('No changes made to course settings.'); } return $output; } my ($numchanges,$skipstore); if (ref($changes) eq 'HASH') { $numchanges = scalar(keys(%{$changes})); if (($numchanges == 1) && (exists($changes->{'linkprotection'}))) { $skipstore = 1; } elsif (!$numchanges) { if ($crstype eq 'Community') { $output = &mt('No changes made to community settings.'); } else { $output = &mt('No changes made to course settings.'); } return $output; } } my %yesno = ( hidefromcat => '1', problem_stream_switch => '1', suppress_tries => '1', disableexampointprint => '1', hideemptyrows => '1', suppress_embed_prompt => '1', ); foreach my $item (@{$prefs_order}) { if (grep(/^\Q$item\E$/,@{$actions})) { $output .= '

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

'; if (ref($changes->{$item}) eq 'HASH') { if ((keys(%{$changes->{$item}}) > 0) || ($item eq 'linkprotection')) { $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 .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',''.$key.'')).'
  • '; } else { $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.$key.'', "'$storehash{$key}'")).'
  • '; } } } elsif ($item eq 'linkprotection') { if (&Apache::lonnet::put('lti',$changes->{'linkprotection'},$cdom,$cnum,1) eq 'ok') { my $hashid=$cdom.'_'.$cnum; &Apache::lonnet::devalidate_cache_new('courselti',$hashid); foreach my $itemid (sort { $a <=> $b } %{$changes->{'linkprotection'}}) { if (ref($changes->{'linkprotection'}->{$itemid}) eq 'HASH') { my %values = %{$changes->{'linkprotection'}->{$itemid}}; my %desc = &linkprot_names(); my $display; foreach my $title ('name','lifetime','version','key','secret') { if ($title eq 'secret') { my $length = length($values{$title}); $display .= $desc{$title}.': '.('*' x $length); } elsif ($title eq 'version') { if ($values{$title} eq 'LTI-1p0') { $display .= $desc{$title}.': 1.1, '; } } else { $display .= $desc{$title}.': '.$values{$title}.', '; } } $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.$itemid.'', "'$display'")).'
  • '; } elsif (ref($oldlinkprot{$itemid}) eq 'HASH') { my $oldname = $oldlinkprot{$itemid}{'name'}; $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',''."$itemid ($oldname)".'')).'
  • '; } } } else { $output .= '
  • '. ''. &mt('An error occurred when saving changes to link protection settings, which remain unchanged.'). ''. '
  • '; } } else { if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') { my @settings = @{$prefs->{$item}->{'ordered'}}; if ($item eq 'feedback') { push(@settings,(map { $_.'.text'; } @settings)); } foreach my $key (@settings) { if ($key eq 'rolenames') { my $displayname = $prefs->{$item}->{'itemtext'}{$key}; my $msg; my @roles; if ($crstype eq 'Community') { @roles = ('co'); } else { @roles = ('cc'); } push(@roles,('in','ta','ep','ad','st')); foreach my $role (@roles) { next if (!exists($changes->{$item}{$key.'_'.$role})); my $stdname = &Apache::lonnet::plaintext($role,$crstype,undef,1); my $newname = $changes->{$item}{$key.'_'.$role}; $storehash{$role.'.plaintext'} = $newname; if ($newname eq '') { $newname = $stdname; } $msg .= '
  • '.&mt('[_1] set to [_2]',''.$stdname.'', "'".$newname."'").'
  • '; } if ($msg ne '') { $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt($displayname)).'
      '.$msg.'
  • '; } } else { next if (!exists($changes->{$item}{$key})); my ($displayname,$text); $text = $prefs->{$item}->{'itemtext'}{$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}; $displayname = &mt('Custom text for '.$text.' questions'); } else { $displayname = &mt('Recipients of '.$text.' questions'); } } elsif ($item eq 'discussion') { if ($key =~ /^p(lc|ch)\.roles\.denied/) { $displayname = &mt("$text (role-based)"); if ($displayval ne '') { my @roles = split(',',$displayval); @roles = map { &Apache::lonnet::plaintext($_); } @roles; $displayval = join(', ',@roles); } } elsif ($key =~ /^p(lc|ch)\.users\.denied/) { $displayname = &mt("$text (specific user(s))"); } else { if ($key eq 'allow_discussion_post_editing') { if ($displayval ne '') { my @roles = split(',',$displayval); my @longroles; foreach my $role (@roles) { my ($trole,$sec) = split(':',$role); my $rolename = &Apache::lonnet::plaintext($trole); if ($sec ne '') { $rolename .= ':'.$sec; } push(@longroles,$rolename); } $displayval = join(', ',@longroles); } } 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); } } elsif ($item eq 'spreadsheet') { if ($key =~ /^spreadsheet_default_(studentcalc|assesscalc)$/x) { my $sheettype = $1; if ($sheettype eq 'studentcalc') { &Apache::lonnet::expirespread('','','studentcalc'); } else { &Apache::lonnet::expirespread('','','assesscalc'); &Apache::lonnet::expirespread('','','studentcalc'); } } $displayname = &mt($text); } 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); } elsif ($item eq 'menuitems') { unless ($changes->{$item}{$key} eq '') { if ($key eq 'menudefault') { $displayname = &mt('Default collection of menu items'); $displayval = &mt('Collection: [_1]', $changes->{$item}{$key}); } elsif ($key eq 'menucollections') { $displayval = &menucollections_display($changes->{$item}{$key}); } } } else { $displayname = &mt($text); } if (defined($yesno{$key})) { $displayval = &mt('No'); if ($changes->{$item}{$key} eq 'yes') { $displayval = &mt('Yes'); } } elsif (($key =~ /^default_enrollment_(start|end)_date$/) && ($displayval)) { $displayval = &Apache::lonlocal::locallocaltime($displayval); } elsif ($key eq 'categories') { $displayval = $env{'form.categories_display'}; } elsif (($key eq 'canuse_pdfforms') || ($key eq 'usejsme') || ($key eq 'uselcmath') || ($key eq 'inline_chem')) { if ($changes->{$item}{$key} eq '1') { $displayval = &mt('Yes'); } elsif ($changes->{$item}{$key} eq '0') { $displayval = &mt('No'); } } if ($key eq 'co-owners') { if (ref($changes->{$item}{$key}) eq 'HASH') { if (ref($changes->{$item}{$key}{'changed'}) eq 'ARRAY') { foreach my $type ('co-owners','pendingco-owners') { next unless (grep(/^\Q$type\E$/,@{$changes->{$item}{$key}{'changed'}})); if ($type eq 'pendingco-owners') { if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { $displayname = &mt('Invited as co-owners, pending acceptance'); } } if ($changes->{$item}{$key}{$type} eq '') { push(@delkeys,'internal.'.$type); if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { $output .= '
  • '.&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_coowner'} eq 'accept') { $displayval = &mt('on'); } elsif ($env{'form.pending_coowner'} eq 'decline') { $displayval = ''; $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Invitation to be co-owner declined')).'
  • '; } elsif ($env{'form.remove_coowner'}) { $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); 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"').'
  • '; } } elsif ($item eq 'menuitems') { if ($key eq 'menudefault') { $output .= '
  • '.&mt("Default collection of menu items set to: 'Standard' (all menus shown)").'
  • '; } elsif ($key eq 'menucollections') { $output .= '
  • '.&mt('Specific collections of menus no longer available').'
  • '; } } else { $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', ''.$displayname.'')).'
  • '; } } elsif ($key eq 'menucollections') { $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Numbered menu collections:')).'
    '. $displayval.'
  • '; } else { $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', ''.$displayname.'', "'$displayval'")); if ($key eq 'url') { my $bkuptime=time; $output .= (' 'x2).&mt('(Previous URL backed up)').': '. $storehash{'top level map backup '.$bkuptime} = $values->{$key}; } $output .= '
  • '; } 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 'co-owners') || ($key eq 'lti.override') || ($key eq 'lti.topmenu') || ($key eq 'lti.inlinemenu') || ($key eq 'lti.lcmenu')) { push(@need_env_update,$key); } } } } $output .= '
'; } else { if ($crstype eq 'Community') { $output .= &mt('No changes made to community settings.'); } else { $output .= &mt('No changes made to course settings.'); } } } } } if ($skipstore) { return $output; } 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 .= '
'; if ($crstype eq 'Community') { $output .= &mt('An error occurred when removing community settings which are no longer in use.'); } else { $output .= &mt('An error occurred when removing course settings which are no longer in use.'); } $output .= ''; } else { foreach my $key (@delkeys) { &Apache::lonnet::delenv('course.'.$cdom.'_'.$cnum.'.'.$key); } } } if (@need_env_update) { $chome = &Apache::lonnet::homeserver($cnum,$cdom); &update_env($cnum,$cdom,$chome,\@need_env_update,\%storehash); } &Apache::lonnet::coursedescription($env{'request.course.id'}, {'freshen_cache' => 1}); } else { $output = ''; if ($crstype eq 'Community') { $output .= &mt('An error occurred when saving changes to community settings, which remain unchanged.'); } else { $output .= &mt('An error occurred when saving changes to course settings, which remain unchanged.'); } $output .= ''; } return $output; } sub update_env { my ($cnum,$cdom,$chome,$need_env_update,$storehash) = @_; my $count = 0; if ((ref($need_env_update) eq 'ARRAY') && (ref($storehash) eq 'HASH')) { my %crsinfo = &Apache::lonnet::courseiddump($cdom,'.',1,'.','.',$cnum,undef,undef,'.'); if (ref($crsinfo{$env{'request.course.id'}}) eq 'HASH') { foreach my $key (@{$need_env_update}) { if ($key eq 'description' && defined($storehash->{$key})) { &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.description' => $storehash->{$key}}); $crsinfo{$env{'request.course.id'}}{'description'} = $storehash->{$key}; $count ++; } elsif (($key eq 'cloners') || ($key eq 'hidefromcat') || ($key eq 'categories')) { &Apache::lonnet::appenv({'course.'.$env{'request.course.id'}.'.'.$key => $storehash->{$key}}); $crsinfo{$env{'request.course.id'}}{$key} = $storehash->{$key}; $count ++; } 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) { my $putresult = &Apache::lonnet::courseidput($cdom,\%crsinfo,$chome,'notime'); } } } return; } sub display_disallowed { my ($item,$disallowed,$prefs,$crstype) = @_; my $output; if ((ref($disallowed) eq 'HASH') && (ref($prefs) eq 'HASH')) { if (keys(%{$disallowed})) { if ($item eq 'cloners') { my @fails; my %lt = &Apache::lonlocal::texthash ( format => 'Invalid format', domain => 'Domain does not exist', newuser => 'LON-CAPA user(s) do(es) not exist.', ); foreach my $error ('format','domain','newuser') { if (defined($disallowed->{$error})) { my $msg = ''.$disallowed->{$error}.', '.&mt('reason').' - '. $lt{$error}; if ($error eq 'newuser') { $msg .= '
'.&mt("Please [_1]add the user(s)[_2] before returning to the [_3]$crstype Configuration[_2] to add as potential cloners.",'','',''); } push(@fails,$msg); } } if (@fails) { $output .= ''.&mt('Unable to add to allowed cloners: '). ''.join(';  ',@fails).'.
'; } } elsif ($item eq 'rolenames') { my %lt = &Apache::lonlocal::texthash ( replacements => 'Name already used to replace a different standard role name', regulars => 'Name already used as a standard role name', customrole => 'Name already used as the name of a custom role', ); my @fails; foreach my $error ('replacements','regulars','customrole') { if (ref($disallowed->{$error}) eq 'ARRAY') { push(@fails,''.join(', ',@{$disallowed->{$error}}). ', '.&mt('reason').' - '.$lt{'error'}); } } if (@fails) { $output .= ''. &mt('Unable to include amongst replacements for role names: '). ''.join(';  ',@fails).'.
'; } } elsif (($item eq 'feedback') || ($item eq 'discussion') || ($item eq 'localization')) { $output .= ''; if ($item eq 'feedback') { if ($crstype eq 'Community') { $output .= &mt('Unable to include as a recipient of community feedback for:'); } else { $output .= &mt('Unable to include as a recipient of course feedback for:'); } } elsif ($item eq 'discussion') { $output .= &mt('Unable to include in user-based access control for:'); } elsif ($item eq 'localization') { if ($crstype eq 'Community') { $output .= &mt('Unable to include in community localization:'); } else { $output .= &mt('Unable to include in course localization:'); } } $output .= '
    '; foreach my $key (sort(keys(%{$disallowed}))) { my $itemtext = $prefs->{$item}{'itemtext'}{$key}; $output .= '
  • '.$itemtext.' - '; if ($item eq 'localization') { $output .= &mt('reason - unsupported language: [_1]', ''.$disallowed->{$key}.''); } else { $output .= &mt('reason - invalid user: [_1]', ''.$disallowed->{$key}.'').'
  • '; } } $output .= '

'; } } } return $output; } sub get_course { my ($courseid) = @_; if (!defined($courseid)) { $courseid = $env{'request.course.id'}; } my $cdom=$env{'course.'.$courseid.'.domain'}; my $cnum=$env{'course.'.$courseid.'.num'}; my $chome=$env{'course.'.$courseid.'.home'}; return ($cnum,$cdom,$chome); } sub get_jscript { my ($cid,$cdom,$phase,$crstype,$settings,$noedit) = @_; my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype); 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 .= <{'menucollections'} ne '') { my @current; foreach my $item (split(/;/,$settings->{'menucollections'})) { my ($num) = split(/\%/,$item); if ($num =~ /^\d+$/) { push(@current,$num); } } $collections = join("','",sort { $a <=> $b } @current); if ($collections) { $collections = "'$collections'"; } $next += $current[-1]; } } my $deftext = &mt('Standard (all menus shown)'); $menuitems_js = <'."\n". ''."\n".$stubrowse_js."\n"; return $jscript; } sub cloners_javascript { my ($formname) = @_; return <<"ENDSCRIPT"; function update_cloners(caller,num) { var delidx = getIndexByName('cloners_delete'); var actidx = getIndexByName('cloners_activate'); if (caller == 'cloners_all') { var selall; for (var i=0; i{'categories'},$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') { $replace = &mt('To replace the standard title for a course role, enter a title, otherwise leave blank'); } 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'}).''.$editmap, input => 'textbox', size => '55', advanced => 1 }, 'description' => { text => ''.&mt($itemtext->{'description'}).'', input => 'textbox', size => '55', }, 'owner' => { text => ''.&mt($itemtext->{'owner'}).'', }, 'co-owners' => { text => ''.&mt($itemtext->{'co-owners'}).'', }, 'clonedfrom' => { text => ''.&mt($itemtext->{'clonedfrom'}).'', }, 'courseid' => { text => ''.&mt($itemtext->{'courseid'}).'
'.'('. &mt('internal, optional').')', input => 'textbox', size => '25', }, 'uniquecode' => { text => ''.&mt($itemtext->{'uniquecode'}).'', }, 'cloners' => { text => ''.&mt($itemtext->{'cloners'}).'
'. &mt('Owner and Coordinators included automatically'). $clonedefaults, input => 'textbox', size => '40' }, 'rolenames' => { text => ''.&mt($itemtext->{'rolenames'}).'
'. '('.$replace.')', input => 'textbox', size => '20', advanced => 1 }, 'syllabus' => { text => ''.&mt($itemtext->{'syllabus'}).'
'. &mt('(Syllabus type in use)').(' ' x2). $editsyllabus, }, 'hidefromcat' => { text => ''.&mt($itemtext->{'hidefromcat'}).'
'. ' ('.&mt('included by default if assigned institutional code, or categorized').')', input => 'radio', }, 'categories' => { text => ''.&mt($itemtext->{'categories'}).' '. &mt('Display Categories').'', input => 'textbox', size => '25', }, '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",$colspan); } else { $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); } if ($items{$item}{input} eq 'radio') { $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(). &Apache::loncommon::start_data_table_row(). ''. (' 'x2).'
'.&mt('Or'). '
'. &Apache::loncommon::start_data_table(); my @cloners; if ($settings->{$item} eq '') { 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('Any user in domain:').' '.$udom. '
'. ''. &Apache::loncommon::end_data_table_row(); $num ++; } elsif (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { unless (grep(/^\Q$entry\E$/,@cloners)) { push(@cloners,$entry); } } } } } my $add_domtitle = &mt('Any user in additional domain:'); if ($settings->{$item} eq '*') { $add_domtitle = &mt('Any user in specific domain:'); } elsif ($settings->{$item} eq '') { $add_domtitle = &mt('Any user in other domain:'); } my $cloners_str = join(',',@cloners); $datatable .= &Apache::loncommon::start_data_table_row(). ''. $add_domtitle.'
'. &Apache::loncommon::select_dom_form('','cloners_newdom', $includeempty,undef,undef, undef,undef,$noedit). ''. ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). '
'.&mt('And'). '
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''. &mt('Specific users').' ('. &mt('user:domain,user:domain').')
'. &Apache::lonhtmlcommon::textbox($item,$cloners_str, $items{$item}{'size'},$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(); my @roles; if ($crstype eq 'Community') { @roles = ('co'); } else { @roles = ('cc'); } push (@roles,('in','ta','ep','ad','st')); foreach my $role (@roles) { $datatable .= &Apache::loncommon::start_data_table_row(). ''. &Apache::lonnet::plaintext($role,$crstype,undef,1). ''. &Apache::lonhtmlcommon::textbox('rolenames_'.$role, $settings->{$role.'.plaintext'}, $items{$item}{size},$disabled).''. &Apache::loncommon::end_data_table_row(); } $datatable .= &Apache::loncommon::end_data_table().''; } elsif ($item eq 'categories') { 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 'syllabus') { 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},$disabled); } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub new_cloners_dom_row { 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). ''. &Apache::loncommon::end_data_table_row(); } return $output; } sub can_modify_catsettings { my ($dom,$crstype) = @_; my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$dom); my ($can_toggle_cat,$can_categorize); if (ref($domconf{'coursecategories'}) eq 'HASH') { if ($crstype eq 'Community') { if ($domconf{'coursecategories'}{'togglecatscomm'} eq 'comm') { $can_toggle_cat = 1; } if ($domconf{'coursecategories'}{'categorizecomm'} eq 'comm') { $can_categorize = 1; } } else { if ($domconf{'coursecategories'}{'togglecats'} eq 'crs') { $can_toggle_cat = 1; } if ($domconf{'coursecategories'}{'categorize'} eq 'crs') { $can_categorize = 1; } } } return ($can_toggle_cat,$can_categorize); } sub assign_course_categories { my ($r,$crstype) = @_; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $hascats = 0; my $cathash; my %domconf = &Apache::lonnet::get_dom('configuration',['coursecategories'],$cdom); if (ref($domconf{'coursecategories'}) eq 'HASH') { $cathash = $domconf{'coursecategories'}{'cats'}; if (ref($cathash) eq 'HASH') { foreach my $cat (keys(%{$cathash})) { next if ($cat eq 'instcode::0'); unless ($crstype eq 'Community') { next if ($cat eq 'communities::0'); } $hascats ++; } } } my $catwin_js; if ($hascats) { my $alert; if ($crstype eq 'Community') { $alert = &mt("Use 'Save' in the main window to save community categories"); } else { $alert = &mt("Use 'Save' in the main window to save course categories"); } &js_escape(\$alert); $catwin_js = < function updateCategories() { var newcategories = ''; var unescapedcats = ''; if (document.chgcats.usecategory.length) { for (var i=0; i 0) { newcategories = newcategories.slice(0,-1); } if (unescapedcats.length > 0) { unescapedcats = unescapedcats.slice(0,-3); } } else { if (document.chgcats.usecategory.checked == true) { newcategories = document.chgcats.usecategory.value; unescapedcats = document.chgcats.catname.value; } } opener.document.display.categories.value = newcategories; opener.document.display.categories_display.value = unescapedcats; alert("$alert"); self.close(); return; } ENDSCRIPT } else { my $onload; } my ($crscat,$catcrs,$assign); if ($crstype eq 'Community') { $crscat = 'Community Categories'; $catcrs = &mt('Categorize Community'); $assign = &mt('Assign one or more categories to this community.') } else { $crscat = 'Course Categories'; $catcrs = &mt('Categorize Course'); $assign = &mt('Assign one or more categories to this course.') } my $start_page = &Apache::loncommon::start_page($crscat,$catwin_js, {'only_body' => 1,}); my $end_page = &Apache::loncommon::end_page(); my $categoriesform = '

'.$catcrs.'

'; if ($hascats) { my %currsettings = &Apache::lonnet::get('environment',['hidefromcat','categories'],$cdom,$cnum); my $cattable = &Apache::loncommon::assign_categories_table($cathash, $currsettings{'categories'},$crstype); if ($cattable eq '') { $categoriesform .= &mt('No suitable categories defined for this course type in this domain.'); } else { $categoriesform .= $assign.'

'. '
'."\n". $cattable."\n". '

'; } } else { $categoriesform .= &mt('No categories defined in this domain.'); } $r->print($start_page.$categoriesform.$end_page); 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,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( languages => { text => ''.&mt($itemtext->{'languages'}).'
'. &mt("(overrides individual user preference)"), input => 'selectbox', }, timezone => { text => ''.&mt($itemtext->{'timezone'}).'', input => 'selectbox', }, datelocale => { text => ''.&mt($itemtext->{'datelocale'}).'', input => 'selectbox', }, ); my ($datatable,$disabled); my $count = 0; if ($noedit) { $disabled = ' disabled="disabled"'; } foreach my $item (@{$ordered}) { $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,$disabled); } elsif ($item eq 'datelocale') { my $includeempty = 1; my $locale_obj = &Apache::lonlocal::getdatelocale(); my $currdatelocale; if (ref($locale_obj)) { $currdatelocale = $locale_obj->id(); } $datatable .= &Apache::loncommon::select_datelocale($item,$currdatelocale, undef,$includeempty,$disabled); } else { if ($settings->{$item} eq '') { 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(); if (@languages > 0) { my %langchoices = &get_lang_choices(); foreach my $lang (@languages) { my $showlang = $lang; if (exists($langchoices{$lang})) { $showlang = $langchoices{$lang}; } $datatable .= &Apache::loncommon::start_data_table_row(). ''. &mt('Language:').' '.$showlang. '
'. ''. &Apache::loncommon::end_data_table_row(); $num ++; } } 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(); } $datatable .= &Apache::loncommon::end_data_table().'
'; } } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub get_lang_choices { my %langchoices; foreach my $id (&Apache::loncommon::languageids()) { my $code = &Apache::loncommon::supportedlanguagecode($id); if ($code) { $langchoices{$code} = &Apache::loncommon::plainlanguagedescription($id); } } return %langchoices; } sub print_feedback { my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'question.email' => { text => ''.&mt($itemtext->{'question.email'}).'', input => 'textbox', size => '50', }, 'comment.email' => { text => ''.&mt($itemtext->{'comment.email'}).'', input => 'textbox', size => '50', }, 'policy.email' => { text => ''.&mt($itemtext->{'policy.email'}).'', input => 'textbox', size => '50', }, ); my $datatable; my $count = 0; my ($cnum) = &get_course(); my %sections = &Apache::loncommon::get_sections($cdom,$cnum); my @sections = sort( { $a <=> $b } keys(%sections)); my %lt = &Apache::lonlocal::texthash ( currone => 'Current recipient:', currmult => 'Current recipients:', add => 'Additional recipient:', 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",2); } if ($position eq 'top') { my $includeempty = 0; $datatable .= ''. &user_table($cdom,$item,\@sections, $settings->{$item},\%lt,$noedit); } else { $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text', $settings->{$item.'.text'},$items{$item}{size},$disabled); } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub user_table { my ($cdom,$item,$sections,$currvalue,$lt,$noedit) = @_; my $output; if ($currvalue eq '') { unless ($noedit) { $output .= &select_recipient($item,'0',$cdom,$sections); } } else { my $num = 0; my @curr = split(/,/,$currvalue); $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)(\(?[^\)]*\)?)$/); my @selsec; if ($seclist) { $seclist =~ s/(^\(|\)$)//g; @selsec = split(/\s*;\s*/,$seclist); } $currusers .= ''. ''; $num ++; } if ($num) { $output .= ''. ''. ''; } unless ($noedit) { $output .= ''. ''; } $output .= '
'. ''. ''.(' 'x2). &Apache::loncommon::aboutmewrapper( &Apache::loncommon::plainname($uname,$udom,'firstname'), $uname,$udom,'aboutuser'); if (ref($sections) eq 'ARRAY') { if (@{$sections}) { $currusers.= (' 'x3).$lt->{'sec'}.' '. &select_sections($item,$num,$sections, \@selsec,$noedit); } } $currusers .= '
'; if ($num == 1) { $output .= $lt->{'currone'}; } else { $output .= $lt->{'currmult'}; } $output .= '
'. ''.$currusers.'
'. $lt->{'add'}.'
'. &select_recipient($item,$num,$cdom,$sections). ''. '
'; } return $output; } sub select_recipient { my ($item,$num,$cdom,$sections,$selected,$includeempty) = @_; my $domform = &Apache::loncommon::select_dom_form($cdom,$item.'_udom_'.$num,$includeempty); my $selectlink = &Apache::loncommon::selectstudent_link('display',$item.'_uname_'.$num, $item.'_udom_'.$num,'only'); my $output = ''. ''; if (ref($sections) eq 'ARRAY') { if (@{$sections}) { $output .= ''; } } $output .= '
'.&mt('Username').'
'. '
'.&mt('Domain').'
'.$domform.'
'.&mt('Sections').'
'. &select_sections($item,$num,$sections,$selected).'
'. $selectlink.'
'; return $output; } sub select_sections { my ($item,$num,$sections,$selected,$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; if (@{$sections} > 1) { $mult = ' multiple="multiple"'; if (@{$sections} > 3) { $mult .= ' size="4"'; } } $output = ''; } } return $output; } sub print_discussion { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'plc.roles.denied' => { text => ''.&mt($itemtext->{'plc.roles.denied'}).''. &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'
'. &mt('(role-based)'), input => 'checkbox', }, 'plc.users.denied' => { text => ''.&mt($itemtext->{'plc.users.denied'}).'
'. &mt('(specific user(s))'), input => 'checkbox', }, 'pch.roles.denied' => { text => ''.&mt($itemtext->{'pch.roles.denied'}).''. &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'
'. &mt('(role-based)'), input => 'checkbox', }, 'pch.users.denied' => { text => ''.&mt($itemtext->{'pch.users.denied'}).'
'. &mt('(specific user(s))'), input => 'checkbox', }, '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', }, 'allow_discussion_post_editing' => { 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; my ($cnum) = &get_course(); my %sections = &Apache::loncommon::get_sections($cdom,$cnum); my @sections = sort( { $a <=> $b } keys(%sections)); my %lt = &Apache::lonlocal::texthash ( currone => 'Disallowed:', currmult => 'Disallowed:', add => 'Disallow more:', del => 'Delete?', sec => 'Sections:', ); foreach my $item (@{$ordered}) { $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,undef,undef,$noedit). '
'; } elsif ($item eq 'plc.users.denied') { $datatable .= ''. &user_table($cdom,$item,undef, $settings->{$item},\%lt,$noedit); } elsif ($item eq 'pch.roles.denied') { $datatable .= ''. ''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). '
'; } elsif ($item eq 'pch.users.denied') { $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,undef,undef,undef,$noedit); } elsif ($item eq 'allow_discussion_post_editing') { $datatable .= '
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''.&mt('Role').''. &mt('Sections').''. &Apache::loncommon::end_data_table_row(). &role_checkboxes($cdom,$cnum,$item,$settings,1,undef,$noedit). &Apache::loncommon::end_data_table().'
'; } elsif ($item eq 'discussion_post_fonts') { $datatable .= '
'. &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').''. &Apache::loncommon::end_data_table_row(). &set_discussion_fonts($cdom,$cnum,$item,$settings,$noedit). &Apache::loncommon::end_data_table().'
'; } $datatable .= &item_table_row_end(); } $$rowtotal += scalar(@{$ordered}); return $datatable; } sub role_checkboxes { my ($cdom,$cnum,$item,$settings,$showsections,$crstype,$noedit) = @_; my @roles = ('st','ad','ta','ep','in'); if ($crstype eq 'Community') { push(@roles,'co'); } else { push(@roles,'cc'); } my $output; my (@current,@curr_roles,%currsec,@sections); if ($showsections) { my %sections = &Apache::loncommon::get_sections($cdom,$cnum); @sections = sort( { $a <=> $b } keys(%sections)); } if (ref($settings) eq 'HASH') { if ($settings->{$item}) { @current = split(',',$settings->{$item}); if ($showsections) { foreach my $role (@current) { if ($role =~ /:/) { my ($trole,$sec) = split(':',$role); push(@curr_roles,$trole); if (ref($currsec{$trole}) eq 'ARRAY') { if (!grep(/^\Q$sec\E/,@{$currsec{$trole}})) { push(@{$currsec{$trole}},$sec); } } else { $currsec{$trole} = [$sec]; } } else { push(@curr_roles,$role); } } @current = @curr_roles; } } } my $numinrow = 3; my $count = 0; my $disabled; if ($noedit) { $disabled = ' disabled="disabled"'; } foreach my $role (@roles) { my $checked = ''; if (grep(/^\Q$role\E$/,@current)) { $checked = ' checked="checked" '; } my $plrole=&Apache::lonnet::plaintext($role,$crstype); if ($showsections) { $output .= &Apache::loncommon::start_data_table_row(); } else { my $rem = $count%($numinrow); if ($rem == 0) { if ($count > 0) { $output .= ''; } $output .= ''; } } $output .= ''; if ($showsections) { $output .= ''. &select_sections($item,$role,\@sections,$currsec{$role},$noedit). ''; } $count ++; } my %adv_roles = &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1); my $total = @roles; foreach my $role (sort(keys(%adv_roles))) { if ($role =~ m{^cr/($match_domain)/($match_name)/\w$}) { my $rolename = $3; my $value = 'cr_'.$1.'_'.$2.'_'.$rolename; my $checked = ''; if (grep(/^\Q$value\E$/,@current)) { $checked = ' checked="checked" '; } if ($showsections) { $output .= &Apache::loncommon::start_data_table_row(); } else { my $rem = $count%($numinrow); if ($rem == 0) { if ($count > 0) { $output .= ''; } $output .= ''; } } $output .= ''; if ($showsections) { $output .= ''. &select_sections($item,$role,\@sections,$currsec{$role},$noedit). ''.&Apache::loncommon::end_data_table_row(); } $total ++; $count ++; } } if (!$showsections) { my $rem = $total%($numinrow); my $colsleft = $numinrow - $rem; if ($colsleft > 1 ) { $output .= ''. ' '; } elsif ($colsleft == 1) { $output .= ' '; } $output .= ''; } return $output; } sub 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(). ''.$classtitles->{$cat}.''; if (ref($styleorder) eq 'ARRAY') { foreach my $item (@{$styleorder}) { $output .= ''; 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 .= ''; } $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,$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','checkforpriv'); } else { @ordered = ('student_classlist_view', 'student_classlist_opt_in', 'student_classlist_portfiles'); } my %lt; if ($crstype eq 'Community') { %lt = &Apache::lonlocal::texthash ( disabled => 'No viewable membership list', section => "Membership of viewer's section", all => 'List of all members', ); } else { %lt = &Apache::lonlocal::texthash ( disabled => 'No viewable classlist', section => "Classlist of viewer's section", all => 'Classlist of all students', ); } my %items = ( 'default_enrollment_start_date' => { text => ''.&mt($itemtext->{'default_enrollment_start_date'}).'', input => 'dates', }, 'default_enrollment_end_date' => { text => ''.&mt($itemtext->{'default_enrollment_end_date'}).'', input => 'dates', }, '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_classlist_opt_in' => { text => ''.&mt($itemtext->{'student_classlist_opt_in'}).'', input => 'radio', }, 'student_classlist_portfiles' => { text => ''.&mt($itemtext->{'student_classlist_portfiles'}).'', input => 'radio', }, ); unless (($settings->{'student_classlist_view'} eq 'all') || ($settings->{'student_classlist_view'} eq 'section')) { $settings->{'student_classlist_view'} = 'disabled'; } return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'classlists',$noedit); } sub print_appearance { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my $mathdef; if ($crstype eq 'Community') { $mathdef = &mt("None specified - use member's choice"); } else { $mathdef = &mt("None specified - use student's choice"); } my %items = ( 'default_xml_style' => { text => ''.&mt($itemtext->{'default_xml_style'}).' '. ''.&mt('Select Style File').'', input => 'textbox', size => 35, }, 'pageseparators' => { text => ''.&mt($itemtext->{'pageseparators'}).'', input => 'radio', }, 'disable_receipt_display' => { text => ''.&mt($itemtext->{'disable_receipt_display'}).'', input => 'radio', }, 'texengine' => { text => ''.&mt($itemtext->{'texengine'}).'', input => 'selectbox', options => { MathJax => 'MathJax', mimetex => &mt('Convert to Images'), tth => &mt('TeX to HTML'), }, order => ['MathJax','mimetex','tth'], nullval => $mathdef, }, 'tthoptions' => { text => ''.&mt($itemtext->{'tthoptions'}).'', input => 'textbox', size => 40, }, 'uselcmath' => { text => ''.&mt($itemtext->{'uselcmath'}).'', input => 'radio', }, 'usejsme' => { text => ''.&mt($itemtext->{'usejsme'}).'', input => 'radio', }, 'inline_chem' => { text => ''.&mt($itemtext->{'inline_chem'}).'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'appearance',$noedit); } sub print_grading { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'grading' => { text => ''.&mt($itemtext->{'grading'}).''. &Apache::loncommon::help_open_topic('GradingOptions'), input => 'selectbox', options => { standard => &mt('Standard: shows points'), 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','categories','external','externalnototals','spreadsheet'], }, 'rndseed' => { text => ''.&mt($itemtext->{'rndseed'}).''. ''.'
'. &mt('Modifying this will make problems have different numbers and answers!'). '
', input => 'selectbox', options => { '32bit' => '32bit', '64bit' => '64bit', '64bit2' => '64bit2', '64bit3' => '64bit3', '64bit4' => '64bit4', '64bit5' => '64bit5', }, order => ['32bit','64bit','64bit2','64bit3','64bit4','64bit5'], advanced => 1 }, 'receiptalg' => { text => ''.&mt($itemtext->{'receiptalg'}).'
'. &mt('This controls how receipt numbers are generated'), input => 'selectbox', options => { receipt => 'receipt', receipt2 => 'receipt2', receipt3 => 'receipt3', }, order => ['receipt','receipt2','receipt3'], advanced => 1 }, 'disablesigfigs' => { text => ''.&mt($itemtext->{'disablesigfigs'}).'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'grading',$noedit); } sub print_printouts { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( problem_stream_switch => { text => ''.&mt($itemtext->{'problem_stream_switch'}).'', input => 'radio', }, suppress_tries => { text => ''.&mt($itemtext->{'suppress_tries'}).'', input => 'radio', }, default_paper_size => { text => ''.&mt($itemtext->{'default_paper_size'}).'', input => 'selectbox', options => { Letter => &mt('Letter').' [8 1/2x11 in]', Legal => &mt('Legal').' [8 1/2x14 in]', Tabloid => &mt('Tabloid').' [11x17 in]', Executive => &mt('Executive').' [7 1/2x10 in]', A2 => &mt('A2').' [420x594 mm]', A3 => &mt('A3').' [297x420 mm]', A4 => &mt('A4').' [210x297 mm]', A5 => &mt('A5').' [148x210 mm]', A6 => &mt('A6').' [105x148 mm]', }, order => ['Letter','Legal','Tabloid','Executive','A2','A3','A4','A5','A6'], nullval => &mt('None specified'), }, print_header_format => { text => ''.&mt($itemtext->{'print_header_format'}).'', input => 'checkbox', }, disableexampointprint => { text => ''.&mt($itemtext->{'disableexampointprint'}).'', input => 'radio', }, canuse_pdfforms => { text => ''.&mt($itemtext->{'canuse_pdfforms'}).'', input => 'selectbox', options => { 1 => &mt('Yes'), 0 => &mt('No'), }, order => ['1','0'], nullval => &mt('None specified - use domain default'), } ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'printouts',$noedit); } sub print_spreadsheet { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my $SelectSpreadsheetFile=&mt('Select Spreadsheet File'); my %items = ( spreadsheet_default_classcalc => { text => ''.&mt($itemtext->{'spreadsheet_default_classcalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, spreadsheet_default_studentcalc => { text => ''.&mt($itemtext->{'spreadsheet_default_studentcalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, spreadsheet_default_assesscalc => { text => ''.&mt($itemtext->{'spreadsheet_default_assesscalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, hideemptyrows => { text => ''.&mt($itemtext->{'hideemptyrows'}).'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'spreadsheet',$noedit); } sub print_bridgetasks { my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my ($stumsg,$msgnote); if ($crstype eq 'Community') { $stumsg = &mt('Send message to member'); $msgnote = &mt('Message to member and add to user notes'); } else { $stumsg = &mt('Send message to student'); $msgnote = &mt('Message to student and add to user notes'); } my %items = ( task_messages => { text => ''.&mt($itemtext->{'task_messages'}).'', input => 'selectbox', options => { only_student => $stumsg, student_and_user_notes_screen => $msgnote, }, order => ['only_student','student_and_user_notes_screen'], nullval => &mt('No message or record in user notes'), }, task_grading => { text => ''.&mt($itemtext->{'task_grading'}).'', input => 'selectbox', options => { any => &mt('Grade BTs in any section'), section => &mt('Grade BTs only in own section') }, order => ['any','section'], }, suppress_embed_prompt => { text => ''.&mt($itemtext->{'suppress_embed_prompt'}).''. ' '.&mt('(applies when current role is student)').'', input => 'radio', }, ); return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$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 = ''; 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_menuitems { my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($itemtext) eq 'HASH')) { return; } if ($position eq 'top') { my (%defaultmenu_options,@defaultmenu_order,$addcollection); if ($settings->{'menucollections'} ne '') { foreach my $item (split(/;/,$settings->{'menucollections'})) { my ($num,$value) = split(/\%/,$item); if ($num =~ /^\d+$/) { $defaultmenu_options{$num} = $num; } } @defaultmenu_order = sort { $a <=> $b } keys(%defaultmenu_options); $addcollection = $defaultmenu_order[-1] + 1; } else { $addcollection = 1; } $defaultmenu_options{$addcollection} = $addcollection; my %items = ( 'menudefault' => { text => ''.&mt($itemtext->{'menudefault'}).'
'. &mt("(can be overriden in deep-link context)"), input => 'selectbox', options => \%defaultmenu_options, order => \@defaultmenu_order, nullval => &mt('Standard (all menus shown)'), }, ); return &make_item_rows($cdom,\%items,['menudefault'],$settings,$rowtotal,$crstype,'menuitems',$noedit); } else { my %menu; my $count = 0; my $next = 1; my ($datatable,$disabled); if ($noedit) { $disabled = ' disabled="disabled"'; } my ($ordered,$cats) = &menuitems_categories(); my @order = @{$ordered}; my %categories = %{$cats}; my %menutitles = &menuitems_titles(); my %menufields = &menuitems_fields(); if ($settings->{'menucollections'} ne '') { foreach my $item (split(/;/,$settings->{'menucollections'})) { my ($num,$value) = split(/\%/,$item); if ($num =~ /^\d+$/) { my @entries = split(/\&/,$value); foreach my $entry (@entries) { my ($name,$fields) = split(/=/,$entry); $menu{$num}{$name} = $fields; } } } if (keys(%menu)) { my @current = sort { $a <=> $b } keys(%menu); $next += $current[-1]; foreach my $num (@current) { my %checked; my $on = ' checked="checked"'; foreach my $key (keys(%{$menu{$num}})) { if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) { if ($menu{$num}{$key} eq 'y') { $checked{$key} = $on; } } else { foreach my $field (split(/,/,$menu{$num}{$key})) { if (exists($menufields{$field})) { $checked{$field} = $on; } } } } if (ref($menu{$num}) eq 'HASH') { $datatable .= &item_table_row_start(''.$num.'',$count,'','','','LC_left_item'); foreach my $category (@order) { if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { $datatable .= '
'.$menutitles{$category}.''."\n"; if ($category eq 'text') { $datatable .= ''.&mt('Header').'
'; } foreach my $field (@{$categories{$category}}) { if ($field eq 'disc') { $datatable .= '
'.&mt('Footer').'
'; } $datatable .= '
'; } $datatable .= '
'; } } $datatable .= &item_table_row_end(); $count ++; } } } } elsif ($noedit) { my $text = &mt('No menu collections defined for this course.'); $datatable .= &item_table_row_start($text,$count); } unless ($noedit) { my $add = ''; $datatable .= &item_table_row_start($add,$count,'','','','LC_left_item'); foreach my $category (@order) { if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { $datatable .= ''; } } $datatable .= &item_table_row_end(); $count ++; } return $datatable; } } sub menuitems_abbreviations { my %briefcats = ( text => 'pt', links => 'p', list => 'ps', inline => 's', ); return %briefcats; } sub menuitems_categories { my @order = ('shown','text','links','list','inline'); my %categories = ( shown => ['top','inline','foot','main'], text => ['name','role','crs','disc','fdbk'], links => ['pers','logo','menu','comm','roles','help','logout'], list => ['about','prefs','port','wish','anno','rss'], inline => ['cont','grades','chat','people','groups','resv','syll','feeds'], ); return (\@order,\%categories); } sub menuitems_titles { return &Apache::lonlocal::texthash ( shown => 'Hierarchy', text => 'Text', links => 'Header links', list => 'Drop-down list', inline => 'Inline links', ); } sub menuitems_fields { return &Apache::lonlocal::texthash ( top => 'Display header', inline => 'Display inline menu', foot => 'Display footer', main => 'Access to main menu', pers => 'Personal', logo => 'LON-CAPA', menu => 'Home', comm => 'Messages', roles => 'Roles/Courses', help => 'Help', logout => 'Logout', name => 'Fullname', crs => 'Course Title', role => 'Current Role', disc => 'Discussion', fdbk => 'Feedback', about => 'Information', prefs => 'Preferences', port => 'Portfolio', wish => 'Stored Links', anno => 'Calendar', rss => 'RSS Feeds', cont => 'Contents', grades => 'Grades', chat => 'Chat', people => 'People', groups => 'Groups', resv => 'Reservations', syll => 'Syllabus', feeds => 'Feeds', ); } sub menucollections_display { my ($collections) = @_; my %menu; my ($ordered,$cats) = &menuitems_categories(); my @order = @{$ordered}; my %categories = %{$cats}; my %menutitles = &menuitems_titles(); my %menufields = &menuitems_fields(); foreach my $item (split(/;/,$collections)) { my ($num,$value) = split(/\%/,$item); if ($num =~ /^\d+$/) { my @entries = split(/\&/,$value); foreach my $entry (@entries) { my ($name,$fields) = split(/=/,$entry); $menu{$num}{$name} = $fields; } } } my $output = ''; if (keys(%menu)) { my @current = sort { $a <=> $b } keys(%menu); foreach my $num (@current) { my %checked; foreach my $key (keys(%{$menu{$num}})) { if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) { if ($menu{$num}{$key} eq 'y') { $checked{$key} = 1; } } else { foreach my $field (split(/,/,$menu{$num}{$key})) { if (exists($menufields{$field})) { $checked{$field} = 1; } } } } if (ref($menu{$num}) eq 'HASH') { $output .= '
'.&mt('Collection [_1]',$num).''; foreach my $category (@order) { if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { $output .= '
'. ''.$menutitles{$category}.''."\n"; if ($category eq 'text') { $output .= ''.&mt('Header Text').'

'; } foreach my $field (@{$categories{$category}}) { if ($field eq 'disc') { $output .= '
'.&mt('Footer Text').'

'; } if ($checked{$field}) { $output .= &Apache::lonhtmlcommon::confirm_success($menufields{$field}); } else { $output .= &Apache::lonhtmlcommon::confirm_success($menufields{$field},1); } $output .= '
'; } $output .= '
'; } } $output .= '
'; } } } return $output; } sub print_linkprotection { my ($cdom,$settings,$rowtotal,$crstype,$noedit) = @_; unless (ref($settings) eq 'HASH') { return; } my %linkprotection; my $count = 0; my $next = 1; my ($datatable,$disabled,$css_class); if ($noedit) { $disabled = ' disabled="disabled"'; } my %lt = &linkprot_names(); my $itemcount = 0; if (ref($settings->{'linkprotection'}) eq 'HASH') { if (keys(%{$settings->{'linkprotection'}})) { my @current = sort { $a <=> $b } keys(%{$settings->{'linkprotection'}}); $next += $current[-1]; for (my $i=0; $i<@current; $i++) { my $num = $current[$i]; my %values; if (ref($settings->{'linkprotection'}->{$num}) eq 'HASH') { %values = %{$settings->{'linkprotection'}->{$num}}; } else { next; } my $selected; if (($values{'version'} eq 'LTI-1p0') || ($values{'version'} eq '')) { $selected = ' selected="selected"'; } $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''. ''. ''.$lt{'name'}. ': '. (' 'x2). ''.$lt{'version'}.': '."\n". (' 'x2). ''.$lt{'lifetime'}.':'. '

'. ''.$lt{'key'}. ': '. (' 'x2). ''.$lt{'secret'}.':'. ''. ''. ''. ''; $itemcount ++; } } } $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''."\n". ''."\n". ''.&mt('Add').''."\n". ''. ''.$lt{'name'}. ': '."\n". (' 'x2). ''.$lt{'version'}.': '."\n". (' 'x2). ''.$lt{'lifetime'}.': '."\n". '

'. ''.$lt{'key'}.': '."\n". (' 'x2). ''.$lt{'secret'}.':'. ' '."\n". ''; $$rowtotal ++; return $datatable;; } sub linkprot_names { my %lt = &Apache::lonlocal::texthash( 'version' => 'LTI Version', 'key' => 'Key', 'lifetime' => 'Nonce lifetime (s)', 'name' => 'Launcher Application Name', 'secret' => 'Secret', ); return %lt; } sub print_other { my ($cdom,$settings,$allitems,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } my @ordered = &get_other_items($cdom,$settings,$allitems); my %items; foreach my $parameter (@ordered) { $items{$parameter} = { text => ''.$parameter.'', input => 'textbox', size => '15', }, } push (@ordered,'newp_value'); $items{'newp_value'} = { text => ''.&mt('Create New Environment Variable').'
'. '', input => 'textbox', size => '30', }; return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'other',$noedit); } sub get_other_items { my ($cdom,$settings,$allitems) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } my @ordered; if (ref($settings) eq 'HASH') { foreach my $parameter (sort(keys(%{$settings}))) { next if (grep/^\Q$parameter\E$/,@{$allitems}); next if (($parameter eq 'course.helper.not.run') && (!exists($env{'user.role.dc./'.$env{'request.role.domain'}.'/'}))); unless (($parameter =~ m/^internal\./)||($parameter =~ m/^metadata\./) || ($parameter =~ m/^selfenroll_/) || ($parameter =~ /_selfenroll$/) || ($parameter eq 'type') || ($parameter =~ m/^(cc|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); } } } return @ordered; } sub item_table_row_start { my ($text,$count,$add_class,$colspan,$leftclass,$rightclass) = @_; my $output; my $css_class = ($count % 2) ? 'LC_odd_row' : 'LC_even_row'; $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); if ($leftclass eq '') { $leftclass = 'LC_left_item'; } if ($rightclass eq '') { $rightclass = 'LC_right_item'; } $output .= ''."\n". ''.$text. ''; if ($colspan > 1) { $output .= ''; } else { $output .= ''; } return $output; } sub item_table_row_end { return ''; } sub yesno_radio { 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 $valueyes) { $itemon = $itemoff; $itemoff = ' '; } unless (exists($settings->{$item})) { if ($unsetdefault eq $valueyes) { $itemon = $itemoff; $itemoff = ' '; } } } my $disabled; if ($noedit) { $disabled = ' disabled="disabled"'; } return ' '. ''; } sub select_from_options { my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange,$noedit,$id) = @_; my $output; my $disabled; if ($noedit) { $disabled = ' disabled=disabled"'; } if ((ref($order) eq 'ARRAY') && (ref($options) eq 'HASH')) { $output=''.&mt('Hidden').' '. '
'. ''; } $datatable .= ''; } else { if ($crstype eq 'Community') { $datatable .= &mt('No Domain Coordinators have community roles'); } else { $datatable .= &mt('No Domain Coordinators have course roles'); } } 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. '
'. ''. &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(). ''. &mt('Additional domain:'). '
'. &Apache::loncommon::select_dom_form('','checkforpriv_'.$num,1, 1,undef,undef,\@excdoms,$noedit). ''.&Apache::loncommon::end_data_table_row(); } $datatable .= &Apache::loncommon::end_data_table(). ''. '
'; } return $datatable; } sub print_hdrfmt_row { my ($item,$settings,$noedit) = @_; my @curr; my $currnum = 0; my $maxnum = 2; my $currstr; if ($settings->{$item} ne '') { $currstr .= ''.&mt('Current print header:').' '. $settings->{$item}.'
'; my @current = split(/(%\d*[nca])/,$settings->{$item}); foreach my $val (@current) { unless ($val eq '') { push(@curr,$val); } } $currnum = @curr; $maxnum += $currnum; } my $output = < function reOrder(chgnum) { var maxnum = $maxnum; var oldidx = 'printfmthdr_oldpos_'+chgnum; var newidx = 'printfmthdr_pos_'+chgnum; oldidx = getIndexByName(oldidx); newidx = getIndexByName(newidx); var oldpos = document.display.elements[oldidx].value; var newpos = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value; document.display.elements[oldidx].value = newpos; var chgtype = 'up'; if (newpos < oldpos) { chgtype = 'down'; } for (var j=0; j oldpos) && (currpos <= newpos)) { document.display.elements[newidx].selectedIndex = currsel-1; document.display.elements[oldidx].value = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value; } } else { if ((currpos >= newpos) && (currpos < oldpos)) { document.display.elements[newidx].selectedIndex = currsel+1; document.display.elements[oldidx].value = document.display.elements[newidx].options[document.display.elements[newidx].selectedIndex].value; } } } } return; } function getIndexByName(item) { for (var i=0;i ENDJS $output .= '
'. $currstr.''; my $disabled; if ($noedit) { $disabled = ' disabled="disabled"'; } if (@curr > 0) { for (my $i=0; $i<@curr; $i++) { my $pos = $i+1; $output .= ''. ''; if ($curr[$i] =~ /^%\d*[nca]$/) { my ($limit,$subst) = ($curr[$i] =~ /^%(\d*)([nca])$/); $output .= ''; } else { $output .= ''; } $output .= ''; } } my $pos = $currnum+1; unless ($noedit) { $output .= ''. ''. ''; $pos ++; $currnum ++; $output .= ''. ''. ''. ''; } $output .= '
'. &position_selector($pos,$i,$maxnum,$disabled).&mt('Delete:'). ''. &substitution_selector($i,$subst,$limit,$disabled).''.&mt('Text').'
'. '
'. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''. &substitution_selector($currnum).'
'. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''.&mt('Text').'
'. ''. '

'; return $output; } sub position_selector { my ($pos,$num,$maxnum,$disabled) = @_; my $output = ''; return $output; } sub substitution_selector { my ($num,$subst,$limit,$crstype,$disabled) = @_; my ($stunametxt,$crsidtxt); if ($crstype eq 'Community') { $stunametxt = 'member name'; $crsidtxt = 'community ID', } else { $stunametxt = 'student name'; $crsidtxt = 'course ID', } my %lt = &Apache::lonlocal::texthash( n => $stunametxt, c => $crsidtxt, a => 'assignment note', ); my $output .= &mt('Substitution').'
'. ''.&mt('Size limit').'
'. '
'; 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;