--- loncom/interface/courseprefs.pm 2009/04/26 00:43:14 1.2 +++ loncom/interface/courseprefs.pm 2014/06/09 20:36:56 1.49.2.14 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.2 2009/04/26 00:43:14 raeburn Exp $ +# $Id: courseprefs.pm,v 1.49.2.14 2014/06/09 20:36:56 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -28,6 +28,185 @@ ############################################################### ############################################################## +=pod + +=head1 NAME + +courseprefs- Handler to set/modify course configuration + +=head1 SYNOPSIS + +courseprefs provides an interface for setting general course configuration + +=head1 DESCRIPTION + +This module is used for configuration of a course + +=head1 INTERNAL SUBROUTINES + +=over + +=item get_allitems() + +=item print_config_box() + +=item process_changes() + +=item get_sec_str() + +=item check_clone() + +=item store_changes() + +=item update_env() + +=item display_disallowed() + +=item get_course() + +=item get_jscript() + +=item cloners_javascript() + +=item print_courseinfo() + +=item new_cloners_dom_row() + +=item can_modify_catsettings() + +=item assign_course_categories() + +=item print_localization() + +=item get_lang_choices() + +=item print_feedback() + +=item user_table() + +=item select_recipient() + +=item select_sections() + +=item print_discussion() + +=item role_checkboxes() + +=item print_classlists() + +=item print_appearance() + +=item print_grading() + +=item print_printouts() + +=item print_spreadsheet() + +=item print_bridgetasks() + +=item print_other() + +=item get_other_items() + +=item item_table_row_start() + +=item item_table_row_end() + +=item yes_no_radio() + +=item select_from_options() + +=item make_item_rows() + +Creates table used to display and set course configuration items. + +Inputs: $cdom,$items,$ordered,$settings,$rowtotal,$crstype +where $cdom is course's domain, $items is HASH ref for current config +item, $ordered is ARRAY ref of items to include in row in +display order, $settings is HASH ref of current values forrow, +$rowtotal is SCALAR ref used to accumulate row count, $crstype is +course type. + +Returns: $datatable +HTML mark-up of data table which accumulates individual rows. + +=item nothidepriv_row() + +Creates row containing form elements used to display and set +whether Domain coordinators who are currently included in +advanced course user .db file for a course are to be hidden (e.g., +in syllabus, or from course user lists). + +Inputs: $cdom,$item,$settings,$crstype +where $cdom is course domain, item is nothideprivileged, $settings is +HASH ref of the current values for nothideprivileged, $crstype is +course type (Course or Community). + +Return: $datatable +HTML mark-up for Privileged users (Domain Coordinators) in staff listing. + +=item print_hdrfmt_row() + +Creates row containing form elements used to display and set +substitution items and text to be used in the header included +on printouts. + +Inputs: $item,$settings +where $item is print_header_format, and $settings is a HASH ref +of the current values stored for print_header_format. + +Returns: $output +HTML mark-up containing Javascript functions: reOrder() and getIndexByName() +used to dynamically update position selectboxes, and HTML table elements +for the "Print header format" row. + +=item position_selector() + +Creates a select box which can be used to reorder substitutions +and text included in a printout header. + +Inputs: $pos,$num,$maxnum +where $pos is current position, $num is the unique identifier, +and $maxnum is the total number of items (both substitutions +and text in the printout header. + +Returns: $output +HTML mark-up for the selectbox and a hidden form element containing +the current position. + +=item substitution_selector() + +Creates a combination of select box for choosing an item +(student name, course ID or assignment note) to substitute, +and a corresponding size limit in the header used for printouts. + +Inputs: $num,$subst,$limit,$crstype +where $num is the unique identifier, $subst is the current +substitution (n,c or a, for name, course or note respectively, +$limit is the current size limit (integer), and $crstype is +course type - course or community. + +Returns: $output +HTML mark-up for selectbox and textbox (separate table cells). + +=item change_clone() + +Modifies the list of courses a user can clone (stored +in the user's environment.db file), called when a +change is made to the list of users allowed to clone +a course. + +Inputs: $action,$cloner +where $action is add or drop, and $cloner is identity of +user for whom cloning ability is to be changed in course. + +Returns: nothing + +=back + +=cut + + package Apache::courseprefs; use strict; @@ -36,9 +215,14 @@ use Apache::lonnet; use Apache::loncommon(); use Apache::lonhtmlcommon(); use Apache::lonconfigsettings; +use Apache::lonrelrequtils; +use Apache::lonparmset; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); +my $registered_cleanup; +my $modified_courses; + sub handler { my $r=shift; if ($r->header_only) { @@ -48,7 +232,7 @@ sub handler { } my $context = 'course'; my $cid = $env{'request.course.id'}; - my ($cnum,$cdom) = &get_course($cid); + my ($cnum,$cdom,$chome) = &get_course($cid); my $crstype = &Apache::loncommon::course_type(); my $parm_permission = &Apache::lonnet::allowed('opa',$cid); my $navmap = Apache::lonnavmaps::navmap->new(); @@ -57,23 +241,102 @@ sub handler { $r->send_http_header; } else { if ($navmap) { - $env{'user.error.msg'}= - "/adm/courseprefs:opa:0:0:Cannot modify course settings"; + 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 { - $env{'user.error.msg'}= - "/adm/courseprefs::0:1:Course environment gone, reinitialize the course"; + 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=>"Course Configuration"}); + text=>$lt{'conf'}}); my $breadcrumbs = - &Apache::lonhtmlcommon::breadcrumbs('Edit Course Configuration'); - - &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['phase','actions']); + &Apache::lonhtmlcommon::breadcrumbs($lt{'edit'}); my $phase = 'pickactions'; if ( exists($env{'form.phase'}) ) { @@ -81,10 +344,25 @@ sub handler { } if ($phase eq 'categorizecourse') { - &assign_course_categories($r); + &assign_course_categories($r,$crstype); return OK; } + if ($phase eq 'releaseinfo') { + my $loncaparev = $env{'course.'.$cid.'.internal.releaserequired'}; + if ($loncaparev) { + if (&display_loncaparev_constraints($r,$navmap,$loncaparev,$crstype)) { + push(@{$modified_courses},[$cdom,$cnum,$chome,$crstype]); + unless ($registered_cleanup) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\&update_releasereq,@{$handlers}]); + $registered_cleanup=1; + } + } + return OK; + } + } + my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', @@ -92,215 +370,322 @@ sub handler { my %prefs = ( 'courseinfo' => - { text => 'General course settings', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], - ordered => ['description','courseid','categories', - 'hidefromcat','cloners','externalsyllabus', - 'url','rolenames'], + { text => $lt{'gens'}, + help => 'Course_Prefs_General', + ordered => ['owner','co-owners','loncaparev','description', + 'clonedfrom','courseid','uniquecode','categories', + 'hidefromcat','externalsyllabus','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'}, + 'externalsyllabus' => 'Syllabus status', + 'url' => 'Top Level Map', + 'rolenames' => $lt{'rept'}, + 'loncaparev' => $lt{'lcrv'}, + 'clonedfrom' => 'Cloned from', + }, }, 'localization' => - { text => 'Language/TimeZone/Locale', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], + { 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_Environment', + help => 'Course_Prefs_Feedback', header => [{col1 => 'Questions about:', - col2 => 'Recipients'}, - {col1 => 'Questions about:', - col2 => 'Custom Text'}], - ordered => ['question','comment','policy'], + 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_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], - ordered => ['plc.roles.denied','plc.users.denied', - 'pch.roles.denied','pch.users.denied', + help => 'Course_Prefs_Discussions', + ordered => ['pch.roles.denied','pch.users.denied', + 'plc.roles.denied','plc.users.denied', 'allow_limited_html_in_feedback', - 'allow_discussion_post_editing'], + 'allow_discussion_post_editing', + 'discussion_post_fonts'], + itemtext => { + 'pch.roles.denied' => 'No Resource Discussion', + 'pch.users.denied' => 'No Resource Discussion', + 'plc.roles.denied' => 'No Chat room use', + 'plc.users.denied' => 'No Chat room use', + allow_limited_html_in_feedback => 'Allow limited HTML in discussion', + allow_discussion_post_editing => 'Users can edit/delete own discussion posts', + discussion_post_fonts => 'Discussion post fonts based on likes/unlikes', + }, }, 'classlists' => - { text => 'Classlists and Staff Listing', - help => 'Course_Environment', + { text => $lt{'clas'}, + help => 'Course_Prefs_Classlists', header => [{col1 => 'Type', - col2 => 'Default dates for student access'}, + col2 => $lt{'defd'}}, {col1 => 'Setting', - col2 => 'Privileged users (Domain Coordinators) in staff listing'}, + col2 => $lt{'priv'}}, {col1 => 'Setting', - col2 => 'Student-viewable classlist options'}], + col2 => $lt{'stuv'}}], ordered => ['default_enrollment_start_date', 'default_enrollment_end_date', - 'nothideprivileged','student_classlist_view', - 'student_opt_in','student_classlist_portfiles'], + 'defaultcredits', + 'nothideprivileged','checkforpriv', + 'student_classlist_view', + 'student_classlist_opt_in','student_classlist_portfiles'], + itemtext => { + default_enrollment_start_date => 'Start date', + default_enrollment_end_date => 'End date', + nothideprivileged => $lt{'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_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], + help => 'Course_Prefs_Display', ordered => ['default_xml_style','pageseparators', 'disable_receipt_display','texengine', 'tthoptions'], + itemtext => { + default_xml_style => 'Default XML style file', + pageseparators => 'Visibly Separate Items on Pages', + disable_receipt_display => 'Disable display of problem receipts', + texengine => 'Force use of a specific math rendering engine', + tthoptions => 'Default set of options to pass to tth/m when converting TeX', + }, }, 'grading' => { text => 'Grading', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], + 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_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], + help => 'Course_Prefs_Printouts', ordered => ['problem_stream_switch','suppress_tries', 'default_paper_size','print_header_format', 'disableexampointprint'], + itemtext => { + problem_stream_switch => 'Allow problems to be split over pages', + suppress_tries => 'Suppress number of tries in printing', + default_paper_size => 'Default paper type', + print_header_format => 'Print header format', + disableexampointprint => 'Disable automatically printing point values on bubblesheet exams', + canuse_pdfforms => 'Users can print problems as PDF forms and upload later for grading', + }, }, 'spreadsheet' => { text => 'Spreadsheets', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], + 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_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], + 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', + }, }, 'other' => { text => 'Other settings', - help => 'Course_Environment', + help => 'Course_Prefs_Other', header => [ {col1 => 'Item', col2 => 'Value', }], }, ); if ($phase eq 'process') { + my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context, - \@prefs_order,\%prefs,\%values); + \@prefs_order,\%prefs,\%values, + $cnum,undef,\@allitems,'coursepref'); } elsif ($phase eq 'display') { - my $jscript = &get_jscript($cdom); - 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 { $_.'.email'; } @{$prefs{$item}{'ordered'}})); - } - } - } - } + my $jscript = &get_jscript($cid,$cdom,$phase,$crstype); + my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, - \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems); + \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype,'coursepref'); } else { &Apache::lonconfigsettings::display_choices($r,$phase,$context, - \@prefs_order,\%prefs); + \@prefs_order,\%prefs,'coursepref'); } return OK; } +sub get_allitems { + my (%prefs) = @_; + my @allitems; + foreach my $item (keys(%prefs)) { + if (ref($prefs{$item}) eq 'HASH') { + if (ref($prefs{$item}{'ordered'}) eq 'ARRAY') { + push(@allitems,@{$prefs{$item}{'ordered'}}); + if ($item eq 'feedback') { + push(@allitems,(map { $_.'.text'; } @{$prefs{$item}{'ordered'}})); + } + } + } + } + return @allitems; +} + sub print_config_box { - my ($r,$cdom,$phase,$action,$item,$settings,$allitems) = @_; + my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype) = @_; my $ordered = $item->{'ordered'}; + my $itemtext = $item->{'itemtext'}; my $rowtotal = 0; my $output = ' - '."\n". - ''; + '."\n". + ''; if (($action eq 'feedback') || ($action eq 'classlists')) { $output .= ' - '. &Apache::loncommon::end_data_table_row(); $num ++; - } else { - push(@cloners,$entry); + } elsif (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + unless (grep(/^\Q$entry\E$/,@cloners)) { + push(@cloners,$entry); + } } } } @@ -504,7 +2018,9 @@ sub print_courseinfo { $includeempty). ''. ''.&Apache::loncommon::end_data_table_row(). - &Apache::loncommon::end_data_table().'
'. + &Apache::loncommon::end_data_table(). + '
'. - &mt($item->{text}).' '. - &Apache::loncommon::help_open_topic($item->{'help'}).'
'. + &mt($item->{text}); + if ($item->{'help'}) { + $output .= ' '. + &Apache::loncommon::help_open_topic($item->{'help'}); + } + $output .= '
- - - - - '; +
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).'
'; + 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,\$rowtotal); + $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'classlists') { - $output .= &print_classlists('top',$cdom,$settings,\$rowtotal); + $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''; + } else { + $output .= ' + '; + } + $output .= &mt($item->{'header'}->[0]->{'col2'}).'
+ '; - $output .= ' - + if ($action eq 'classlists') { + $output .= ' + '; if ($action eq 'classlists') { - $output .= &print_classlists('middle',$cdom,$settings,\$rowtotal). + $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal,$crstype). '
'.&mt($item->{'header'}->[1]->{'col1'}).''.&mt($item->{'header'}->[1]->{'col2'}).''; + } else { + $output .= ' + '; + } + $output .= &mt($item->{'header'}->[1]->{'col2'}).'
- - - - - '; +
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
'; + if (exists $item->{'header'}->[2]->{'col1'} || + exists $item->{'header'}->[2]->{'col2'}) { + $output .= ' + + + + '; + } } } else { $output .= ' '. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). - '
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
- - - - - '; +
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'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,\$rowtotal); + $output .= &print_courseinfo($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'localization') { - $output .= &print_localization($cdom,$settings,$ordered,\$rowtotal); + $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'feedback') { - $output .= &print_feedback('bottom',$cdom,$settings,$ordered,\$rowtotal); + $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal); } elsif ($action eq 'discussion') { - $output .= &print_discussion($cdom,$settings,$ordered,\$rowtotal); - } elsif ($action eq 'classlists') { - $output .= &print_classlists('bottom',$cdom,$settings,\$rowtotal); + $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal); + } elsif (($action eq 'classlists') || ($action eq 'viewableroster')) { + $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'appearance') { - $output .= &print_appearance($cdom,$settings,$ordered,\$rowtotal); + $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'grading') { - $output .= &print_grading($cdom,$settings,$ordered,\$rowtotal); + $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'printouts') { - $output .= &print_printouts($cdom,$settings,$ordered,\$rowtotal); + $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'spreadsheet') { - $output .= &print_spreadsheet($cdom,$settings,$ordered,\$rowtotal); + $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'bridgetasks') { - $output .= &print_bridgetasks($cdom,$settings,$ordered,\$rowtotal); + $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype); } elsif ($action eq 'other') { - $output .= &print_other($cdom,$settings,$allitems,\$rowtotal); + $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''; + } else { + $output .= ''; + } + $output .= &mt($item->{'header'}->[0]->{'col2'}).'
@@ -311,12 +696,978 @@ sub print_config_box { } sub process_changes { - my ($r,$cdom,$action,$values) = @_; - my %domconfig; - if (ref($values) eq 'HASH') { - %domconfig = %{$values}; + my ($cdom,$action,$values,$item,$changes,$allitems,$disallowed,$crstype) = @_; + my %newvalues; + if (ref($item) eq 'HASH') { + if (ref($changes) eq 'HASH') { + my @ordered; + if ($action eq 'other') { + @ordered = &get_other_items($cdom,$values,$allitems); + if ($env{'form.newp_name'} ne '') { + my $newp = $env{'form.newp_name'}; + if ($env{'form.newp_value'} ne '') { + if (ref($allitems) eq 'ARRAY') { + unless ((grep(/^\Q$newp\E$/,@ordered)) || + (grep(/^\Q$newp\E$/,@{$allitems}))) { + $changes->{$newp} = $env{'form.newp_value'}; + } + } + } + } + } elsif (ref($item->{'ordered'}) eq 'ARRAY') { + if ($action eq 'courseinfo') { + my ($can_toggle_cat,$can_categorize) = + &can_modify_catsettings($cdom,$crstype); + foreach my $entry (@{$item->{'ordered'}}) { + next if (($entry eq 'hidefromcat') && + (!$can_toggle_cat)); + next if (($entry eq 'categories') && + (!$can_categorize)); + next if (($entry eq 'loncaparev') || + ($entry eq 'owner') || + ($entry eq 'clonedfrom')); + push(@ordered,$entry); + } + } elsif ($action eq 'classlists') { + foreach my $entry (@{$item->{'ordered'}}) { + next if ($entry eq 'defaultcredits'); + push(@ordered,$entry); + } + } else { + @ordered = @{$item->{'ordered'}}; + } + } + if (@ordered > 0) { + if ($action eq 'feedback') { + foreach my $entry (@ordered) { + my $userstr = ''; + my $total = $env{'form.'.$entry.'_total'}; + if ($total) { + my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); + for (my $i=0; $i<$total; $i++) { + unless (grep(/^$i$/,@deletes)) { + $userstr .= $env{'form.'.$entry.'_user_'.$i}. + &get_sec_str($entry,$i).','; + } + } + } else { + $total = 0; + } + if ($env{'form.'.$entry.'_uname_'.$total} ne '') { + my $uname = $env{'form.'.$entry.'_uname_'.$total}; + my $udom = $env{'form.'.$entry.'_udom_'.$total}; + if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { + $userstr =~ s/,$//; + $disallowed->{'feedback'}{$entry} = $uname.':'.$udom; + } else { + $userstr .= $uname.':'.$udom.&get_sec_str($entry,$total); + } + } else { + $userstr =~ s/,$//; + } + $newvalues{$entry} = $userstr; + if ($newvalues{$entry} ne $values->{$entry}) { + $changes->{$entry} = $newvalues{$entry}; + } + my $ext_entry = $entry.'.text'; + $newvalues{$ext_entry} = $env{'form.'.$ext_entry}; + if ($newvalues{$ext_entry} ne $values->{$ext_entry}) { + $changes->{$ext_entry} = $newvalues{$ext_entry}; + } + } + } else { + foreach my $entry (@ordered) { + if ($entry eq 'cloners') { + if ($env{'form.cloners_all'}) { + $newvalues{$entry} = '*'; + } else { + my @clonedoms; + if (exists($env{'form.cloners_activate'})) { + my $actnum = $env{'form.cloners_activate'}; + if ($actnum ne '') { + if ($env{'form.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($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'}; + } + } + unless ($autocoowner) { + my @keepcoowners = &Apache::loncommon::get_env_multiple('form.coowners'); + my @pendingcoowners = &Apache::loncommon::get_env_multiple('form.pendingcoowners'); + my @invitecoowners = &Apache::loncommon::get_env_multiple('form.invitecoowners'); + if (@invitecoowners) { + push(@pendingcoowners,@invitecoowners); + } + $newvalues{'pendingco-owners'} = join(',',sort(@pendingcoowners)); + $newvalues{'co-owners'} = join(',',sort(@keepcoowners)); + if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) { + $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'}; + push(@{$changes->{$entry}{'changed'}},'co-owners'); + } + if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) { + $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'}; + push(@{$changes->{$entry}{'changed'}},'pendingco-owners'); + } + } + } else { + my (@newpending,@newcoown); + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + my $pendingcoowners = $values->{'internal.pendingco-owners'}; + my @pendingcoown = split(',',$pendingcoowners); + if ($env{'form.pending_coowoner'}) { + foreach my $item (@pendingcoown) { + unless ($item eq $uname.':'.$udom) { + push(@newpending,$item); + } + } + @newcoown = @currcoown; + if ($env{'form.pending_coowoner'} eq 'accept') { + unless (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { + push(@newcoown,$uname.':'.$udom); + } + } + } elsif ($env{'form.remove_coowoner'}) { + foreach my $item (@currcoown) { + unless ($item eq $uname.':'.$udom) { + push(@newcoown,$item); + } + } + if ($pendingcoowners ne '') { + @newpending = @pendingcoown; + } + } + $newvalues{'pendingco-owners'} = join(',',sort(@newpending)); + $newvalues{'co-owners'} = join(',',sort(@newcoown)); + if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) { + $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'}; + push(@{$changes->{$entry}{'changed'}},'co-owners'); + } + if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) { + $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'}; + push(@{$changes->{$entry}{'changed'}},'pendingco-owners'); + } + } + } elsif ($entry =~ /^default_enrollment_(start|end)_date$/) { + $newvalues{$entry}=&Apache::lonhtmlcommon::get_date_from_form($entry); + } elsif ($entry eq 'rolenames') { + 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')) { + my @denied = &Apache::loncommon::get_env_multiple('form.'.$entry); + @denied = sort(@denied); + my $deniedstr = ''; + if (@denied > 0) { + $deniedstr = join(',',@denied); + } + $newvalues{$entry} = $deniedstr; + } elsif (($entry eq 'plc.users.denied') || ($entry eq 'pch.users.denied')) { + my $total = $env{'form.'.$entry.'_total'}; + my $userstr = ''; + my @denied; + if ($total > 0) { + my @deletes = + &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); + for (my $i=0; $i<$total; $i++) { + unless (grep(/^$i$/,@deletes)) { + $userstr .= $env{'form.'.$entry.'_user_'.$i}.','; + push(@denied,$env{'form.'.$entry.'_user_'.$i}); + } + } + } else { + $total = 0; + } + if ($env{'form.'.$entry.'_uname_'.$total} ne '') { + my $uname = $env{'form.'.$entry.'_uname_'.$total}; + my $udom = $env{'form.'.$entry.'_udom_'.$total}; + if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { + $userstr =~ s/,$//; + $disallowed->{'discussion'}{$entry} = $uname.':'.$udom; + } else { + my $newuser .= $uname.':'.$udom; + if (grep(/^\Q$newuser\E$/,@denied)) { + $userstr =~ s/,$//; + } else { + $userstr .= $newuser; + } + } + } else { + $userstr =~ s/,$//; + } + $newvalues{$entry} = $userstr; + } elsif ($entry eq 'allow_discussion_post_editing') { + my @canedit = &Apache::loncommon::get_env_multiple('form.'.$entry); + @canedit = sort(@canedit); + foreach my $role (@canedit) { + my @secs = &Apache::loncommon::get_env_multiple('form.'.$entry.'_sections_'.$role); + if ((grep(/^\s*$/,@secs)) || (@secs == 0)) { + $newvalues{$entry} .= $role.','; + } else { + foreach my $sec (@secs) { + $newvalues{$entry} .= $role.':'.$sec.','; + } + } + } + $newvalues{$entry} =~ s/,$//; + } elsif ($entry eq '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; + } 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; +} + +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); + if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) { + %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 %yesno = ( + hidefromcat => '1', + problem_stream_switch => '1', + suppress_tries => '1', + disableexampointprint => '1', + hideemptyrows => '1', + suppress_embed_prompt => '1', + ); + foreach my $item (@{$prefs_order}) { + if (grep(/^\Q$item\E$/,@{$actions})) { + $output .= '

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

'; + if (ref($changes->{$item}) eq 'HASH') { + if (keys(%{$changes->{$item}}) > 0) { + $output .= &mt('Changes made:').'
    '; + if ($item eq 'other') { + foreach my $key (sort(keys(%{$changes->{$item}}))) { + $storehash{$key} = $changes->{$item}{$key}; + if ($changes->{$item}{$key} eq '') { + push(@delkeys,$key); + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]',''.$key.'')).'
  • '; + } else { + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]',''.$key.'', + "'$storehash{$key}'")).'
  • '; + } + } + } else { + if (ref($prefs->{$item}->{'ordered'}) eq 'ARRAY') { + my @settings = @{$prefs->{$item}->{'ordered'}}; + if ($item eq 'feedback') { + push(@settings,(map { $_.'.text'; } @settings)); + } + foreach my $key (@settings) { + if ($key eq 'rolenames') { + my $displayname = $prefs->{$item}->{'itemtext'}{$key}; + my $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); + } 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') { + 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_coowoner'} eq 'accept') { + $displayval = &mt('on'); + } elsif ($env{'form.pending_coowoner'} eq 'decline') { + $displayval = ''; + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Invitation to be co-owner declined')).'
  • '; + } elsif ($env{'form.remove_coowoner'}) { + $displayval = &mt('off'); + } + if ($displayval) { + $displayname = &mt('Your co-ownership status'); + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('[_1] set to [_2]', + ''.$displayname.'', + "'$displayval'")).'
  • '; + } + } + } + } elsif ($changes->{$item}{$key} eq '') { + push(@delkeys,$key); + $output .= '
  • '.&Apache::lonhtmlcommon::confirm_success(&mt('Deleted setting for [_1]', + ''.$displayname.'')).'
  • '; + } 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')) { + 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 (&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 ++; + } + } + 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 &modify_crsenv($action,$cdom,%domconfig); + return $output; } sub get_course { @@ -326,15 +1677,17 @@ sub get_course { } my $cdom=$env{'course.'.$courseid.'.domain'}; my $cnum=$env{'course.'.$courseid.'.num'}; - return ($cnum,$cdom); + my $chome=$env{'course.'.$courseid.'.home'}; + return ($cnum,$cdom,$chome); } sub get_jscript { - my ($cdom) = @_; - my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom); - my ($jscript,$categorize_js); + my ($cid,$cdom,$phase,$crstype) = @_; + my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom,$crstype); + my ($jscript,$categorize_js,$loncaparev_js); my $stubrowse_js = &Apache::loncommon::studentbrowser_javascript(); my $browse_js = &Apache::loncommon::browser_and_searcher_javascript('parmset'); + my $cloners_js = &cloners_javascript($phase); if ($can_categorize) { $categorize_js = <'."\n".$stubrowse_js."\n"; + '// '."\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'})."\n"; + $settings->{'categories'},$crstype)."\n"; } } + if (ref($domconf{'autoenroll'}) eq 'HASH') { + $autocoowner = $domconf{'autoenroll'}{'co-owners'}; + } if (!defined($categoriesform)) { - $categoriesform = &mt('No categories defined for this domain'); + $categoriesform = &mt('No categories defined in this domain.'); } - my ($can_toggle_cat,$can_categorize) = &can_modify_catsettings($cdom); + 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 %items = ( - 'url' => { - text => ''.&mt('Top Level Map').''.(' 'x2). + 'url' => { + text => ''.&mt($itemtext->{'url'}).''.(' 'x2). '
". &mt('Select Map').'
'. &mt('Modification may make assessment data inaccessible!'). '', input => 'textbox', - size => '40', + size => '55', + advanced => 1 }, 'description' => { - text => ''.&mt('Course Description').'', + text => ''.&mt($itemtext->{'description'}).'', input => 'textbox', - size => '25', + size => '55', + }, + 'owner' => { + text => ''.&mt($itemtext->{'owner'}).'', + }, + 'co-owners' => { + text => ''.&mt($itemtext->{'co-owners'}).'', + }, + 'clonedfrom' => { + text => ''.&mt($itemtext->{'clonedfrom'}).'', }, 'courseid' => { - text => ''.&mt('Course ID or number'). - '
'. - '('.&mt('internal, optional').')', + text => ''.&mt($itemtext->{'courseid'}).'
'.'('. + &mt('internal, optional').')', input => 'textbox', size => '25', }, + 'uniquecode' => { + text => ''.&mt($itemtext->{'uniquecode'}).'', + }, 'cloners' => { - text => ''.&mt('Users allowed to clone course').'
'. - &mt('Course Coordinators included automatically'), + text => ''.&mt($itemtext->{'cloners'}).'
'. + &mt('Owner and Coordinators included automatically'), input => 'textbox', - size => '40', + size => '40' }, 'rolenames' => { - text => ''.&mt('Replacement titles for standard course roles').'
'. - '('.&mt('To replace the standard title for a course role, enter a title, otherwise leave blank').')', + text => ''.&mt($itemtext->{'rolenames'}).'
'. + '('.$replace.')', input => 'textbox', size => '20', + advanced => 1 }, 'externalsyllabus' => { - text => ''.&mt('URL of Syllabus').'
('.&mt('not using internal handler)'), - input => 'textbox', - size => '40', + text => ''.&mt($itemtext->{'externalsyllabus'}).'
'. + &mt('(Syllabus type in use)').(' ' x2). + &mt('[_1]Edit[_2]','', + ''), }, 'hidefromcat' => { - text => ''.&mt('Exclude from course catalog').'
'. + text => ''.&mt($itemtext->{'hidefromcat'}).'
'. ' ('.&mt('included by default if assigned institutional code, or categorized').')', input => 'radio', }, 'categories' => { - text => ''.&mt('Categorize course').' '. + 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 ++; - $datatable .= &item_table_row_start($items{$item}{text},$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); } elsif ($item eq 'cloners') { my $includeempty = 1; my $num = 0; - $datatable .= &Apache::loncommon::start_data_table(). + $datatable .= '
'. + &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). '
'.&mt('Or'). - '
'. + '
'.&mt('Or'). + '
'. &Apache::loncommon::start_data_table(); my @cloners; if ($settings->{$item} eq '') { @@ -472,20 +1977,29 @@ sub print_courseinfo { if (@entries > 0) { foreach my $entry (@entries) { my ($uname,$udom) = split(/:/,$entry); + if ($udom =~ /^$match_domain$/) { + unless (&Apache::lonnet::domain($udom)) { + next; + } + } else { + next; + } if ($uname eq '*') { $datatable .= &Apache::loncommon::start_data_table_row(). - '
'. - &mt('Domain:').' '.$udom. + ''. + &mt('Any user in domain:').' '.$udom. '
'. '
'.&mt('And'). + '
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''. @@ -515,8 +2031,16 @@ sub print_courseinfo { ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); } elsif ($item eq 'rolenames') { - $datatable .= &Apache::loncommon::start_data_table(); - foreach my $role ('cc','in','ta','ep','ad','st') { + $datatable .= ''. + &Apache::loncommon::start_data_table(); + 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). @@ -528,7 +2052,95 @@ sub print_courseinfo { } $datatable .= &Apache::loncommon::end_data_table().''; } elsif ($item eq 'categories') { - $datatable .= ''.&Apache::lonhtmlcommon::textbox($item.'_display',$settings->{$item},$items{$item}{size}); + my $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); + } + } else { + if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) { + $datatable .= &show_autocoowners(@currcoown); + } else { + $datatable .= &manage_coownership($cnum,$cdom,@currcoown); + } + } + } elsif ($item eq 'externalsyllabus') { + my $external = $env{'course.'.$env{'request.course.id'}.'.externalsyllabus'}; + my $uploaded = $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}; + my $minimal = $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}; + if (($minimal =~/\w/) || ($uploaded =~/\w/)) { + if ($minimal =~/\w/) { + if ($external =~ m{\Q$minimal\E$}) { + undef($external); + } + } elsif ($uploaded =~/\w/) { + if ($external =~ m{\Q$uploaded\E$}) { + undef($external); + } + } + } elsif ($external!~/\w/) { + undef($external); + } + if ($external) { + $datatable .= &mt('External URL'); + } elsif ($minimal) { + $datatable .= &mt('Minimal template'); + } elsif ($uploaded) { + $datatable .= &mt('Uploaded file'); + } else { + $datatable .= &mt('Standard template'); + } + $datatable .= (' ' x 2). + &mt('[_1]View[_2]', + '', + ''); + } elsif ($item eq 'loncaparev') { + my $loncaparev = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'}; + my $showreqd; + if ($loncaparev) { + $showreqd = &mt('[_1] or newer',$loncaparev).' '. + &mt('Details').''; + } else { + $showreqd = &mt('No specific version required'); + } + $datatable .= $showreqd; } else { $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); } @@ -547,36 +2159,46 @@ sub new_cloners_dom_row { &mt('Any user in domain:').' '.$newdom.''. (' 'x2).''.(' 'x2). ''. + &mt('No').''. &Apache::loncommon::end_data_table_row(); } return $output; } sub can_modify_catsettings { - my ($dom) = @_; + 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 ($domconf{'coursecategories'}{'togglecats'} eq 'crs') { - $can_toggle_cat = 1; - } - if ($domconf{'coursecategories'}{'categorize'} eq 'crs') { - $can_categorize = 1; + 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) = @_; + my ($r,$crstype) = @_; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $hascats = 0; @@ -585,12 +2207,23 @@ sub assign_course_categories { if (ref($domconf{'coursecategories'}) eq 'HASH') { $cathash = $domconf{'coursecategories'}{'cats'}; if (ref($cathash) eq 'HASH') { - $hascats = 1; + 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 = &mt('Use \"Save\" in the main window to save course categories'); + 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"); + } $catwin_js = < @@ -628,44 +2261,755 @@ 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('Course Categories',$catwin_js, + &Apache::loncommon::start_page($crscat,$catwin_js, {'only_body' => 1,}); my $end_page = &Apache::loncommon::end_page(); - my $categoriesform = '

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

'; + my $categoriesform = '

'.$catcrs.'

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

'. + 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". - &Apache::loncommon::assign_categories_table($cathash, - $currsettings{'categories'})."\n". + $cattable."\n". '

'; + } } else { - $categoriesform .= &mt('No categories defined for this domain'); + $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); + @scopeorder = ('all','section/group','user'); + my $resourcedata = &Apache::lonparmset::readdata($cnum,$cdom); + if (ref($resourcedata) eq 'HASH') { + foreach my $key (keys(%{$resourcedata})) { + foreach my $item (keys(%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 = ''; + } + } + my ($middle,$scope,$which,$level,$map,$resource); + if (grep(/^\Q$value\E$/,@{$Apache::lonrelrequtils::checkparms{$item}})) { + my $stdtype = &Apache::lonparmset::standard_parameter_types($item); + my $stdname = &Apache::lonparmset::standard_parameter_names($item); + my $valname = &get_param_description($stdtype,$value); + my $rev = $Apache::lonnet::needsrelease{'parameter:'.$item.':'.$value}; + my $start = $cid.'.'; + if ($key =~ /^\Q$start\E(\[useropt\:($match_username\:$match_domain)\]\.)/) { + $middle = $1; + $which = $2; + $scope = 'user'; + } elsif ($key =~ /^\Q$start\E(\[(\w+)\]\.)/) { + $middle = $1; + $which = $2; + $scope = 'section/group'; + } else { + $scope = 'all'; + } + my $what="$stdname=$valname"; + if ($key =~ /^\Q$start$middle\E\w+\.\Q$item\E$/) { + $level = 'general'; + if ($scope eq 'all') { + if (ref($fromparam{$rev}{$scope}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$fromparam{$rev}{$scope}})) { + push(@{$fromparam{$rev}{$scope}},$what); + } + } else { + push(@{$fromparam{$rev}{$scope}},$what); + } + } else { + if (ref($fromparam{$rev}{$scope}{$which}) eq 'ARRAY') { + unless (grep(/^\Q$what\E$/,@{$fromparam{$rev}{$scope}{$which}})) { + push(@{$fromparam{$rev}{$scope}{$which}},$what); + } + } else { + push(@{$fromparam{$rev}{$scope}{$which}},$what); + } + } + $rowspan{$rev} ++; + } elsif ($key =~ /^\Q$start$middle\E(.+)___\(all\).\w+\.\Q$item\E$/) { + $level = 'folder'; + $map = $1; + if ($scope eq 'all') { + if (ref($bymap{$map}{$rev}{$scope}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$bymap{$map}{$rev}{$scope}})) { + push(@{$bymap{$map}{$rev}{$scope}},$what); + } + } else { + push(@{$bymap{$map}{$rev}{$scope}},$what); + } + } else { + if (ref($bymap{$map}{$rev}{$scope}{$which}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$bymap{$map}{$rev}{$scope}{$which}})) { + push(@{$bymap{$map}{$rev}{$scope}{$which}},$what); + } + } else { + push(@{$bymap{$map}{$rev}{$scope}{$which}},$what); + } + } + } elsif ($key =~ /^\Q$start$middle\E(.+)\.\w+\.\Q$item\E$/) { + $level = 'resource'; + $resource = $1; + if ($scope eq 'all') { + if (ref($byresource{$resource}{$rev}{$scope}) eq 'ARRAY') { + unless(grep(/^\Q$what\E$/,@{$byresource{$resource}{$rev}{$scope}})) { + push(@{$byresource{$resource}{$rev}{$scope}},$what); + } + } else { + push(@{$byresource{$resource}{$rev}{$scope}},$what); + } + } else { + if (ref($byresource{$resource}{$rev}{$scope}{$which}) eq 'ARRAY') { + unless (grep(/^\Q$what\E$/,@{$byresource{$resource}{$rev}{$scope}{$which}})) { + push(@{$byresource{$resource}{$rev}{$scope}{$which}},$what); + } + } else { + push(@{$byresource{$resource}{$rev}{$scope}{$which}},$what); + } + } + } + } + } + } + } + } + if (keys(%fromparam)) { + $output .= '

'.&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 $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() },1,0)) { + my @parts = @{$res->parts()}; + my $symb = $res->symb(); + my $enclosing_map = &Apache::lonnet::declutter($res->enclosing_map_src()); + foreach my $part (@parts) { + if (exists($anonsubms{$symb."\0".$part})) { + my $rev = $rev_anonsurv; + my $what="$stdname=$valanon"; + if (ref($bysubmission{$symb}{$rev}) eq 'ARRAY') { + unless (grep(/^\Q$what\E/,@{$bysubmission{$symb}{$rev}})) { + push(@{$bysubmission{$symb}{$rev}},$what); + } + } else { + push(@{$bysubmission{$symb}{$rev}},$what); + } + $allmaps{$enclosing_map} = 1; + 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); + my $mapsymb = $mapres->symb(); + $toshow{$mapsymb} = 1; + if (ref($mapres)) { + my $pcslist = $mapres->map_hierarchy(); + if ($pcslist ne '') { + foreach my $pc (split(/,/,$pcslist)) { + my $res = $navmap->getByMapPc($pc); + if (ref($res)) { + my $symb = $res->symb(); + unless ($symb eq '______') { + $toshow{$symb} = 1; + } + } + } + } + } + } + } + my $mapres_header = '

'. + &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)) { + &show_contents_view($r,$navmap,$cid,\%toshow,\%bymap,\%byresource,\%bysubmission, + \%byresponsetype,\@scopeorder,\%lt); + } + $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, + $scopeorder,$lt) = @_; + if ((keys(%{$toshow}) > 0) || (keys(%{$byresource}) > 0) || + (keys(%{$bysubmission}) > 0) || (keys(%{$byresponsetype}) > 0)) { + my $location=&Apache::loncommon::lonhttpdurl("/adm/lonIcons"); + my $whitespace = ''; + my $icon = ''; + my $topmap = $env{'course.'.$cid.'.url'}; + $r->print(&Apache::loncommon::start_data_table(). + &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}})); + } + 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()); + } + } + } + } + $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')); + if (ref($bymap->{$url}) eq 'HASH') { + foreach my $rev (sort(keys(%{$bymap->{$url}}))) { + $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(''); + } + } else { + $r->print(' '); + } + return; +} + +sub get_param_description { + my ($stdtype,$value) = @_; + my $name = $value; + my $paramstrings = &Apache::lonparmset::standard_string_options($stdtype); + unless (ref($paramstrings) eq 'ARRAY') { + return $name; + } + foreach my $possibilities (@{$paramstrings}) { + next unless (ref($possibilities) eq 'ARRAY'); + my ($thing, $description) = @{ $possibilities }; + if ($thing eq $value) { + $name = $description; + last; + } + } + return $name; +} + +sub 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,@currcoown) = @_; + my ($output,@pendingcoown,@othercoords); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + my $ccrole = 'cc'; + my %ccroles = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,undef,[$ccrole]); + foreach my $key (sort(keys(%ccroles))) { + my ($ccname,$ccdom,$role) = split(':',$key); + next if ($key eq $env{'user.name'}.':'.$env{'user.domain'}.':'.$ccrole); + unless (grep(/^\Q$ccname\E:\Q$ccdom\E$/,@currcoown,@pendingcoown)) { + push(@othercoords,$ccname.':'.$ccdom); + } + } + my $coowner_rows = @currcoown + @pendingcoown + @othercoords; + if ($coowner_rows) { + $output .= &Apache::loncommon::start_data_table(); + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Current co-owners').''; + foreach my $person (@currcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if ($pendingcoowners) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invited as co-owners [_1](agreement pending)','
').'
'; + foreach my $person (@pendingcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if (@othercoords) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invite other Coordinators [_1]to become co-owners','
').'
'; + foreach my $person (@othercoords) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + } else { + $output = &mt('There are no coordinators to select as co-owners'); + } + return $output; +} + +sub manage_coownership { + my ($cnum,$cdom,@currcoown) = @_; + my (@pendingcoown); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + my ($is_coowner,$is_pending,$output); + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + if (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { + $is_coowner = 1; + } + if (grep(/^\Q$uname\E:\Q$udom\E$/,@pendingcoown)) { + $is_pending = 1; + } + if (@currcoown && ($is_coowner || $is_pending)) { + $output = &Apache::loncommon::start_data_table(); + } + if (@currcoown) { + if ($is_coowner || $is_pending) { + $output .= &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row().''; + } + $output .= &mt('Current co-owners are:').' '. + join(', ', map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + if ($is_coowner || $is_pending) { + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + if ($is_coowner || $is_pending) { + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row().''; + } + $output .= ''; + if ($is_coowner) { + $output .= &mt('You are currently a co-owner:').' '; + } else { + $output .= &mt('The course owner has invited you to become a co-owner:').' '.(' 'x2). + ''; + } + $output .= ''; + if (@currcoown) { + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + if (@currcoown && ($is_coowner || $is_pending)) { + $output .= &Apache::loncommon::end_data_table(); + } + return $output; +} + sub print_localization { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( languages => { - text => &mt('Languages used').'
'.&mt("(will override user's preference)"), + text => ''.&mt($itemtext->{'languages'}).'
'. + &mt("(overrides individual user preference)"), input => 'selectbox', }, timezone => { - text => &mt('Timezone in which the course takes place'), + text => ''.&mt($itemtext->{'timezone'}).'', input => 'selectbox', }, datelocale => { - text => &mt('Locale used for course calendar'), + text => ''.&mt($itemtext->{'datelocale'}).'', input => 'selectbox', }, ); @@ -673,7 +3017,11 @@ sub print_localization { my $count = 0; foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + my $colspan; + unless ($item eq 'languages') { + $colspan = 2; + } + $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); if ($item eq 'timezone') { my $includeempty = 1; my $timezone = &Apache::lonlocal::gettimezone(); @@ -692,39 +3040,40 @@ sub print_localization { undef,$includeempty); } else { if ($settings->{$item} eq '') { - $datatable .= - &Apache::loncommon::select_language('language_0','',1); + $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(); + 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; - my $code = &Apache::loncommon::supportedlanguagecode($lang); - if ($code) { - $showlang = &plainlanguagedescription($lang); + if (exists($langchoices{$lang})) { + $showlang = $langchoices{$lang}; } $datatable .= &Apache::loncommon::start_data_table_row(). - ''. + ''. &mt('Language:').' '.$showlang. '
'. ''. - &Apache::loncommon::end_data_table_row().''; + &Apache::loncommon::end_data_table_row(); $num ++; } } $datatable .= &Apache::loncommon::start_data_table_row(). - ''. - &mt('Additional language:').'
'. - &Apache::loncommon::select_language($item); + ''. + &mt('Additional language:'). '
'. + &Apache::loncommon::select_language('languages_'.$num,'',1). ''. ''.&Apache::loncommon::end_data_table_row(). - &Apache::loncommon::end_data_table(); + &Apache::loncommon::end_data_table().'
'; } } $datatable .= &item_table_row_end(); @@ -733,26 +3082,37 @@ sub print_localization { 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,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( - 'question' => { - text => ''.&mt('Resource Content').'', + 'question.email' => { + text => ''.&mt($itemtext->{'question.email'}).'', input => 'textbox', size => '50', }, - 'comment' => { - text => ''.&mt('Course Content').'', + 'comment.email' => { + text => ''.&mt($itemtext->{'comment.email'}).'', input => 'textbox', size => '50', }, - 'policy' => { - text => ''.&mt('Course Policy').'', + 'policy.email' => { + text => ''.&mt($itemtext->{'policy.email'}).'', input => 'textbox', size => '50', }, @@ -763,23 +3123,28 @@ sub print_feedback { my %sections = &Apache::loncommon::get_sections($cdom,$cnum); my @sections = sort( { $a <=> $b } keys(%sections)); my %lt = &Apache::lonlocal::texthash ( - currone => 'Current recipient:', - curmult => 'Current recipients:', - add => 'Additional recipient:', - del => 'Delete?', - sec => 'Sections:', + currone => 'Current recipient:', + currmult => 'Current recipients:', + add => 'Additional recipient:', + del => 'Delete?', + sec => 'Sections:', ); foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + if ($position eq 'top') { + $datatable .= &item_table_row_start($items{$item}{text},$count); + } else { + $datatable .= &item_table_row_start($items{$item}{text}."
(Custom text)",$count, "advanced",2); + } if ($position eq 'top') { my $includeempty = 0; - $datatable .= &user_table($cdom,$item,\@sections, - $settings->{$item.'.email'},\%lt); + $datatable .= ''. + &user_table($cdom,$item,\@sections, + $settings->{$item},\%lt); } else { - $datatable .= &Apache::lonhtmlcommon::textbox($item.'_text', - $settings->{$item},$items{$item}{size}); + $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text', + $settings->{$item.'.text'},$items{$item}{size}); } $datatable .= &item_table_row_end(); } @@ -795,7 +3160,7 @@ sub user_table { } else { my $num = 0; my @curr = split(/,/,$currvalue); - $output .= &Apache::loncommon::start_data_table(); + $output .= ''; my ($currusers); foreach my $val (@curr) { next if ($val eq ''); @@ -811,7 +3176,7 @@ sub user_table { 'name="'.$item.'_delete" value="'.$num.'" />'. $lt->{'del'}.''. ''.(' 'x2). + $num.'" value="'.$uname.':'.$udom.'" />'.(' 'x2). &Apache::loncommon::aboutmewrapper( &Apache::loncommon::plainname($uname,$udom,'firstname'), $uname,$udom,'aboutuser'); @@ -826,24 +3191,23 @@ sub user_table { $num ++; } if ($num) { - $output .= &Apache::loncommon::start_data_table_row(). + $output .= ''. ''. - &Apache::loncommon::end_data_table_row(); + ''; } - $output .= &Apache::loncommon::start_data_table_row(). + $output .= ''. ''.&Apache::loncommon::end_data_table_row(). - &Apache::loncommon::end_data_table(); + '
'; - if ($num > 1) { + if ($num == 1) { $output .= $lt->{'currone'}; } else { $output .= $lt->{'currmult'}; } $output .= '
'. ''.$currusers.'
'. $lt->{'add'}.'
'. &select_recipient($item,$num,$cdom,$sections). ''. - '
'; } return $output; } @@ -903,41 +3267,50 @@ sub select_sections { } sub print_discussion { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'plc.roles.denied' => { - text => ''.&mt('No Chat room use').''. - &Apache::loncommon::help_open_topic("Course_Disable_Discussion"), + text => ''.&mt($itemtext->{'plc.roles.denied'}).''. + &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'
'. + &mt('(role-based)'), input => 'checkbox', }, 'plc.users.denied' => { - text => ''.&mt('No Chat room use').'', + text => ''.&mt($itemtext->{'plc.users.denied'}).'
'. + &mt('(specific user(s))'), input => 'checkbox', }, 'pch.roles.denied' => { - text => ''.&mt('No Resource Discussion').''. - &Apache::loncommon::help_open_topic("Course_Disable_Discussion"), + text => ''.&mt($itemtext->{'pch.roles.denied'}).''. + &Apache::loncommon::help_open_topic("Course_Disable_Discussion").'
'. + &mt('(role-based)'), input => 'checkbox', }, 'pch.users.denied' => { - text => ''.&mt('No Resource Discussion').'', + text => ''.&mt($itemtext->{'pch.users.denied'}).'
'. + &mt('(specific user(s))'), input => 'checkbox', }, 'allow_limited_html_in_feedback' => { - text => ''.&mt('Allow limited HTML in discussion posts').'', + text => ''.&mt($itemtext->{'allow_limited_html_in_feedback'}).'', input => 'radio', }, 'allow_discussion_post_editing' => { - text => ''.&mt('Users can edit/delete own discussion posts').'', + 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; @@ -945,38 +3318,58 @@ sub print_discussion { my %sections = &Apache::loncommon::get_sections($cdom,$cnum); my @sections = sort( { $a <=> $b } keys(%sections)); my %lt = &Apache::lonlocal::texthash ( - currone => 'Disallowed:', - curmult => 'Disallowed:', - add => 'Disallow more:', - del => 'Delete?', - sec => 'Sections:', + currone => 'Disallowed:', + currmult => 'Disallowed:', + add => 'Disallow more:', + del => 'Delete?', + sec => 'Sections:', ); - foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + my $colspan; + if ($item eq 'allow_limited_html_in_feedback') { + $colspan = 2; + } + $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); if ($item eq 'plc.roles.denied') { - $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). + $datatable .= '
'. + ''.&role_checkboxes($cdom,$cnum,$item,$settings). '
'; } elsif ($item eq 'plc.users.denied') { - $datatable .= &user_table($cdom,$item,undef, + $datatable .= '
'. + &user_table($cdom,$item,undef, $settings->{$item},\%lt); } elsif ($item eq 'pch.roles.denied') { - $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). + $datatable .= ''. &Apache::loncommon::end_data_table_row(). &role_checkboxes($cdom,$cnum,$item,$settings,1). - &Apache::loncommon::end_data_table(); + &Apache::loncommon::end_data_table().'
'; + } elsif ($item eq 'discussion_post_fonts') { + $datatable .= ''. + ''. + ''. + ''. + ''. + &Apache::loncommon::end_data_table_row(). + &set_discussion_fonts($cdom,$cnum,$item,$settings). + &Apache::loncommon::end_data_table().'
'; } $datatable .= &item_table_row_end(); } @@ -985,8 +3378,13 @@ sub print_discussion { } sub role_checkboxes { - my ($cdom,$cnum,$item,$settings,$showsections) = @_; - my @roles = ('st','ad','ta','ep','in','cc'); + my ($cdom,$cnum,$item,$settings,$showsections,$crstype) = @_; + 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) { @@ -1005,6 +3403,8 @@ sub role_checkboxes { if (!grep(/^\Q$sec\E/,@{$currsec{$trole}})) { push(@{$currsec{$trole}},$sec); } + } else { + $currsec{$trole} = [$sec]; } } else { push(@curr_roles,$role); @@ -1021,7 +3421,7 @@ sub role_checkboxes { if (grep(/^\Q$role\E$/,@current)) { $checked = ' checked="checked" '; } - my $plrole=&Apache::lonnet::plaintext($role); + my $plrole=&Apache::lonnet::plaintext($role,$crstype); if ($showsections) { $output .= &Apache::loncommon::start_data_table_row(); } else { @@ -1033,7 +3433,7 @@ sub role_checkboxes { $output .= ''; } } - $output .= ''; if ($showsections) { @@ -1065,7 +3465,7 @@ sub role_checkboxes { $output .= ''; } } - $output .= ''; if ($showsections) { @@ -1091,50 +3491,143 @@ sub role_checkboxes { return $output; } +sub set_discussion_fonts { + my ($cdom,$cnum,$item,$settings) = @_; + my ($classorder,$classtitles) = &discussion_vote_classes(); + my ($styleorder,$styleitems) = &discussion_vote_styles(); + my $output; + if (ref($classorder) eq 'ARRAY') { + foreach my $cat (@{$classorder}) { + my %curr = (); + ($curr{'size'},$curr{'weight'},$curr{'style'},$curr{'other'}) = + split(/,/,$settings->{'discussion_post_fonts_'.$cat}); + $output .= &Apache::loncommon::start_data_table_row(). + ''; + if (ref($styleorder) eq 'ARRAY') { + foreach my $item (@{$styleorder}) { + $output .= ''; + } + $output .= &Apache::loncommon::end_data_table_row(); + } + return $output; +} + +sub discussion_vote_classes { + my $classorder = ['twoplus','oneplus','zero','oneminus','twominus']; + my %classtitles = &Apache::lonlocal::texthash( + 'twoplus' => 'Two sigma above mean', + 'oneplus' => 'One sigma above mean', + 'zero' => 'Within one sigma of mean', + 'oneminus' => 'One sigma below mean', + 'twominus' => 'Two sigma below mean', + ); + return ($classorder,\%classtitles); +} + +sub discussion_vote_styles { + my $styleorder = ['size','weight','style']; + my $styleitems = { + size => ['','px','%','xx-small','x-small','small','medium','large', + 'x-large','xx-large','smaller','larger'], + weight => ['','normal','bold','bolder','lighter','100','200','300','400', + '500','600','700','800','900'], + style => ['','normal','italic','oblique'], + }; + return ($styleorder,$styleitems); +} + sub print_classlists { - my ($position,$cdom,$settings,$rowtotal) = @_; + my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype) = @_; my @ordered; if ($position eq 'top') { @ordered = ('default_enrollment_start_date', 'default_enrollment_end_date'); + if ($crstype eq 'Course') { + push(@ordered,'defaultcredits'); + } } elsif ($position eq 'middle') { - @ordered = ('nothideprivileged'); + @ordered = ('nothideprivileged','checkforpriv'); } else { @ordered = ('student_classlist_view', - 'student_opt_in','student_classlist_portfiles'); + 'student_classlist_opt_in', + 'student_classlist_portfiles'); } + my %lt; + + 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('Start date').'', + text => ''.&mt($itemtext->{'default_enrollment_start_date'}).'', input => 'dates', }, 'default_enrollment_end_date' => { - text => ''.&mt('End date').'', + text => ''.&mt($itemtext->{'default_enrollment_end_date'}).'', input => 'dates', }, + 'defaultcredits' => { + text => ''.&mt($itemtext->{'defaultcredits'}).'', + }, 'nothideprivileged' => { - text => ''.&mt('Domain Coodinators in course').'', + text => ''.&mt($itemtext->{'nothideprivileged'}).'', input => 'checkbox', }, + 'checkforpriv' => { + text => ''.&mt($itemtext->{'checkforpriv'}).'', + input => 'selectbox', + }, + 'student_classlist_view' => { - text => ''.&mt('Student-viewable classlist').'', + text => ''.&mt($itemtext->{'student_classlist_view'}).'', input => 'selectbox', - options => { - disabled => &mt('No viewable classlist'), - section => &mt("Classlist of viewer's section"), - all => &mt('Classlist of all students'), - }, + options => \%lt, order => ['disabled','all','section'], }, - 'student_opt_in' => { - text => ''.&mt('Student agreement needed to be listed').'', + 'student_classlist_opt_in' => { + text => ''.&mt($itemtext->{'student_classlist_opt_in'}).'', input => 'radio', }, 'student_classlist_portfiles' => { - text => ''.&mt('Include link to accessible portfolio files').'', + text => ''.&mt($itemtext->{'student_classlist_portfiles'}).'', input => 'radio', }, ); @@ -1142,17 +3635,23 @@ sub print_classlists { ($settings->{'student_classlist_view'} eq 'section')) { $settings->{'student_classlist_view'} = 'disabled'; } - return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'classlists'); } sub print_appearance { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + 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('Default XML Style File').' '. + text => ''.&mt($itemtext->{'default_xml_style'}).' '. ''.&mt('Select Style File').'', @@ -1161,53 +3660,55 @@ sub print_appearance { }, 'pageseparators' => { - text => ''.&mt('Visibly Separate Items on Pages').'', + text => ''.&mt($itemtext->{'pageseparators'}).'', input => 'radio', }, 'disable_receipt_display' => { - text => ''.&mt('Disable display of problem receipts').'', + text => ''.&mt($itemtext->{'disable_receipt_display'}).'', input => 'radio', }, 'texengine' => { - text => ''.&mt('Force use of a specific math rendering engine.').'', + text => ''.&mt($itemtext->{'texengine'}).'', input => 'selectbox', options => { + MathJax => 'MathJax', jsMath => 'jsMath', mimetex => &mt('Convert to Images'), tth => &mt('TeX to HTML'), }, - order => ['jsMath','mimetex','tth'], - nullval => &mt("None specified - use student's choice"), + order => ['MathJax','jsMath','mimetex','tth'], + nullval => $mathdef, }, 'tthoptions' => { - text => ''.&mt('Default set of options to pass to tth/m when converting TeX').'', + text => ''.&mt($itemtext->{'tthoptions'}).'', input => 'textbox', size => 40, }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'appearance'); } sub print_grading { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'grading' => { - text => ''.&mt('Grading').''. + text => ''.&mt($itemtext->{'grading'}).''. &Apache::loncommon::help_open_topic('GradingOptions'), input => 'selectbox', options => { standard => &mt('Standard: shows points'), - external => &mt('External: shows number of completed parts'), + external => &mt('External: shows number of completed parts and totals'), + externalnototals => &mt('External: shows only number of completed parts'), spreadsheet => &mt('Spreadsheet: (with link to detailed scores)'), }, - order => ['standard','external','spreadsheet'], + order => ['standard','external','externalnototals','spreadsheet'], }, 'rndseed' => { - text => ''.&mt('Randomization algorithm used').''. - ''.'
'. + text => ''.&mt($itemtext->{'rndseed'}).''. + ''.'
'. &mt('Modifying this will make problems have different numbers and answers!'). '
', input => 'selectbox', @@ -1220,10 +3721,11 @@ sub print_grading { '64bit5' => '64bit5', }, order => ['32bit','64bit','64bit2','64bit3','64bit4','64bit5'], + advanced => 1 }, 'receiptalg' => { - text => ''.&mt('Receipt algorithm used').'
'. - &mt('This controls how receipt numbers are generated.'), + text => ''.&mt($itemtext->{'receiptalg'}).'
'. + &mt('This controls how receipt numbers are generated'), input => 'selectbox', options => { receipt => 'receipt', @@ -1231,31 +3733,32 @@ sub print_grading { receipt3 => 'receipt3', }, order => ['receipt','receipt2','receipt3'], + advanced => 1 }, 'disablesigfigs' => { - text => ''.&mt('Disable checking of Significant Figures').'', + text => ''.&mt($itemtext->{'disablesigfigs'}).'', input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'grading'); } sub print_printouts { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( problem_stream_switch => { - text => ''.&mt('Allow problems to be split over pages').'', + text => ''.&mt($itemtext->{'problem_stream_switch'}).'', input => 'radio', }, suppress_tries => { - text => ''.&mt('Suppress number of tries in printing').'', + text => ''.&mt($itemtext->{'suppress_tries'}).'', input => 'radio', }, default_paper_size => { - text => ''.&mt('Default paper type').'', + text => ''.&mt($itemtext->{'default_paper_size'}).'', input => 'selectbox', options => { Letter => &mt('Letter').' [8 1/2x11 in]', @@ -1269,74 +3772,92 @@ sub print_printouts { A6 => &mt('A6').' [105x148 mm]', }, order => ['Letter','Legal','Tabloid','Executive','A2','A3','A4','A5','A6'], - nullval => 'None specified', + nullval => &mt('None specified'), }, print_header_format => { - text => ''.&mt('Print header format').'', + text => ''.&mt($itemtext->{'print_header_format'}).'', input => 'checkbox', }, disableexampointprint => { - text => ''.&mt('Disable automatically printing point values on exams').'', + 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); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'printouts'); } sub print_spreadsheet { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + 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('Default Course Spreadsheet').' '. + text => ''.&mt($itemtext->{'spreadsheet_default_classcalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, spreadsheet_default_studentcalc => { - text => ''.&mt('Default Student Spreadsheet').' '. + text => ''.&mt($itemtext->{'spreadsheet_default_studentcalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, spreadsheet_default_assesscalc => { - text => ''.&mt('Default Assessment Spreadsheet').' '. + text => ''.&mt($itemtext->{'spreadsheet_default_assesscalc'}).' '. ''.$SelectSpreadsheetFile.'', input => 'textbox', }, hideemptyrows => { - text => ''.&mt('Hide Empty Rows in Spreadsheets').'', + text => ''.&mt($itemtext->{'hideemptyrows'}).'', input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); -} + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'spreadsheet'); +} sub print_bridgetasks { - my ($cdom,$settings,$ordered,$rowtotal) = @_; - unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype) = @_; + 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('Send message to student when clicking Done on Tasks').'', + text => ''.&mt($itemtext->{'task_messages'}).'', input => 'selectbox', options => { - only_student => &mt('Send message to student'), - student_and_user_notes_screen => &mt('Message to student and add to user notes'), + 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('Bridge Task grading by instructors and TAs in sections').'', + text => ''.&mt($itemtext->{'task_grading'}).'', input => 'selectbox', options => { any => &mt('Grade BTs in any section'), @@ -1345,52 +3866,77 @@ sub print_bridgetasks { order => ['any','section'], }, suppress_embed_prompt => { - text => ''.&mt('Hi$de upload references prompt if uploading file to portfolio').' '. - &mt('(applies when current role is student)').'', + text => ''.&mt($itemtext->{'suppress_embed_prompt'}).''. + ' '.&mt('(applies when current role is student)').'', input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'bridgetasks'); } sub print_other { - my ($cdom,$settings,$allitems,$rowtotal) = @_; + my ($cdom,$settings,$allitems,$rowtotal,$crstype) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } - my @ordered; + my @ordered = &get_other_items($cdom,$settings,$allitems); my %items; + foreach my $parameter (@ordered) { + $items{$parameter} = { + text => ''.$parameter.'', + input => 'textbox', + size => '15', + }, + } + push (@ordered,'newp_value'); + $items{'newp_value'} = { + text => ''.&mt('Create New Environment Variable').'
'. + '', + input => 'textbox', + size => '30', + }; + my $output = &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'other'); +} + +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'}.'/'}))); + next if (($parameter eq 'course.helper.not.run') && + (!exists($env{'user.role.dc./'.$env{'request.role.domain'}.'/'}))); unless (($parameter =~ m/^internal\./)||($parameter =~ m/^metadata\./) || ($parameter =~ m/^selfenroll_/) || ($parameter =~ /_selfenroll$/) || ($parameter eq 'type') || - ($parameter =~ m/^(cc|in|ta|ep|ad|st)\.plaintext$/)) { + ($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); - $items{$parameter} = { - text => $parameter, - input => 'textbox', - size => '15', - }, } } } - return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal); + return @ordered; } sub item_table_row_start { - my ($text,$count) = @_; + my ($text,$count,$add_class,$colspan) = @_; my $output; - if ($count%2) { - $output .= '
'; + my $css_class = ($count % 2) ? 'LC_odd_row' : 'LC_even_row'; + $css_class = (join(' ',$css_class,$add_class)) unless ($add_class eq ''); + $output .= ''."\n". + ''; + if ($colspan) { + $output .= ''; + $output .= ''. + &Apache::loncommon::end_data_table_row(); + $num ++; + unless (grep(/^\Q$currdom\E$/,@excdoms)) { + push(@excdoms,$currdom); + } + } + } + if ((scalar(keys(%domains)) - scalar(@excdoms)) > 0) { + $datatable .= + &Apache::loncommon::start_data_table_row(). + ''.&Apache::loncommon::end_data_table_row(); + } + $datatable .= &Apache::loncommon::end_data_table(). + ''. + '
'; } return $datatable; } @@ -1567,9 +4202,9 @@ sub print_hdrfmt_row { $currstr .= ''.&mt('Current print header:').' '. $settings->{$item}.'
'; my @current = split(/(%\d*[nca])/,$settings->{$item}); - foreach my $item (@current) { - unless ($item eq '') { - push(@curr,$item); + foreach my $val (@current) { + unless ($val eq '') { + push(@curr,$val); } } $currnum = @curr; @@ -1629,11 +4264,12 @@ function getIndexByName(item) { ENDJS - $output .= $currstr.&Apache::loncommon::start_data_table(); + $output .= '
'. + ''.&role_checkboxes($cdom,$cnum,$item,$settings). '
'; } elsif ($item eq 'pch.users.denied') { - $datatable .= &user_table($cdom,$item,undef, + $datatable .= '
'. + &user_table($cdom,$item,undef, $settings->{$item},\%lt); } elsif ($item eq 'allow_limited_html_in_feedback') { $datatable .= &yesno_radio($item,$settings); } elsif ($item eq 'allow_discussion_post_editing') { - $datatable .= &Apache::loncommon::start_data_table(). + $datatable .= '
'. + &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). '
'.&mt('Role').''. &mt('Sections').'
'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row(). + '
'.&mt('Sum of likes/dislikes').''.&mt('font-size').''.&mt('font-weight').''.&mt('font-style').''.&mt('Other css').'
'.$classtitles->{$cat}.''; + my $selitem = $item; + if ($item eq 'size') { + my ($currsize,$currunit); + if ($curr{'size'} =~ /^(\d+)(px|%)$/) { + ($currsize,$currunit) = ($1,$2); + $curr{'size'} = $currunit; + } + $output .= ''. + ' '; + $selitem = 'unit'; + } + if ((ref($styleitems) eq 'HASH') && (ref($styleitems->{$item}) eq 'ARRAY')) { + $output .= '
'.$text. + ''; } else { - $output .= '
'; } - $output .= ''.$text. - ''; return $output; } @@ -1461,15 +4007,35 @@ sub select_from_options { } sub make_item_rows { - my ($cdom,$items,$ordered,$settings,$rowtotal) = @_; + my ($cdom,$items,$ordered,$settings,$rowtotal,$crstype,$caller) = @_; my $datatable; if ((ref($items) eq 'HASH') && (ref($ordered) eq 'ARRAY')) { my $count = 0; foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items->{$item}{text},$count); - if ($item eq 'nothideprivileged') { - $datatable .= ¬hidepriv_row($cdom,$item,$settings); + my $colspan; + if ((($caller eq 'classlists') && ($item eq 'nothideprivileged')) || + (($caller eq 'printouts') && ($item ne 'print_header_format'))) { + $colspan = 2; + } + 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 ($item eq 'defaultcredits') { + my $defaultcredits = $env{'course.'.$env{'request.course.id'}.'.internal.defaultcredits'}; + my $showcredits; + if ($defaultcredits ne '') { + $showcredits = &mt('Default is [quant,_1,credit]',$defaultcredits); + } else { + $showcredits = &mt('No default set'); + } + $datatable .= $showcredits; + } elsif ($item eq 'nothideprivileged') { + $datatable .= ¬hidepriv_row($cdom,$item,$settings,$crstype); + } elsif ($item eq 'checkforpriv') { + $datatable .= &checkforpriv_row($cdom,$item,$settings,$crstype); } elsif ($item eq 'print_header_format') { $datatable .= &print_hdrfmt_row($item,$settings); } elsif ($items->{$item}{input} eq 'dates') { @@ -1499,10 +4065,9 @@ sub make_item_rows { } sub nothidepriv_row { - my ($cdom,$item,$settings) = @_; + my ($cdom,$item,$settings,$crstype) = @_; my ($cnum) = &get_course(); - my %nothide; - my $datatable; + my ($datatable,%nothide,@checkdoms); if (ref($settings) eq 'HASH') { if ($settings->{$item} ne '') { foreach my $user (split(/\s*\,\s*/,$settings->{$item})) { @@ -1513,23 +4078,30 @@ sub nothidepriv_row { } } } + if ($settings->{'checkforpriv'}) { + @checkdoms = split(/,/,$settings->{'checkforpriv'}); + } } - my %coursepersonnel = &Apache::lonnet::dump('nohist_userroles',$cdom,$cnum); - my $now = time; + push(@checkdoms,$cdom); + my %coursepersonnel = + &Apache::lonnet::get_my_roles($cnum,$cdom,'',['previous','future','active']); my @privusers; foreach my $person (keys(%coursepersonnel)) { - my ($role,$user,$usec) = ($person =~ /^([^:]*):([^:]+:[^:]+):([^:]*)/); - $user =~ s/:$//; - my ($end,$start) = split(/:/,$coursepersonnel{$person}); + my ($uname,$udom,$role) = split(/:/,$person); + my $user = $uname.':'.$udom; + my ($start,$end) = split(/:/,$coursepersonnel{$person}); if ($end == -1 || $start == -1) { next; } - my ($uname,$udom) = split(':',$user); - if (&Apache::lonnet::privileged($uname,$udom)) { - push(@privusers,$user); + foreach my $dom (@checkdoms) { + if (&Apache::lonnet::privileged($uname,$udom,\@checkdoms,['dc','su'])) { + unless (grep(/^\Q$user\E$/,@privusers)) { + push(@privusers,$user); + } + } } } - if (@privusers) { + if (@privusers > 0) { $datatable .= ''; foreach my $user (sort(@privusers)) { my $hideon = ' checked="checked" '; @@ -1546,13 +4118,76 @@ sub nothidepriv_row { ''. + $hideon.' value="" />'.&mt('Hidden').' '. + ''. ''; } $datatable .= '
'. ' '. - '
'; } else { - $datatable .= &mt('No Domain Coordinators have course roles'); + 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) = @_; + 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); + } else { + my @privdoms = split(/,/,$settings->{$item}); + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + $datatable = '
'. + &Apache::loncommon::start_data_table(); + if (@privdoms > 0) { + foreach my $currdom (@privdoms) { + next unless ($domains{$currdom}); + my $domdesc = &Apache::lonnet::domain($currdom,'description'); + if ($domdesc eq '') { + $domdesc = $currdom; + } + $datatable .= + &Apache::loncommon::start_data_table_row(). + '
'. + &mt('Domain:').' '.$domdesc. + '
'. + '
'. + &mt('Additional domain:'). '
'. + &Apache::loncommon::select_dom_form('','checkforpriv_'.$num,1, + 1,undef,undef,\@excdoms). + '

'. + $currstr.''; if (@curr > 0) { for (my $i=0; $i<@curr; $i++) { my $pos = $i+1; - $output .= &Apache::loncommon::start_data_table_row(). + $output .= ''. ''; } - $output .= &Apache::loncommon::end_data_table_row(); + $output .= ''; } } my $pos = $currnum+1; - $output .= &Apache::loncommon::start_data_table_row(). + $output .= ''. ''. - &Apache::loncommon::end_data_table_row(); + ''; $pos ++; $currnum ++; - $output .= &Apache::loncommon::start_data_table_row(). + $output .= ''. ''. ''. - &Apache::loncommon::end_data_table_row(). - &Apache::loncommon::end_data_table(); + '" value="" size ="25" />'. + ''. + ''. + '
'. &position_selector($pos,$i,$maxnum).&mt('Delete:'). '
'. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''. &substitution_selector($currnum).'
'. &position_selector($pos,$currnum,$maxnum). ''.&mt('New').''.&mt('Text').'
'. '

'; return $output; } @@ -1687,14 +4325,22 @@ sub position_selector { } sub substitution_selector { - my ($num,$subst,$limit) = @_; + my ($num,$subst,$limit,$crstype) = @_; + 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 => 'student name', - c => 'course ID', + n => $stunametxt, + c => $crsidtxt, a => 'assignment note', ); my $output .= &mt('Substitution').'
'. - ''; if ($subst eq '') { $output .= ''; } @@ -1712,10 +4358,66 @@ sub substitution_selector { return $output; } -sub modify_crsenv { - my ($action,$cdom,%domconfig) = @_; +sub change_clone { + my ($cdom,$cnum,$clonelist,$oldcloner) = @_; + my $clone_crs = $cnum.':'.$cdom; + if ($cnum && $cdom) { + my $clone_crs = $cnum.':'.$cdom; + my @allowclone; + if ($clonelist =~ /,/) { + @allowclone = split(',',$clonelist); + } else { + $allowclone[0] = $clonelist; + } + foreach my $currclone (@allowclone) { + if (!grep(/^$currclone$/,@$oldcloner)) { + if ($currclone ne '*') { + my ($uname,$udom) = split(/:/,$currclone); + if ($uname && $udom && $uname ne '*') { + if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable'); + if ($currclonecrs{'cloneable'} !~ /\Q$clone_crs\E/) { + if ($currclonecrs{'cloneable'} eq '') { + $currclonecrs{'cloneable'} = $clone_crs; + } else { + $currclonecrs{'cloneable'} .= ','.$clone_crs; + } + &Apache::lonnet::put('environment',\%currclonecrs,$udom,$uname); + } + } + } + } + } + } + foreach my $oldclone (@$oldcloner) { + if (!grep(/^\Q$oldclone\E$/,@allowclone)) { + if ($oldclone ne '*') { + my ($uname,$udom) = split(/:/,$oldclone); + if ($uname && $udom && $uname ne '*' ) { + if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable'); + my %newclonecrs = (); + if ($currclonecrs{'cloneable'} =~ /\Q$clone_crs\E/) { + if ($currclonecrs{'cloneable'} =~ /,/) { + my @currclonecrs = split/,/,$currclonecrs{'cloneable'}; + foreach my $crs (@currclonecrs) { + if ($crs ne $clone_crs) { + $newclonecrs{'cloneable'} .= $crs.','; + } + } + $newclonecrs{'cloneable'} =~ s/,$//; + } else { + $newclonecrs{'cloneable'} = ''; + } + &Apache::lonnet::put('environment',\%newclonecrs,$udom,$uname); + } + } + } + } + } + } + } return; } 1; -