--- loncom/interface/courseprefs.pm 2009/08/19 19:35:00 1.6 +++ loncom/interface/courseprefs.pm 2021/12/29 23:15:54 1.49.2.28.2.1 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set configuration settings for a course # -# $Id: courseprefs.pm,v 1.6 2009/08/19 19:35:00 raeburn Exp $ +# $Id: courseprefs.pm,v 1.49.2.28.2.1 2021/12/29 23:15:54 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -28,6 +28,185 @@ ############################################################### ############################################################## +=pod + +=head1 NAME + +courseprefs- Handler to set/modify course configuration + +=head1 SYNOPSIS + +courseprefs provides an interface for setting general course configuration + +=head1 DESCRIPTION + +This module is used for configuration of a course + +=head1 INTERNAL SUBROUTINES + +=over + +=item get_allitems() + +=item print_config_box() + +=item process_changes() + +=item get_sec_str() + +=item check_clone() + +=item store_changes() + +=item update_env() + +=item display_disallowed() + +=item get_course() + +=item get_jscript() + +=item cloners_javascript() + +=item print_courseinfo() + +=item new_cloners_dom_row() + +=item can_modify_catsettings() + +=item assign_course_categories() + +=item print_localization() + +=item get_lang_choices() + +=item print_feedback() + +=item user_table() + +=item select_recipient() + +=item select_sections() + +=item print_discussion() + +=item role_checkboxes() + +=item print_classlists() + +=item print_appearance() + +=item print_grading() + +=item print_printouts() + +=item print_spreadsheet() + +=item print_bridgetasks() + +=item print_other() + +=item get_other_items() + +=item item_table_row_start() + +=item item_table_row_end() + +=item yes_no_radio() + +=item select_from_options() + +=item make_item_rows() + +Creates table used to display and set course configuration items. + +Inputs: $cdom,$items,$ordered,$settings,$rowtotal,$crstype +where $cdom is course's domain, $items is HASH ref for current config +item, $ordered is ARRAY ref of items to include in row in +display order, $settings is HASH ref of current values forrow, +$rowtotal is SCALAR ref used to accumulate row count, $crstype is +course type. + +Returns: $datatable +HTML mark-up of data table which accumulates individual rows. + +=item nothidepriv_row() + +Creates row containing form elements used to display and set +whether Domain coordinators who are currently included in +advanced course user .db file for a course are to be hidden (e.g., +in syllabus, or from course user lists). + +Inputs: $cdom,$item,$settings,$crstype,$noedit +where $cdom is course domain, item is nothideprivileged, $settings is +HASH ref of the current values for nothideprivileged, $crstype is +course type (Course or Community). + +Return: $datatable +HTML mark-up for Privileged users (Domain Coordinators) in staff listing. + +=item print_hdrfmt_row() + +Creates row containing form elements used to display and set +substitution items and text to be used in the header included +on printouts. + +Inputs: $item,$settings +where $item is print_header_format, and $settings is a HASH ref +of the current values stored for print_header_format. + +Returns: $output +HTML mark-up containing Javascript functions: reOrder() and getIndexByName() +used to dynamically update position selectboxes, and HTML table elements +for the "Print header format" row. + +=item position_selector() + +Creates a select box which can be used to reorder substitutions +and text included in a printout header. + +Inputs: $pos,$num,$maxnum +where $pos is current position, $num is the unique identifier, +and $maxnum is the total number of items (both substitutions +and text in the printout header. + +Returns: $output +HTML mark-up for the selectbox and a hidden form element containing +the current position. + +=item substitution_selector() + +Creates a combination of select box for choosing an item +(student name, course ID or assignment note) to substitute, +and a corresponding size limit in the header used for printouts. + +Inputs: $num,$subst,$limit,$crstype +where $num is the unique identifier, $subst is the current +substitution (n,c or a, for name, course or note respectively, +$limit is the current size limit (integer), and $crstype is +course type - course or community. + +Returns: $output +HTML mark-up for selectbox and textbox (separate table cells). + +=item change_clone() + +Modifies the list of courses a user can clone (stored +in the user's environment.db file), called when a +change is made to the list of users allowed to clone +a course. + +Inputs: $action,$cloner +where $action is add or drop, and $cloner is identity of +user for whom cloning ability is to be changed in course. + +Returns: nothing + +=back + +=cut + + package Apache::courseprefs; use strict; @@ -36,9 +215,15 @@ use Apache::lonnet; use Apache::loncommon(); use Apache::lonhtmlcommon(); use Apache::lonconfigsettings; +use Apache::lonrelrequtils; +use Apache::lonparmset; +use Apache::courseclassifier; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); +my $registered_cleanup; +my $modified_courses; + sub handler { my $r=shift; if ($r->header_only) { @@ -48,24 +233,38 @@ sub handler { } my $context = 'course'; my $cid = $env{'request.course.id'}; - my ($cnum,$cdom) = &get_course($cid); + my ($cnum,$cdom,$chome) = &get_course($cid); my $crstype = &Apache::loncommon::course_type(); - my $parm_permission = &Apache::lonnet::allowed('opa',$cid); + my ($parm_permission,$allowed) = &get_permission($cid); my $navmap = Apache::lonnavmaps::navmap->new(); - if ($parm_permission && $navmap) { + if ($allowed && $navmap) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; } else { 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(); @@ -73,133 +272,219 @@ sub handler { &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::lonhtmlcommon::breadcrumbs($lt{'edit'}); my $phase = 'pickactions'; if ( exists($env{'form.phase'}) ) { $phase = $env{'form.phase'}; } - if ($phase eq 'categorizecourse') { - &assign_course_categories($r); + if (($phase eq 'categorizecourse') && ($parm_permission->{'categorizecourse'})) { + &assign_course_categories($r,$crstype); return OK; } + if (($phase eq 'releaseinfo') && ($parm_permission->{'releaseinfo'})) { + my $loncaparev = $env{'course.'.$cid.'.internal.releaserequired'}; + if ($loncaparev) { + if (&display_loncaparev_constraints($r,$navmap,$loncaparev,$crstype)) { + push(@{$modified_courses},[$cdom,$cnum,$chome,$crstype]); + unless ($registered_cleanup) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\&update_releasereq,@{$handlers}]); + $registered_cleanup=1; + } + } + return OK; + } + } + my %values=&Apache::lonnet::dump('environment',$cdom,$cnum); + my %courselti=&Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); + if ($courselti{'lock'}) { + delete($courselti{'lock'}); + } + $values{'linkprotection'} = \%courselti; my @prefs_order = ('courseinfo','localization','feedback','discussion', 'classlists','appearance','grading','printouts', - 'spreadsheet','bridgetasks','other'); + 'menuitems','linkprotection','spreadsheet','bridgetasks', + 'other'); my %prefs = ( 'courseinfo' => - { text => 'General course settings', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], - ordered => ['description','courseid','categories', - 'hidefromcat','cloners','externalsyllabus', - 'url','rolenames'], + { text => $lt{'gens'}, + help => 'Course_Prefs_General', + ordered => ['owner','co-owners','loncaparev','description', + 'clonedfrom','courseid','uniquecode','categories', + 'hidefromcat','syllabus','cloners','url', + 'rolenames'], itemtext => { - description => 'Course Description', - courseid => 'Course ID or number', - categories => 'Categorize course', - hidefromcat => 'Exclude from course catalog', - cloners => 'Users allowed to clone course', - externalsyllabus => 'URL of Syllabus', - url => 'Top Level Map', - rolenames => 'Replacement titles for standard course roles', + 'owner' => $lt{'ownr'}, + 'co-owners' => $lt{'cown'}, + 'description' => $lt{'desc'}, + 'courseid' => $lt{'idnu'}, + 'uniquecode' => $lt{'unco'}, + 'categories' => $lt{'catg'}, + 'hidefromcat' => $lt{'excc'}, + 'cloners' => $lt{'clon'}, + 'syllabus' => 'Syllabus status', + 'url' => 'Top Level Map', + 'rolenames' => $lt{'rept'}, + 'loncaparev' => $lt{'lcrv'}, + 'clonedfrom' => 'Cloned from', }, }, 'localization' => - { text => 'Language/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 => 'Timezone in which the course takes place', - datelocale => 'Locale used for course calendar', + 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'}], + col2 => 'Recipients'}], ordered => ['question.email','comment.email','policy.email'], itemtext => { 'question.email' => 'Resource Content', - 'comment.email' => 'Course Content', - 'policy.email' => 'Course Policy', + '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 => { - 'plc.roles.denied' => 'No Resource Discussion', - 'plc.users.denied' => 'No Resource Discussion', - 'pch.roles.denied' => 'No Chat room use', - 'pch.users.denied' => 'No Chat room use', - allow_limited_html_in_feedback => 'Allow limited HTML in discussion posts', + '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 => 'Domain Coodinators in course', - student_classlist_view => 'Student-viewable classlist', - student_opt_in => 'Student agreement needed to be listed', + 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'], + 'tthoptions','uselcmath','usejsme','inline_chem'], itemtext => { - default_xml_style => 'Default XML Style File', + default_xml_style => 'Default XML style file', pageseparators => 'Visibly Separate Items on Pages', disable_receipt_display => 'Disable display of problem receipts', texengine => 'Force use of a specific math rendering engine', tthoptions => 'Default set of options to pass to tth/m when converting TeX', + uselcmath => 'Student formula entry uses inline preview, not DragMath pop-up', + usejsme => 'Molecule editor uses JSME (HTML5) in place of JME (Java)', + inline_chem => 'Chemical reaction response uses inline preview, not pop-up', }, }, 'grading' => { text => 'Grading', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value',}], + help => 'Course_Prefs_Grading', ordered => ['grading','rndseed', 'receiptalg','disablesigfigs'], itemtext => { @@ -212,9 +497,7 @@ sub handler { }, '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'], @@ -223,62 +506,117 @@ sub handler { suppress_tries => 'Suppress number of tries in printing', default_paper_size => 'Default paper type', print_header_format => 'Print header format', - disableexampointprint => 'Disable automatically printing point values on exams', + disableexampointprint => 'Disable automatically printing point values on bubblesheet exams', + canuse_pdfforms => 'Users can print problems as PDF forms and upload later for grading', }, }, 'spreadsheet' => { text => 'Spreadsheets', - help => 'Course_Environment', - header => [{col1 => 'Setting', - col2 => 'Value'}], + help => 'Course_Prefs_Spreadsheet', ordered => ['spreadsheet_default_classcalc', 'spreadsheet_default_studentcalc', 'spreadsheet_default_assesscalc','hideemptyrows'], itemtext => { - spreadsheet_default_classcalc => 'Default Course Spreadsheet', - spreadsheet_default_studentcalc => 'Default Student Spreadsheet', + spreadsheet_default_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 => 'Send message to student when clicking Done on Tasks', + 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', }, }, + 'menuitems' => + { + text => 'Menu display', + help => 'Course_Prefs_Menus', + header => [{col1 => 'Default Menu', + col2 => 'Value',}, + {col1 => 'Menu collections', + col2 => 'Settings', + }], + ordered => ['menudefault','menucollections'], + itemtext => { + menudefault => 'Choose default collection of menu items for course', + menucollections => 'Menu collections', + }, + }, + 'linkprotection' => + { + text => 'Link protection', + help => 'Course_Prefs_Linkprotection', + header => [{col1 => 'Item', + col2 => 'Settings', + }], + }, 'other' => { text => 'Other settings', - help => 'Course_Environment', + help => 'Course_Prefs_Other', header => [ {col1 => 'Item', col2 => 'Value', }], }, ); - if ($phase eq 'process') { + if (($phase eq 'process') && ($parm_permission->{'process'})) { my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::make_changes($r,$cdom,$phase,$context, \@prefs_order,\%prefs,\%values, - $cnum,undef,\@allitems); - } elsif ($phase eq 'display') { - my $jscript = &get_jscript($cdom,$phase); + $cnum,undef,\@allitems, + 'coursepref',$parm_permission); + } elsif (($phase eq 'display') && ($parm_permission->{'display'})) { + my $noedit; + if (ref($parm_permission) eq 'HASH') { + unless ($parm_permission->{'process'}) { + $noedit = 1; + } + } + my $jscript = &get_jscript($cid,$cdom,$phase,$crstype,\%values,$noedit); my @allitems = &get_allitems(%prefs); &Apache::lonconfigsettings::display_settings($r,$cdom,$phase,$context, - \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems); + \@prefs_order,\%prefs,\%values,undef,$jscript,\@allitems,$crstype, + 'coursepref',$parm_permission); } else { &Apache::lonconfigsettings::display_choices($r,$phase,$context, - \@prefs_order,\%prefs); + \@prefs_order,\%prefs, + 'coursepref',$parm_permission); } return OK; } +sub get_permission { + my ($cid) = @_; + my %permission; + my $allowed = 0; + return (\%permission,$allowed) unless ($cid); + if (&Apache::lonnet::allowed('opa',$cid)) { + %permission= ( + 'pickactions' => 1, + 'categorizecourse' => 1, + 'releaseinfo' => 1, + 'process' => 1, + 'display' => 1, + ); + } elsif (&Apache::lonnet::allowed('vpa',$env{'request.course.id'})) { + %permission = ( + 'pickactions' => 1, + 'releaseinfo' => 1, + 'display' => 1, + ); + } + foreach my $perm (values(%permission)) { + if ($perm) { $allowed=1; last; } + } + return (\%permission,$allowed); +} + sub get_allitems { my (%prefs) = @_; my @allitems; @@ -296,91 +634,138 @@ sub get_allitems { } sub print_config_box { - my ($r,$cdom,$phase,$action,$item,$settings,$allitems) = @_; + my ($r,$cdom,$phase,$action,$item,$settings,$allitems,$crstype,$parm_permission) = @_; my $ordered = $item->{'ordered'}; my $itemtext = $item->{'itemtext'}; + my $noedit; + if (ref($parm_permission) eq 'HASH') { + unless ($parm_permission->{'process'}) { + $noedit = 1; + } + } my $rowtotal = 0; my $output = ' - '."\n". - ''; - if (($action eq 'feedback') || ($action eq 'classlists')) { + '."\n". + ''; + if (($action eq 'feedback') || ($action eq 'classlists') || ($action eq 'menuitems')) { $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); + } } } } @@ -1329,41 +2639,171 @@ sub print_courseinfo { ''.&Apache::loncommon::end_data_table_row(). &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,$itemtext,\$rowtotal); + $output .= &print_feedback('top',$cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'classlists') { - $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal); + $output .= &print_classlists('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); + } elsif ($action eq 'menuitems') { + $output .= &print_menuitems('top',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''; + } else { + $output .= ' + '; + } + $output .= &mt($item->{'header'}->[0]->{'col2'}).'
+ '; - $output .= ' - + if ($action eq 'classlists') { + $output .= ' + '; if ($action eq 'classlists') { - $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal). + $output .= &print_classlists('middle',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit). '
'.&mt($item->{'header'}->[1]->{'col1'}).''.&mt($item->{'header'}->[1]->{'col2'}).''; + } else { + $output .= ' + '; + } + $output .= &mt($item->{'header'}->[1]->{'col2'}).'
- - - - - '; +
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
'; + if (exists $item->{'header'}->[2]->{'col1'} || + exists $item->{'header'}->[2]->{'col2'}) { + $output .= ' + + + + '; + } } } else { $output .= ' '. + "'cloners_all'".');"'.$disabled.' />'.&mt('No').''. &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,$itemtext,\$rowtotal); + $output .= &print_courseinfo($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'localization') { - $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_localization($cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'feedback') { - $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_feedback('bottom',$cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); } elsif ($action eq 'discussion') { - $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal); - } elsif ($action eq 'classlists') { - $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal); + $output .= &print_discussion($cdom,$settings,$ordered,$itemtext,\$rowtotal,$noedit); + } elsif (($action eq 'classlists') || ($action eq 'viewableroster')) { + $output .= &print_classlists('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'appearance') { - $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_appearance($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'grading') { - $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_grading($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'printouts') { - $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_printouts($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'spreadsheet') { - $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_spreadsheet($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'bridgetasks') { - $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal); + $output .= &print_bridgetasks($cdom,$settings,$ordered,$itemtext,\$rowtotal,$crstype,$noedit); + } elsif ($action eq 'menuitems') { + $output .= &print_menuitems('bottom',$cdom,$settings,$itemtext,\$rowtotal,$crstype,$noedit); + } elsif ($action eq 'linkprotection') { + $output .= &print_linkprotection($cdom,$settings,\$rowtotal,$crstype,$noedit); } elsif ($action eq 'other') { - $output .= &print_other($cdom,$settings,$allitems,\$rowtotal); + $output .= &print_other($cdom,$settings,$allitems,\$rowtotal,$crstype,$noedit); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''; + } else { + $output .= ''; + } + $output .= &mt($item->{'header'}->[0]->{'col2'}).'
@@ -391,8 +776,8 @@ sub print_config_box { } sub process_changes { - my ($cdom,$action,$values,$item,$changes,$allitems,$disallowed) = @_; - my %newvalues; + my ($cdom,$cnum,$action,$values,$item,$changes,$allitems,$disallowed,$crstype) = @_; + my (%newvalues,%courselti,$errors); if (ref($item) eq 'HASH') { if (ref($changes) eq 'HASH') { my @ordered; @@ -409,8 +794,44 @@ sub process_changes { } } } + } elsif ($action eq 'linkprotection') { + if (ref($values->{'linkprotection'}) eq 'HASH') { + foreach my $id (keys(%{$values->{'linkprotection'}})) { + if ($id =~ /^\d+$/) { + push(@ordered,$id); + unless (ref($values->{'linkprotection'}->{$id}) eq 'HASH') { + $courselti{$id} = ''; + } + } + } + } + @ordered = sort { $a <=> $b } @ordered; + if (($env{'form.linkprot_add'}) && ($env{'form.linkprot_maxnum'} =~ /^\d+$/)) { + push(@ordered,$env{'form.linkprot_maxnum'}); + } } elsif (ref($item->{'ordered'}) eq 'ARRAY') { - @ordered = @{$item->{'ordered'}}; + if ($action eq 'courseinfo') { + my ($can_toggle_cat,$can_categorize) = + &can_modify_catsettings($cdom,$crstype); + foreach my $entry (@{$item->{'ordered'}}) { + next if (($entry eq 'hidefromcat') && + (!$can_toggle_cat)); + next if (($entry eq 'categories') && + (!$can_categorize)); + next if (($entry eq 'loncaparev') || + ($entry eq 'owner') || + ($entry eq 'clonedfrom') || + ($entry eq 'syllabus')); + push(@ordered,$entry); + } + } elsif ($action eq 'classlists') { + foreach my $entry (@{$item->{'ordered'}}) { + next if ($entry eq 'defaultcredits'); + push(@ordered,$entry); + } + } else { + @ordered = @{$item->{'ordered'}}; + } } if (@ordered > 0) { if ($action eq 'feedback') { @@ -450,6 +871,152 @@ sub process_changes { $changes->{$ext_entry} = $newvalues{$ext_entry}; } } + } elsif ($action eq 'menuitems') { + my (%current,@colls); + my $next = 1; + if ($values->{'menucollections'}) { + foreach my $item (split(/;/,$values->{'menucollections'})) { + my ($num,$value) = split(/\%/,$item); + if ($num =~ /^\d+$/) { + unless (grep(/^$num$/,@colls)) { + push(@colls,$num); + } + my @entries = split(/\&/,$value); + foreach my $entry (@entries) { + my ($name,$fields) = split(/=/,$entry); + $current{$num}{$name} = $fields; + } + } + } + } + if (@colls) { + @colls = sort { $a <=> $b } @colls; + $next += $colls[-1]; + } + if ($env{'form.menucollections_add'} eq $next) { + push(@colls,$next); + } + my $currdef = $values->{'menudefault'}; + my $possdef = $env{'form.menudefault'}; + if (($possdef =~ /^\d+$/) && (grep(/^$possdef$/,@colls))) { + if ($currdef ne $possdef) { + $changes->{'menudefault'} = $possdef; + } + } elsif ($currdef) { + $changes->{'menudefault'} = ''; + } + my $menucoll; + if (@colls) { + my ($ordered,$cats) = &menuitems_categories(); + my %shortcats = &menuitems_abbreviations(); + foreach my $num (@colls) { + my ($entry,%include); + map { $include{$_}= 1; } &Apache::loncommon::get_env_multiple('form.menucollections_'.$num); + foreach my $item (@{$ordered}) { + if ($item eq 'shown') { + foreach my $type (@{$cats->{$item}}) { + $entry .= $type.'='; + if ($include{$type}) { + $entry .= 'y'; + } else { + $entry .= 'n'; + } + $entry .= '&'; + } + } else { + $entry .= $shortcats{$item}.'='; + foreach my $type (@{$cats->{$item}}) { + if ($include{$type}) { + $entry .= $type.','; + } + } + $entry =~ s/,$//; + $entry .= '&'; + } + } + $entry =~ s/\&$//; + if ($menucoll) { + $menucoll .= ';'; + } + $menucoll .= $num.'%'.$entry; + } + if ($menucoll ne $values->{'menucollections'}) { + $changes->{'menucollections'} = $menucoll; + } + } elsif ($values->{'menucollections'}) { + $changes->{'menucollections'} = ''; + } + } elsif ($action eq 'linkprotection') { + my %menutitles = <imenu_titles(); + my (@items,%deletions,%itemids,%haschanges); + if ($env{'form.linkprot_add'}) { + my $name = $env{'form.linkprot_name_add'}; + $name =~ s/(`)/'/g; + my ($newid,$error) = &get_courselti_id($cdom,$cnum,$name); + if ($newid) { + $itemids{'add'} = $newid; + push(@items,'add'); + $haschanges{$newid} = 1; + } else { + $errors .= ''. + &mt('Failed to acquire unique ID for link protection'). + ''; + } + } + if (ref($values->{'linkprotection'}) eq 'HASH') { + my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_del'); + my $maxnum = $env{'form.linkprot_maxnum'}; + for (my $i=0; $i<=$maxnum; $i++) { + my $itemid = $env{'form.linkprot_id_'.$i}; + $itemid =~ s/\D+//g; + if ($itemid) { + if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') { + push(@items,$i); + $itemids{$i} = $itemid; + if ((@todelete > 0) && (grep(/^$i$/,@todelete))) { + $deletions{$itemid} = $values->{'linkprotection'}->{$itemid}->{'name'}; + } + } + } + } + } + foreach my $idx (@items) { + my $itemid = $itemids{$idx}; + next unless ($itemid); + if (exists($deletions{$itemid})) { + $courselti{$itemid} = $deletions{$itemid}; + $haschanges{$itemid} = 1; + next; + } + my %current; + if (ref($values->{'linkprotection'}) eq 'HASH') { + if (ref($values->{'linkprotection'}->{$itemid}) eq 'HASH') { + foreach my $key (keys(%{$values->{'linkprotection'}->{$itemid}})) { + $current{$key} = $values->{'linkprotection'}->{$itemid}->{$key}; + } + } + } + foreach my $inner ('name','key','secret','lifetime','version') { + my $formitem = 'form.linkprot_'.$inner.'_'.$idx; + $env{$formitem} =~ s/(`)/'/g; + if ($inner eq 'lifetime') { + $env{$formitem} =~ s/[^\d.]//g; + } + unless ($idx eq 'add') { + if ($current{$inner} ne $env{$formitem}) { + $haschanges{$itemid} = 1; + } + } + if ($env{$formitem} ne '') { + $courselti{$itemid}{$inner} = $env{$formitem}; + } + } + } + if (keys(%haschanges)) { + foreach my $entry (keys(%haschanges)) { + $changes->{$entry} = $courselti{$entry}; + } + } } else { foreach my $entry (@ordered) { if ($entry eq 'cloners') { @@ -459,9 +1026,9 @@ sub process_changes { my @clonedoms; if (exists($env{'form.cloners_activate'})) { my $actnum = $env{'form.cloners_activate'}; - if ($actnum ne '') { - if ($env{'form.clonersdom_'.$actnum} ne '') { - my $clonedom = $env{'form.clonersdom_'.$actnum}; + if ($actnum ne '-1') { + if ($env{'form.cloners_dom_'.$actnum} ne '') { + my $clonedom = $env{'form.cloners_dom_'.$actnum}; if (&check_clone($clonedom,$disallowed) eq 'ok') { $newvalues{$entry} = '*:'.$clonedom; push(@clonedoms,$newvalues{$entry}); @@ -477,7 +1044,7 @@ sub process_changes { my $clonedom = $env{'form.cloners_dom_'.$i}; if (&check_clone($clonedom,$disallowed) eq 'ok') { if (!grep(/^\*:\Q$clonedom\E$/,@clonedoms)) { - push (@clonedoms,'*:'.$clonedom); + push(@clonedoms,'*:'.$clonedom); } } } @@ -490,7 +1057,7 @@ sub process_changes { my $clonedom = $env{'form.cloners_newdom'}; if (&check_clone($clonedom,$disallowed) eq 'ok') { my $newdom = '*:'.$env{'form.cloners_newdom'}; - if (@clonedoms) { + if (@clonedoms) { if (!grep(/^\Q$newdom\E$/,@clonedoms)) { $newvalues{$entry} .= ','.$newdom; } @@ -503,10 +1070,14 @@ sub process_changes { my @cloners = split(',',$env{'form.'.$entry}); my @okcloners; foreach my $cloner (@cloners) { - my ($uname,$udom) = split(':',$cloner); - if (&check_clone($udom,$disallowed,$uname) eq 'ok') { - if (!grep(/^\Q$cloner\E$/,@okcloners)) { - push(@okcloners,$cloner); + $cloner =~ s/^\s+//; + $cloner =~ s/\s+$//; + unless ($cloner eq '') { + my ($uname,$udom) = split(':',$cloner); + if (&check_clone($udom,$disallowed,$uname) eq 'ok') { + if (!grep(/^\Q$cloner\E$/,@okcloners)) { + push(@okcloners,$cloner); + } } } } @@ -519,6 +1090,37 @@ sub process_changes { } } } + if (ref($values) eq 'HASH') { + my (@code_order,%codedefaults); + &Apache::lonnet::auto_instcode_defaults($cdom,\%codedefaults, + \@code_order); + my $clonebycode; + if ($env{'form.cloners_instcode'}) { + if (@code_order > 0) { + my @standardnames = &Apache::loncommon::get_standard_codeitems(); + my %local_to_standard; + for (my $i=0; $i<@code_order; $i++) { + $local_to_standard{$code_order[$i]} = $standardnames[$i]; + } + foreach my $item (@code_order) { + my $key = $local_to_standard{$item}; + if ($key ne '') { + if ($env{'form.'.$key}) { + $clonebycode .= $key.'='.&escape($env{'form.'.$key}).'&'; + } + } + } + $clonebycode =~ s/\&$//; + } + } + if ($clonebycode) { + if ($newvalues{$entry}) { + $newvalues{$entry} .= ','.$clonebycode; + } else { + $newvalues{$entry} = $clonebycode; + } + } + } } if (ref($disallowed) eq 'HASH') { if (ref($disallowed->{'cloners'}) eq 'HASH') { @@ -527,21 +1129,100 @@ sub process_changes { } } } + } elsif ($entry eq 'co-owners') { + my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; + my $coowners = $values->{'internal.co-owners'}; + my @currcoown; + if ($coowners) { + @currcoown = split(',',$coowners); + } + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + my $autocoowner; + if (($crstype eq 'Course') && + ($values->{'internal.coursecode'})) { + my %domconf = + &Apache::lonnet::get_dom('configuration',['autoenroll'],$cdom); + if (ref($domconf{'autoenroll'}) eq 'HASH') { + $autocoowner = $domconf{'autoenroll'}{'co-owners'}; + } + } + unless ($autocoowner) { + my @keepcoowners = &Apache::loncommon::get_env_multiple('form.coowners'); + my @pendingcoowners = &Apache::loncommon::get_env_multiple('form.pendingcoowners'); + my @invitecoowners = &Apache::loncommon::get_env_multiple('form.invitecoowners'); + if (@invitecoowners) { + push(@pendingcoowners,@invitecoowners); + } + $newvalues{'pendingco-owners'} = join(',',sort(@pendingcoowners)); + $newvalues{'co-owners'} = join(',',sort(@keepcoowners)); + if ($newvalues{'co-owners'} ne $values->{'internal.co-owners'}) { + $changes->{$entry}{'co-owners'} = $newvalues{'co-owners'}; + push(@{$changes->{$entry}{'changed'}},'co-owners'); + } + if ($newvalues{'pendingco-owners'} ne $values->{'internal.pendingco-owners'}) { + $changes->{$entry}{'pendingco-owners'} = $newvalues{'pendingco-owners'}; + push(@{$changes->{$entry}{'changed'}},'pendingco-owners'); + } + } + } else { + my (@newpending,@newcoown); + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + my $pendingcoowners = $values->{'internal.pendingco-owners'}; + my @pendingcoown = split(',',$pendingcoowners); + if ($env{'form.pending_coowner'}) { + foreach my $item (@pendingcoown) { + unless ($item eq $uname.':'.$udom) { + push(@newpending,$item); + } + } + @newcoown = @currcoown; + if ($env{'form.pending_coowner'} eq 'accept') { + unless (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { + push(@newcoown,$uname.':'.$udom); + } + } + } elsif ($env{'form.remove_coowner'}) { + foreach my $item (@currcoown) { + unless ($item eq $uname.':'.$udom) { + push(@newcoown,$item); + } + } + if ($pendingcoowners ne '') { + @newpending = @pendingcoown; + } + } + $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 $crstype = &Apache::loncommon::course_type(); my %adv_roles = &Apache::lonnet::get_course_adv_roles($env{'request.course.id'},1); - my @stds = ('cc','in','ta','ep','ad','st'); + my @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); + push(@replacements,$role); } else { push(@regulars,$role); } - } + } foreach my $stdrole (@stds) { my $ext_entry = $entry.'_'.$stdrole; my $stdname = &Apache::lonnet::plaintext($stdrole,$crstype, @@ -554,7 +1235,6 @@ sub process_changes { if ($newvalues{$ext_entry} ne $values->{$stdrole.'.plaintext'}) { my $dupname = 0; if ($newvalues{$ext_entry} ne '') { - my $dupname = 0; if (grep(/^\Q$newvalues{$ext_entry}\E$/,@replacements)) { $dupname = 1; push(@{$disallowed->{'rolenames'}{'replacements'}},$newvalues{$ext_entry}); @@ -636,6 +1316,35 @@ sub process_changes { } } $newvalues{$entry} =~ s/,$//; + } elsif ($entry eq 'discussion_post_fonts') { + my ($classorder,$classtitles) = &discussion_vote_classes(); + my $fontchange = 0; + foreach my $class (@{$classorder}) { + my $ext_entry = $entry.'_'.$class; + my $size = $env{'form.'.$ext_entry.'_size'}; + my $unit = $env{'form.'.$ext_entry.'_unit'}; + my $weight = $env{'form.'.$ext_entry.'_weight'}; + my $style = $env{'form.'.$ext_entry.'_style'}; + my $other = $env{'form.'.$ext_entry.'_other'}; + $size =~ s/,//g; + $unit =~ s/,//g; + $weight =~ s/,//g; + $style =~ s/,//g; + $other =~ s/[^\w;:\s\-\%.]//g; + $other =~ s/(^\s+|\s+$)//g; + $newvalues{$ext_entry} = join(',',($size.$unit,$weight,$style,$other)); + my $current = $values->{$ext_entry}; + if ($values->{$ext_entry} eq '') { + $current = ',,,'; + } + if ($newvalues{$ext_entry} ne $current) { + $changes->{$ext_entry} = $newvalues{$ext_entry}; + $fontchange ++; + } + } + if ($fontchange) { + $changes->{$entry} = 1; + } } elsif ($entry eq 'nothideprivileged') { my @curr_nothide; my @new_nothide; @@ -655,7 +1364,7 @@ sub process_changes { } foreach my $key (keys(%env)) { if ($key =~ /^form\.\Q$entry\E_($match_username:$match_domain)$/) { - if ($env{'form.'.$key}) { + if ($env{$key}) { my $nothide = $1; if (!grep(/^\Q$nothide\E$/,@new_nothide)) { push(@new_nothide,$nothide); @@ -691,8 +1400,8 @@ sub process_changes { $hdr .= $env{'form.printfmthdr_limit_'.$i}; } $hdr .= $env{'form.printfmthdr_sub_'.$i}; - } elsif ($env{'form.printfmthdr_sub_'.$i} ne '') { - $hdr = $env{'form.printfmthdr_sub_'.$i}; + } elsif ($env{'form.printfmthdr_text_'.$i} ne '') { + $hdr = $env{'form.printfmthdr_text_'.$i}; } $newhdr[$env{'form.printfmthdr_pos_'.$i}] = $hdr; } @@ -710,44 +1419,101 @@ sub process_changes { my $newtext = $maxnum-1; $newhdr[$env{'form.printfmthdr_pos_'.$newtext}] = $env{'form.printfmthdr_text_'.$newtext}; $newvalues{$entry} = join('',@newhdr); - } elsif ($entry eq 'languages') { - my $langstr; + } elsif (($entry eq 'languages') || + ($entry eq 'checkforpriv')) { + my $settings; my $total = $env{'form.'.$entry.'_total'}; if ($total) { my @deletes = &Apache::loncommon::get_env_multiple('form.'.$entry.'_delete'); for (my $i=0; $i<$total; $i++) { unless (grep(/^$i$/,@deletes)) { - $langstr .= $env{'form.'.$entry.'_'.$i}.','; + $settings .= $env{'form.'.$entry.'_'.$i}.','; } } } else { $total = 0; } if ($env{'form.'.$entry.'_'.$total} ne '') { - my $newlang = $env{'form.'.$entry.'_'.$total}; - my %langchoices = &get_lang_choices(); - if ($langchoices{$newlang}) { - $langstr .= $newlang; + my $new = $env{'form.'.$entry.'_'.$total}; + if ($entry eq 'languages') { + my %langchoices = &get_lang_choices(); + if ($langchoices{$new}) { + $settings .= $new; + } else { + $settings =~ s/,$//; + $disallowed->{'localization'}{$entry} = $new; + } } else { - $langstr =~ s/,$//; - $disallowed->{'localization'}{$entry} = $newlang; + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + if ($domains{$new}) { + $settings .= $new; + } else { + $settings =~ s/,$//; + $disallowed->{'classlists'}{$entry} = $new; + } } } else { - $langstr =~ s/,$//; + $settings =~ s/,$//; } - $newvalues{$entry} = $langstr; + $newvalues{$entry} = $settings; } else { $newvalues{$entry} = $env{'form.'.$entry}; } - if ($newvalues{$entry} ne $values->{$entry}) { - $changes->{$entry} = $newvalues{$entry}; + unless (($entry eq 'co-owners') || ($entry eq 'discussion_post_fonts')) { + if ($newvalues{$entry} ne $values->{$entry}) { + $changes->{$entry} = $newvalues{$entry}; + } } } } } } } - return; + return $errors; +} + +sub get_courselti_id { + my ($cdom,$cnum,$name) = @_; + # get lock on lti db in course + my $lockhash = { + lock => $env{'user.name'}. + ':'.$env{'user.domain'}, + }; + my $tries = 0; + my $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); + my ($id,$error); + while (($gotlock ne 'ok') && ($tries<10)) { + $tries ++; + sleep (0.1); + $gotlock = &Apache::lonnet::newput('lti',$lockhash,$cdom,$cnum); + } + if ($gotlock eq 'ok') { + my %currids = &Apache::lonnet::dump('lti',$cdom,$cnum,undef,undef,undef,1); + if ($currids{'lock'}) { + delete($currids{'lock'}); + if (keys(%currids)) { + my @curr = sort { $a <=> $b } keys(%currids); + if ($curr[-1] =~ /^\d+$/) { + $id = 1 + $curr[-1]; + } else { + $id = 1; + } + } else { + $id = 1; + } + if ($id) { + unless (&Apache::lonnet::newput('lti',{ $id => $name },$cdom,$cnum) eq 'ok') { + $error = 'nostore'; + } + } else { + $error = 'nonumber'; + } + } + my $dellockoutcome = &Apache::lonnet::del('lti',['lock'],$cdom,$cnum); + } else { + $error = 'nolock'; + } + return ($id,$error); } sub get_sec_str { @@ -790,14 +1556,36 @@ sub check_clone { } sub store_changes { - my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes) = @_; + my ($cdom,$cnum,$prefs_order,$actions,$prefs,$values,$changes,$crstype) = @_; my ($chome,$output); - my (%storehash,@delkeys,@need_env_update); + my (%storehash,@delkeys,@need_env_update,@oldcloner,%oldlinkprot); if ((ref($values) eq 'HASH') && (ref($changes) eq 'HASH')) { + if (ref($values->{'linkprotection'}) eq 'HASH') { + %oldlinkprot = %{$values->{'linkprotection'}}; + } + delete($values->{'linkprotection'}); %storehash = %{$values}; } else { - $output = &mt('No changes made to course settings.'); - return; + if ($crstype eq 'Community') { + $output = &mt('No changes made to community settings.'); + } else { + $output = &mt('No changes made to course settings.'); + } + return $output; + } + my ($numchanges,$skipstore); + if (ref($changes) eq 'HASH') { + $numchanges = scalar(keys(%{$changes})); + if (($numchanges == 1) && (exists($changes->{'linkprotection'}))) { + $skipstore = 1; + } elsif (!$numchanges) { + if ($crstype eq 'Community') { + $output = &mt('No changes made to community settings.'); + } else { + $output = &mt('No changes made to course settings.'); + } + return $output; + } } my %yesno = ( hidefromcat => '1', @@ -811,19 +1599,54 @@ sub store_changes { 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:').'
'. + &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''. - (' 'x2).''.&mt('Yes').''. + (' 'x2).'
'.&mt('Or'). - '
'. + '
'.&mt('Or'). + '
'. &Apache::loncommon::start_data_table(); my @cloners; if ($settings->{$item} eq '') { - $datatable .= &new_cloners_dom_row($cdom,'0'); + unless ($noedit) { + my $default; + if ($currcanclone eq 'domain') { + $default = '0'; + } + $datatable .= &new_cloners_dom_row($cdom,'0',$default); + } } elsif ($settings->{$item} ne '*') { my @entries = split(/,/,$settings->{$item}); if (@entries > 0) { foreach my $entry (@entries) { my ($uname,$udom) = split(/:/,$entry); + if ($udom =~ /^$match_domain$/) { + unless (&Apache::lonnet::domain($udom)) { + next; + } + } else { + next; + } if ($uname eq '*') { $datatable .= &Apache::loncommon::start_data_table_row(). '
'. - &mt('Domain:').' '.$udom. + &mt('Any user in domain:').' '.$udom. '
'. '
'. $add_domtitle.'
'. &Apache::loncommon::select_dom_form('','cloners_newdom', - $includeempty). + $includeempty,undef,undef, + undef,undef,$noedit). ''. '
'.&mt('And'). - '
'. + '
'.&mt('And'). + '
'. &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''. &mt('Specific users').' ('. &mt('user:domain,user:domain').')
'. &Apache::lonhtmlcommon::textbox($item,$cloners_str, - $items{$item}{'size'}). + $items{$item}{'size'},$disabled). ''.&Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(); + if (@code_order > 0) { + my (%cat_items,@codetitles,%cat_titles,%cat_order); + my ($jscript,$totcodes,$numtitles,$lasttitle) = + &Apache::courseclassifier::instcode_selectors_data($cdom,'display', + \%cat_items,\@codetitles, + \%cat_titles,\%cat_order); + my $showncodes = 'off'; + my $checkedoff = ' checked="checked"'; + my $checkedon = ''; + if ($cloner_instcode) { + $checkedon = $checkedoff; + $checkedoff = ''; + $showncodes = 'on'; + } + $datatable .= '
'.&mt('And'). + '
'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row(). + ''. + &mt('Cloning by official course(s) based on course category').(' 'x2). + ''. + (' '). + ''. + &Apache::courseclassifier::build_instcode_selectors($numtitles, + $lasttitle,\%cat_items,\@codetitles,\%cat_titles,\%cat_order, + $showncodes,'LC_cloners_instcodes','LC_cloners_instcode',$noedit). + ''.&Apache::loncommon::end_data_table_row(). + &Apache::loncommon::end_data_table(); + } } elsif ($item eq 'rolenames') { - $datatable .= &Apache::loncommon::start_data_table(); - 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). ''. &Apache::lonhtmlcommon::textbox('rolenames_'.$role, $settings->{$role.'.plaintext'}, - $items{$item}{size}).''. + $items{$item}{size},$disabled).''. &Apache::loncommon::end_data_table_row(); } $datatable .= &Apache::loncommon::end_data_table().''; } elsif ($item eq 'categories') { - my $launcher = 'onFocus="this.blur();javascript:catsbrowser();";'; + my $launcher; + if ($noedit) { + $launcher = $disabled; + } else { + $launcher = 'onfocus="this.blur();javascript:catsbrowser();"'; + } $datatable .= ''. &Apache::lonhtmlcommon::textbox($item.'_display',$settings->{$item}, $items{$item}{size},$launcher); + } elsif ($item eq 'owner') { + my $owner = $env{'course.'.$env{'request.course.id'}.'.internal.courseowner'}; + if ($owner =~ /:/) { + my ($ownername,$ownerdom) = split(':',$owner); + $owner = &Apache::loncommon::plainname($ownername,$ownerdom); + } elsif ($owner ne '') { + $owner = &Apache::loncommon::plainname($owner,$cdom); + } else { + $owner = &mt('None specified'); + } + $datatable .= $owner; + } elsif ($item eq 'clonedfrom') { + my $clonesrc = $env{'course.'.$env{'request.course.id'}.'.clonedfrom'}; + my $clonedfrom = &mt('None'); + if ($clonesrc =~ m{/$match_domain/$match_courseid}) { + my %clonesrcinfo = &Apache::lonnet::coursedescription($clonesrc); + if ($clonesrcinfo{'description'}) { + $clonedfrom = $clonesrcinfo{'description'}.' '.($clonesrc); + } + } + $datatable .= $clonedfrom; + } elsif ($item eq 'uniquecode') { + my $code = $env{'course.'.$env{'request.course.id'}.'.internal.uniquecode'}; + if ($code) { + $datatable .= $code; + } + } elsif ($item eq 'co-owners') { + my $coowners = $env{'course.'.$env{'request.course.id'}.'.internal.co-owners'}; + my @currcoown; + if ($coowners) { + @currcoown = split(',',$coowners); + } + if (&Apache::lonnet::is_course_owner($cdom,$cnum)) { + if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) { + $datatable .= &show_autocoowners(@currcoown); + } else { + $datatable .= &coowner_invitations($cnum,$cdom,\@currcoown,$noedit); + } + } else { + if (($crstype eq 'Course') && ($env{'course.'.$env{'request.course.id'}.'.internal.coursecode'}) && ($autocoowner)) { + $datatable .= &show_autocoowners(@currcoown); + } else { + $datatable .= &manage_coownership($cnum,$cdom,\@currcoown,$noedit); + } + } + } elsif ($item eq 'syllabus') { + my $external = $env{'course.'.$env{'request.course.id'}.'.externalsyllabus'}; + my $uploaded = $env{'course.'.$env{'request.course.id'}.'.uploadedsyllabus'}; + my $minimal = $env{'course.'.$env{'request.course.id'}.'.minimalsyllabus'}; + if (($minimal =~/\w/) || ($uploaded =~/\w/)) { + if ($minimal =~/\w/) { + if ($external =~ m{\Q$minimal\E$}) { + undef($external); + } + } elsif ($uploaded =~/\w/) { + if ($external =~ m{\Q$uploaded\E$}) { + undef($external); + } + } + } elsif ($external!~/\w/) { + undef($external); + } + if ($external) { + $datatable .= &mt('External URL'); + } elsif ($minimal) { + $datatable .= &mt('Minimal template'); + } elsif ($uploaded) { + $datatable .= &mt('Uploaded file'); + } else { + $datatable .= &mt('Standard template'); + } + $datatable .= (' ' x 2). + &mt('[_1]View[_2]', + '', + ''); + } elsif ($item eq 'loncaparev') { + my $loncaparev = $env{'course.'.$env{'request.course.id'}.'.internal.releaserequired'}; + my $showreqd; + if ($loncaparev) { + $showreqd = &mt('[_1] or newer',$loncaparev).' '. + &mt('Details').''; + } else { + $showreqd = &mt('No specific version required'); + } + $datatable .= $showreqd; } else { - $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size}); + $datatable .= &Apache::lonhtmlcommon::textbox($item,$settings->{$item},$items{$item}{size},$disabled); } $datatable .= &item_table_row_end(); } @@ -1372,19 +2812,24 @@ sub print_courseinfo { } sub new_cloners_dom_row { - my ($newdom,$num) = @_; - my $output; + my ($newdom,$num,$default) = @_; + my ($output,$checkedon,$checkedoff); if ($newdom ne '') { + if ($num eq $default) { + $checkedon = 'checked="checked" '; + } else { + $checkedoff = 'checked="checked" '; + } $output .= &Apache::loncommon::start_data_table_row(). ''. &mt('Any user in domain:').' '.$newdom.''. (' 'x2).''.(' 'x2). ' @@ -1462,59 +2928,810 @@ 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 $now = time; + 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 = ''; + } + } elsif ($item eq 'printstartdate') { + if ($value =~ /^\d+$/) { + if ($value > $now) { + $value = 'future'; + } + } + } elsif ($item eq 'printenddate') { + if ($value =~ /^\d+$/) { + if ($value < $now) { + $value = 'past'; + } + } + + } + 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); + if (ref($mapres)) { + my $mapsymb = $mapres->symb(); + $toshow{$mapsymb} = 1; + my $pcslist = $mapres->map_hierarchy(); + if ($pcslist ne '') { + foreach my $pc (split(/,/,$pcslist)) { + my $res = $navmap->getByMapPc($pc); + if (ref($res)) { + my $symb = $res->symb(); + unless ($symb eq '______') { + $toshow{$symb} = 1; + } + } + } + } + } + } + } + my $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')); + my $newrow = 0; + if (ref($bymap->{$url}) eq 'HASH') { + foreach my $rev (sort(keys(%{$bymap->{$url}}))) { + if ($newrow) { + $r->print(&Apache::loncommon::end_data_table_row(). + &Apache::loncommon::continue_data_table_row()); + } + $r->print(''.$rev.''); + if (ref($bymap->{$url}{$rev}) eq 'HASH') { + $r->print(''); + foreach my $scope (@{$scopeorder}) { + if (ref($bymap->{$url}{$rev}{$scope}) eq 'HASH') { + $r->print(''); + foreach my $which (sort(keys(%{$bymap->{$url}{$rev}{$scope}}))) { + $r->print(''); + } + $r->print(''); + } elsif (ref($bymap->{$url}{$rev}{$scope}) eq 'ARRAY') { + $r->print(''); + } + } + $r->print('
'.&mt('Setting - scope: [_1]',$lt->{$scope}).''.$which.''. + join('
',@{$bymap->{$url}{$rev}{$scope}{$which}}). + '
'.&mt('Setting - scope: [_1]',$lt->{$scope}). + ' '. + join('
',@{$bymap->{$url}{$rev}{$scope}}).'
'); + } + $r->print(''); + $newrow = 1; + } + } else { + $r->print(' '); + } + return; +} + +sub get_param_description { + my ($stdtype,$value) = @_; + 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,$currcoownref,$noedit) = @_; + my ($output,@pendingcoown,@othercoords,@currcoown); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + if (ref($currcoownref) eq 'ARRAY') { + @currcoown == @{$currcoownref}; + } + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + my $ccrole = 'cc'; + my %ccroles = &Apache::lonnet::get_my_roles($cnum,$cdom,undef,undef,[$ccrole]); + foreach my $key (sort(keys(%ccroles))) { + my ($ccname,$ccdom,$role) = split(':',$key); + next if ($key eq $env{'user.name'}.':'.$env{'user.domain'}.':'.$ccrole); + unless (grep(/^\Q$ccname\E:\Q$ccdom\E$/,@currcoown,@pendingcoown)) { + push(@othercoords,$ccname.':'.$ccdom); + } + } + my $coowner_rows = @currcoown + @pendingcoown + @othercoords; + if ($coowner_rows) { + $output .= &Apache::loncommon::start_data_table(); + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Current co-owners').''; + foreach my $person (@currcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if ($pendingcoowners) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invited as co-owners [_1](agreement pending)','
').'
'; + foreach my $person (@pendingcoown) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + if (@othercoords) { + $output .= &Apache::loncommon::start_data_table_row(). + ''.&mt('Invite other Coordinators [_1]to become co-owners','
').'
'; + foreach my $person (@othercoords) { + my ($co_uname,$co_dom) = split(':',$person); + $output .= ''.(' 'x2).' '; + } + $output .= ''. + &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::end_data_table(); + } else { + $output = &mt('There are no coordinators to select as co-owners'); + } + return $output; +} + +sub manage_coownership { + my ($cnum,$cdom,$currcoownref,$noedit) = @_; + my (@pendingcoown,@currcoown); + my $pendingcoowners = + $env{'course.'.$env{'request.course.id'}.'.internal.pendingco-owners'}; + if ($pendingcoowners) { + @pendingcoown = split(',',$pendingcoowners); + } + if (ref($currcoownref) eq 'ARRAY') { + @currcoown == @{$currcoownref}; + } + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + my ($is_coowner,$is_pending,$output); + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + if (grep(/^\Q$uname\E:\Q$udom\E$/,@currcoown)) { + $is_coowner = 1; + } + if (grep(/^\Q$uname\E:\Q$udom\E$/,@pendingcoown)) { + $is_pending = 1; + } + if (@currcoown && ($is_coowner || $is_pending)) { + $output = &Apache::loncommon::start_data_table(); + } + if (@currcoown) { + if ($is_coowner || $is_pending) { + $output .= &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row().''; + } + $output .= &mt('Current co-owners are:').' '. + join(', ', map { &Apache::loncommon::plainname(split(':',$_)); } (@currcoown)); + if ($is_coowner || $is_pending) { + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + if ($is_coowner || $is_pending) { + if (@currcoown) { + $output .= &Apache::loncommon::start_data_table_row().''; + } + $output .= ''; + if ($is_coowner) { + $output .= &mt('You are currently a co-owner:').' '; + } else { + $output .= &mt('The course owner has invited you to become a co-owner:').' '.(' 'x2). + ''; + } + $output .= ''; + if (@currcoown) { + $output .= ''.&Apache::loncommon::end_data_table_row(); + } + } + if (@currcoown && ($is_coowner || $is_pending)) { + $output .= &Apache::loncommon::end_data_table(); + } + return $output; +} + sub print_localization { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( languages => { - text => &mt($itemtext->{'languages'}).'
'. - &mt("(will override user's preference)"), + text => ''.&mt($itemtext->{'languages'}).'
'. + &mt("(overrides individual user preference)"), input => 'selectbox', }, timezone => { - text => &mt($itemtext->{'timezone'}), + text => ''.&mt($itemtext->{'timezone'}).'', input => 'selectbox', }, datelocale => { - text => &mt($itemtext->{'datelocale'}), + text => ''.&mt($itemtext->{'datelocale'}).'', input => 'selectbox', }, ); - my $datatable; + my ($datatable,$disabled); my $count = 0; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $item (@{$ordered}) { $count ++; - $datatable .= &item_table_row_start($items{$item}{text},$count); + my $colspan; + unless ($item eq 'languages') { + $colspan = 2; + } + $datatable .= &item_table_row_start($items{$item}{text},$count,undef,$colspan); if ($item eq 'timezone') { my $includeempty = 1; my $timezone = &Apache::lonlocal::gettimezone(); $datatable .= &Apache::loncommon::select_timezone($item,$timezone,undef, - $includeempty); + $includeempty,$disabled); } elsif ($item eq 'datelocale') { my $includeempty = 1; my $locale_obj = &Apache::lonlocal::getdatelocale(); @@ -1524,15 +3741,18 @@ sub print_localization { } $datatable .= &Apache::loncommon::select_datelocale($item,$currdatelocale, - undef,$includeempty); + undef,$includeempty,$disabled); } else { if ($settings->{$item} eq '') { - $datatable .= - &Apache::loncommon::select_language('languages_0','',1); + unless ($noedit) { + $datatable .= ''. + &Apache::loncommon::select_language('languages_0','',1); + } } else { my $num = 0; my @languages = split(/\s*[,;:]\s*/,$settings->{$item}); - $datatable .= &Apache::loncommon::start_data_table(); + $datatable .= '
'. + &Apache::loncommon::start_data_table(); if (@languages > 0) { my %langchoices = &get_lang_choices(); foreach my $lang (@languages) { @@ -1547,19 +3767,22 @@ sub print_localization { '

'. ''. &Apache::loncommon::end_data_table_row(); $num ++; } } - $datatable .= &Apache::loncommon::start_data_table_row(). + unless ($noedit) { + $datatable .= + &Apache::loncommon::start_data_table_row(). ''. &mt('Additional language:'). '
'. &Apache::loncommon::select_language('languages_'.$num,'',1). ''. - ''.&Apache::loncommon::end_data_table_row(). - &Apache::loncommon::end_data_table(); + ''.&Apache::loncommon::end_data_table_row(); + } + $datatable .= &Apache::loncommon::end_data_table().'
'; } } $datatable .= &item_table_row_end(); @@ -1580,7 +3803,7 @@ sub get_lang_choices { } sub print_feedback { - my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($position,$cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -1609,23 +3832,31 @@ 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:', ); - + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } 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},\%lt); + $datatable .= ''. + &user_table($cdom,$item,\@sections, + $settings->{$item},\%lt,$noedit); } else { $datatable .= &Apache::lonhtmlcommon::textbox($item.'.text', - $settings->{$item.'.text'},$items{$item}{size}); + $settings->{$item.'.text'},$items{$item}{size},$disabled); } $datatable .= &item_table_row_end(); } @@ -1634,15 +3865,21 @@ sub print_feedback { } sub user_table { - my ($cdom,$item,$sections,$currvalue,$lt) = @_; + my ($cdom,$item,$sections,$currvalue,$lt,$noedit) = @_; my $output; if ($currvalue eq '') { - $output .= &select_recipient($item,'0',$cdom,$sections); + unless ($noedit) { + $output .= &select_recipient($item,'0',$cdom,$sections); + } } else { my $num = 0; my @curr = split(/,/,$currvalue); - $output .= &Apache::loncommon::start_data_table(); + $output .= ''; my ($currusers); + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $val (@curr) { next if ($val eq ''); my ($uname,$udom,$seclist) = ($val =~ /^($match_username):($match_domain)(\(?[^\)]*\)?)$/); @@ -1654,7 +3891,7 @@ sub user_table { $currusers .= ''. ''; $num ++; } if ($num) { - $output .= &Apache::loncommon::start_data_table_row(). + $output .= ''. ''. - &Apache::loncommon::end_data_table_row(); + ''; } - $output .= &Apache::loncommon::start_data_table_row(). + unless ($noedit) { + $output .= + ''. ''.&Apache::loncommon::end_data_table_row(). - &Apache::loncommon::end_data_table(); + ''; + } + $output .= '
'. ''. ''.(' 'x2). @@ -1665,31 +3902,34 @@ sub user_table { if (@{$sections}) { $currusers.= (' 'x3).$lt->{'sec'}.' '. &select_sections($item,$num,$sections, - \@selsec); + \@selsec,$noedit); } } $currusers .= '
'; - 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; } @@ -1699,10 +3939,9 @@ sub select_recipient { my $domform = &Apache::loncommon::select_dom_form($cdom,$item.'_udom_'.$num,$includeempty); my $selectlink = &Apache::loncommon::selectstudent_link('display',$item.'_uname_'.$num, - $item.'_udom_'.$num,1); - my $css_class = ($num % 2)?'LC_even_row':'LC_odd_row'; + $item.'_udom_'.$num,'only'); my $output = - '
'.&mt('Username').'
'. + ''. ''; if (ref($sections) eq 'ARRAY') { @@ -1717,14 +3956,17 @@ sub select_recipient { } sub select_sections { - my ($item,$num,$sections,$selected) = @_; - my ($output,@currsecs,$allsec); + my ($item,$num,$sections,$selected,$noedit) = @_; + my ($output,@currsecs,$allsec,$disabled); if (ref($selected) eq 'ARRAY') { @currsecs = @{$selected}; } if (!@currsecs) { $allsec = ' selected="selected"'; } + if ($noedit) { + $disabled = ' disabled="disabled"'; + } if (ref($sections) eq 'ARRAY') { if (@{$sections}) { my $mult; @@ -1734,7 +3976,7 @@ sub select_sections { $mult .= ' size="4"'; } } - $output = ''. ' '; foreach my $sec (@{$sections}) { my $is_sel; @@ -1750,14 +3992,14 @@ sub select_sections { } sub print_discussion { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } my %items = ( 'plc.roles.denied' => { - text => ''.&mt($itemtext->{'plc.roles.denied'}).''. - &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', }, @@ -1769,8 +4011,8 @@ sub print_discussion { }, 'pch.roles.denied' => { - text => ''.&mt($itemtext->{'pch.roles.denied'}).''. - &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', }, @@ -1789,6 +4031,11 @@ sub print_discussion { text => ''.&mt($itemtext->{'allow_discussion_post_editing'}).'', input => 'checkbox', }, + 'discussion_post_fonts' => { + text => ''.&mt($itemtext->{'discussion_post_fonts'}).'', + input => 'textbox', + size => '20', + }, ); my $datatable; my $count; @@ -1796,38 +4043,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 .= '
'.&mt('Username').'
'. '
'.&mt('Domain').'
'.$domform.'
'.&role_checkboxes($cdom,$cnum,$item,$settings). + $datatable .= '
'. + ''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). '
'; } elsif ($item eq 'plc.users.denied') { - $datatable .= &user_table($cdom,$item,undef, - $settings->{$item},\%lt); + $datatable .= '
'. + &user_table($cdom,$item,undef, + $settings->{$item},\%lt,$noedit); } elsif ($item eq 'pch.roles.denied') { - $datatable .= ''.&role_checkboxes($cdom,$cnum,$item,$settings). + $datatable .= ''. &Apache::loncommon::end_data_table_row(). - &role_checkboxes($cdom,$cnum,$item,$settings,1). - &Apache::loncommon::end_data_table(); + &role_checkboxes($cdom,$cnum,$item,$settings,1,undef,$noedit). + &Apache::loncommon::end_data_table().'
'; + } elsif ($item eq 'discussion_post_fonts') { + $datatable .= ''. + ''. + ''. + ''. + ''. + &Apache::loncommon::end_data_table_row(). + &set_discussion_fonts($cdom,$cnum,$item,$settings,$noedit). + &Apache::loncommon::end_data_table().'
'; } $datatable .= &item_table_row_end(); } @@ -1836,8 +4103,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,$noedit) = @_; + my @roles = ('st','ad','ta','ep','in'); + if ($crstype eq 'Community') { + push(@roles,'co'); + } else { + push(@roles,'cc'); + } my $output; my (@current,@curr_roles,%currsec,@sections); if ($showsections) { @@ -1869,12 +4141,16 @@ sub role_checkboxes { } my $numinrow = 3; my $count = 0; + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } foreach my $role (@roles) { my $checked = ''; if (grep(/^\Q$role\E$/,@current)) { $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 { @@ -1886,12 +4162,12 @@ sub role_checkboxes { $output .= ''; } } - $output .= ''; if ($showsections) { $output .= ''; } $count ++; @@ -1918,12 +4194,12 @@ sub role_checkboxes { $output .= ''; } } - $output .= ''; if ($showsections) { $output .= ''.&Apache::loncommon::end_data_table_row(); } $total ++; @@ -1944,18 +4220,111 @@ sub role_checkboxes { return $output; } +sub set_discussion_fonts { + my ($cdom,$cnum,$item,$settings,$noedit) = @_; + my ($classorder,$classtitles) = &discussion_vote_classes(); + my ($styleorder,$styleitems) = &discussion_vote_styles(); + my $output; + if (ref($classorder) eq 'ARRAY') { + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + foreach my $cat (@{$classorder}) { + my %curr = (); + ($curr{'size'},$curr{'weight'},$curr{'style'},$curr{'other'}) = + split(/,/,$settings->{'discussion_post_fonts_'.$cat}); + $output .= &Apache::loncommon::start_data_table_row(). + ''; + if (ref($styleorder) eq 'ARRAY') { + foreach my $item (@{$styleorder}) { + $output .= ''; + } + $output .= &Apache::loncommon::end_data_table_row(); + } + return $output; +} + +sub discussion_vote_classes { + my $classorder = ['twoplus','oneplus','zero','oneminus','twominus']; + my %classtitles = &Apache::lonlocal::texthash( + 'twoplus' => 'Two sigma above mean', + 'oneplus' => 'One sigma above mean', + 'zero' => 'Within one sigma of mean', + 'oneminus' => 'One sigma below mean', + 'twominus' => 'Two sigma below mean', + ); + return ($classorder,\%classtitles); +} + +sub discussion_vote_styles { + my $styleorder = ['size','weight','style']; + my $styleitems = { + size => ['','px','%','xx-small','x-small','small','medium','large', + 'x-large','xx-large','smaller','larger'], + weight => ['','normal','bold','bolder','lighter','100','200','300','400', + '500','600','700','800','900'], + style => ['','normal','italic','oblique'], + }; + return ($styleorder,$styleitems); +} + sub print_classlists { - my ($position,$cdom,$settings,$itemtext,$rowtotal) = @_; + my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype,$noedit) = @_; my @ordered; if ($position eq 'top') { @ordered = ('default_enrollment_start_date', 'default_enrollment_end_date'); + if ($crstype eq 'Course') { + push(@ordered,'defaultcredits'); + } } elsif ($position eq 'middle') { - @ordered = ('nothideprivileged'); + @ordered = ('nothideprivileged','checkforpriv'); } else { @ordered = ('student_classlist_view', - 'student_opt_in','student_classlist_portfiles'); + 'student_classlist_opt_in', + 'student_classlist_portfiles'); } + my %lt; + + if ($crstype eq 'Community') { + %lt = &Apache::lonlocal::texthash ( + disabled => 'No viewable membership list', + section => "Membership of viewer's section", + all => 'List of all members', + ); + } else { + %lt = &Apache::lonlocal::texthash ( + disabled => 'No viewable classlist', + section => "Classlist of viewer's section", + all => 'Classlist of all students', + ); + } + my %items = ( 'default_enrollment_start_date' => { text => ''.&mt($itemtext->{'default_enrollment_start_date'}).'', @@ -1965,24 +4334,28 @@ sub print_classlists { text => ''.&mt($itemtext->{'default_enrollment_end_date'}).'', input => 'dates', }, + 'defaultcredits' => { + text => ''.&mt($itemtext->{'defaultcredits'}).'', + }, 'nothideprivileged' => { text => ''.&mt($itemtext->{'nothideprivileged'}).'', input => 'checkbox', }, + 'checkforpriv' => { + text => ''.&mt($itemtext->{'checkforpriv'}).'', + input => 'selectbox', + }, + 'student_classlist_view' => { text => ''.&mt($itemtext->{'student_classlist_view'}).'', input => 'selectbox', - options => { - 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($itemtext->{'student_opt_in'}).'', + 'student_classlist_opt_in' => { + text => ''.&mt($itemtext->{'student_classlist_opt_in'}).'', input => 'radio', }, @@ -1995,14 +4368,20 @@ 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',$noedit); } sub print_appearance { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } + my $mathdef; + if ($crstype eq 'Community') { + $mathdef = &mt("None specified - use member's choice"); + } else { + $mathdef = &mt("None specified - use student's choice"); + } my %items = ( 'default_xml_style' => { text => ''.&mt($itemtext->{'default_xml_style'}).' '. @@ -2025,24 +4404,36 @@ sub print_appearance { text => ''.&mt($itemtext->{'texengine'}).'', input => 'selectbox', options => { - jsMath => 'jsMath', + MathJax => 'MathJax', mimetex => &mt('Convert to Images'), tth => &mt('TeX to HTML'), }, - order => ['jsMath','mimetex','tth'], - nullval => &mt("None specified - use student's choice"), + order => ['MathJax','mimetex','tth'], + nullval => $mathdef, }, 'tthoptions' => { text => ''.&mt($itemtext->{'tthoptions'}).'', input => 'textbox', size => 40, }, + 'uselcmath' => { + text => ''.&mt($itemtext->{'uselcmath'}).'', + input => 'radio', + }, + 'usejsme' => { + text => ''.&mt($itemtext->{'usejsme'}).'', + input => 'radio', + }, + 'inline_chem' => { + text => ''.&mt($itemtext->{'inline_chem'}).'', + input => 'radio', + }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'appearance',$noedit); } sub print_grading { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2053,14 +4444,15 @@ sub print_grading { 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($itemtext->{'rndseed'}).''. - ''.'
'. + ''.'
'. &mt('Modifying this will make problems have different numbers and answers!'). '
', input => 'selectbox', @@ -2073,6 +4465,7 @@ sub print_grading { '64bit5' => '64bit5', }, order => ['32bit','64bit','64bit2','64bit3','64bit4','64bit5'], + advanced => 1 }, 'receiptalg' => { text => ''.&mt($itemtext->{'receiptalg'}).'
'. @@ -2084,17 +4477,18 @@ sub print_grading { receipt3 => 'receipt3', }, order => ['receipt','receipt2','receipt3'], + advanced => 1 }, 'disablesigfigs' => { text => ''.&mt($itemtext->{'disablesigfigs'}).'', input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'grading',$noedit); } sub print_printouts { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2122,7 +4516,7 @@ sub print_printouts { A6 => &mt('A6').' [105x148 mm]', }, order => ['Letter','Legal','Tabloid','Executive','A2','A3','A4','A5','A6'], - nullval => 'None specified', + nullval => &mt('None specified'), }, print_header_format => { text => ''.&mt($itemtext->{'print_header_format'}).'', @@ -2132,12 +4526,22 @@ sub print_printouts { 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',$noedit); } sub print_spreadsheet { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } @@ -2169,21 +4573,29 @@ sub print_spreadsheet { input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); -} + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'spreadsheet',$noedit); +} sub print_bridgetasks { - my ($cdom,$settings,$ordered,$itemtext,$rowtotal) = @_; + my ($cdom,$settings,$ordered,$itemtext,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($ordered) eq 'ARRAY') && (ref($itemtext) eq 'HASH')) { return; } + my ($stumsg,$msgnote); + if ($crstype eq 'Community') { + $stumsg = &mt('Send message to member'); + $msgnote = &mt('Message to member and add to user notes'); + } else { + $stumsg = &mt('Send message to student'); + $msgnote = &mt('Message to student and add to user notes'); + } my %items = ( task_messages => { text => ''.&mt($itemtext->{'task_messages'}).'', input => 'selectbox', options => { - only_student => &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'), @@ -2203,11 +4615,369 @@ sub print_bridgetasks { input => 'radio', }, ); - return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,$ordered,$settings,$rowtotal,$crstype,'bridgetasks',$noedit); +} + +sub ltimenu_titles { + return &Apache::lonlocal::texthash( + fullname => 'Full name', + coursetitle => 'Course title', + role => 'Role', + logout => 'Logout', + grades => 'Grades', + ); +} + +sub print_menuitems { + my ($position,$cdom,$settings,$itemtext,$rowtotal,$crstype,$noedit) = @_; + unless ((ref($settings) eq 'HASH') && (ref($itemtext) eq 'HASH')) { + return; + } + if ($position eq 'top') { + my (%defaultmenu_options,@defaultmenu_order,$addcollection); + if ($settings->{'menucollections'} ne '') { + foreach my $item (split(/;/,$settings->{'menucollections'})) { + my ($num,$value) = split(/\%/,$item); + if ($num =~ /^\d+$/) { + $defaultmenu_options{$num} = $num; + } + } + @defaultmenu_order = sort { $a <=> $b } keys(%defaultmenu_options); + $addcollection = $defaultmenu_order[-1] + 1; + } else { + $addcollection = 1; + } + $defaultmenu_options{$addcollection} = $addcollection; + my %items = ( + 'menudefault' => { + text => ''.&mt($itemtext->{'menudefault'}).'
'. + &mt("(can be overriden in deep-link context)"), + input => 'selectbox', + options => \%defaultmenu_options, + order => \@defaultmenu_order, + nullval => &mt('Standard (all menus shown)'), + }, + ); + return &make_item_rows($cdom,\%items,['menudefault'],$settings,$rowtotal,$crstype,'menuitems',$noedit); + } else { + my %menu; + my $count = 0; + my $next = 1; + my ($datatable,$disabled); + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + + my ($ordered,$cats) = &menuitems_categories(); + my @order = @{$ordered}; + my %categories = %{$cats}; + my %menutitles = &menuitems_titles(); + my %menufields = &menuitems_fields(); + + if ($settings->{'menucollections'} ne '') { + foreach my $item (split(/;/,$settings->{'menucollections'})) { + my ($num,$value) = split(/\%/,$item); + if ($num =~ /^\d+$/) { + my @entries = split(/\&/,$value); + foreach my $entry (@entries) { + my ($name,$fields) = split(/=/,$entry); + $menu{$num}{$name} = $fields; + } + } + } + if (keys(%menu)) { + my @current = sort { $a <=> $b } keys(%menu); + $next += $current[-1]; + foreach my $num (@current) { + my %checked; + my $on = ' checked="checked"'; + foreach my $key (keys(%{$menu{$num}})) { + if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) { + if ($menu{$num}{$key} eq 'y') { + $checked{$key} = $on; + } + } else { + foreach my $field (split(/,/,$menu{$num}{$key})) { + if (exists($menufields{$field})) { + $checked{$field} = $on; + } + } + } + } + if (ref($menu{$num}) eq 'HASH') { + $datatable .= &item_table_row_start(''.$num.'',$count,'','','','LC_left_item'); + foreach my $category (@order) { + if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { + $datatable .= '
'.$menutitles{$category}.''."\n"; + if ($category eq 'text') { + $datatable .= ''.&mt('Header').'
'; + } + foreach my $field (@{$categories{$category}}) { + if ($field eq 'disc') { + $datatable .= '
'.&mt('Footer').'
'; + } + $datatable .= '
'; + } + $datatable .= '
'; + } + } + $datatable .= &item_table_row_end(); + $count ++; + } + } + } + } elsif ($noedit) { + my $text = &mt('No menu collections defined for this course.'); + $datatable .= &item_table_row_start($text,$count); + } + unless ($noedit) { + my $add = ''; + $datatable .= &item_table_row_start($add,$count,'','','','LC_left_item'); + foreach my $category (@order) { + if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { + $datatable .= ''; + } + } + $datatable .= &item_table_row_end(); + $count ++; + } + return $datatable; + } +} + +sub menuitems_abbreviations { + my %briefcats = ( + text => 'pt', + links => 'p', + list => 'ps', + inline => 's', + ); + return %briefcats; +} + +sub menuitems_categories { + my @order = ('shown','text','links','list','inline'); + my %categories = ( + shown => ['top','inline','foot','main'], + text => ['name','role','crs','disc','fdbk'], + links => ['pers','logo','menu','comm','roles','help','logout'], + list => ['about','prefs','port','wish','anno','rss'], + inline => ['cont','grades','chat','people','groups','resv','syll','feeds'], + ); + return (\@order,\%categories); +} + +sub menuitems_titles { + return &Apache::lonlocal::texthash ( + shown => 'Hierarchy', + text => 'Text', + links => 'Header links', + list => 'Drop-down list', + inline => 'Inline links', + ); +} + +sub menuitems_fields { + return &Apache::lonlocal::texthash ( + top => 'Display header', + inline => 'Display inline menu', + foot => 'Display footer', + main => 'Access to main menu', + pers => 'Personal', + logo => 'LON-CAPA', + menu => 'Home', + comm => 'Messages', + roles => 'Roles/Courses', + help => 'Help', + logout => 'Logout', + name => 'Fullname', + crs => 'Course Title', + role => 'Current Role', + disc => 'Discussion', + fdbk => 'Feedback', + about => 'Information', + prefs => 'Preferences', + port => 'Portfolio', + wish => 'Stored Links', + anno => 'Calendar', + rss => 'RSS Feeds', + cont => 'Contents', + grades => 'Grades', + chat => 'Chat', + people => 'People', + groups => 'Groups', + resv => 'Reservations', + syll => 'Syllabus', + feeds => 'Feeds', + ); +} + +sub menucollections_display { + my ($collections) = @_; + my %menu; + my ($ordered,$cats) = &menuitems_categories(); + my @order = @{$ordered}; + my %categories = %{$cats}; + my %menutitles = &menuitems_titles(); + my %menufields = &menuitems_fields(); + foreach my $item (split(/;/,$collections)) { + my ($num,$value) = split(/\%/,$item); + if ($num =~ /^\d+$/) { + my @entries = split(/\&/,$value); + foreach my $entry (@entries) { + my ($name,$fields) = split(/=/,$entry); + $menu{$num}{$name} = $fields; + } + } + } + my $output = ''; + if (keys(%menu)) { + my @current = sort { $a <=> $b } keys(%menu); + foreach my $num (@current) { + my %checked; + foreach my $key (keys(%{$menu{$num}})) { + if (($key eq 'top') || ($key eq 'inline') || ($key eq 'foot') || ($key eq 'main')) { + if ($menu{$num}{$key} eq 'y') { + $checked{$key} = 1; + } + } else { + foreach my $field (split(/,/,$menu{$num}{$key})) { + if (exists($menufields{$field})) { + $checked{$field} = 1; + } + } + } + } + if (ref($menu{$num}) eq 'HASH') { + $output .= '
'.&mt('Collection [_1]',$num).''; + foreach my $category (@order) { + if ((ref($categories{$category}) eq 'ARRAY') && (@{$categories{$category}} > 0)) { + $output .= '
'. + ''.$menutitles{$category}.''."\n"; + if ($category eq 'text') { + $output .= ''.&mt('Header Text').'

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

'; + } + if ($checked{$field}) { + $output .= &Apache::lonhtmlcommon::confirm_success($menufields{$field}); + } else { + $output .= &Apache::lonhtmlcommon::confirm_success($menufields{$field},1); + } + $output .= '
'; + } + $output .= '
'; + } + } + $output .= '
'; + } + } + } + return $output; +} + +sub print_linkprotection { + my ($cdom,$settings,$rowtotal,$crstype,$noedit) = @_; + unless (ref($settings) eq 'HASH') { + return; + } + + my %linkprotection; + my $count = 0; + my $next = 1; + my ($datatable,$disabled,$css_class); + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + my %lt = &linkprot_names(); + my $itemcount = 0; + + if (ref($settings->{'linkprotection'}) eq 'HASH') { + if (keys(%{$settings->{'linkprotection'}})) { + my @current = sort { $a <=> $b } keys(%{$settings->{'linkprotection'}}); + $next += $current[-1]; + for (my $i=0; $i<@current; $i++) { + my $num = $current[$i]; + my %values; + if (ref($settings->{'linkprotection'}->{$num}) eq 'HASH') { + %values = %{$settings->{'linkprotection'}->{$num}}; + } else { + next; + } + my $selected; + if (($values{'version'} eq 'LTI-1p0') || ($values{'version'} eq '')) { + $selected = ' selected="selected"'; + } + $css_class = $itemcount%2?' class="LC_odd_row"':''; + $datatable .= + '
'. + ''; + $itemcount ++; + } + } + } + $css_class = $itemcount%2?' class="LC_odd_row"':''; + $datatable .= ''."\n". + ''; + $$rowtotal ++; + return $datatable;; +} + +sub linkprot_names { + my %lt = &Apache::lonlocal::texthash( + 'version' => 'LTI Version', + 'key' => 'Key', + 'lifetime' => 'Nonce lifetime (s)', + 'name' => 'Launcher Application Name', + 'secret' => 'Secret', + ); + return %lt; } sub print_other { - my ($cdom,$settings,$allitems,$rowtotal) = @_; + my ($cdom,$settings,$allitems,$rowtotal,$crstype,$noedit) = @_; unless ((ref($settings) eq 'HASH') && (ref($allitems) eq 'ARRAY')) { return; } @@ -2228,7 +4998,7 @@ sub print_other { input => 'textbox', size => '30', }; - my $output = &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal); + return &make_item_rows($cdom,\%items,\@ordered,$settings,$rowtotal,$crstype,'other',$noedit); } sub get_other_items { @@ -2245,7 +5015,10 @@ sub get_other_items { 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); } } @@ -2254,15 +5027,24 @@ sub get_other_items { } sub item_table_row_start { - my ($text,$count) = @_; + my ($text,$count,$add_class,$colspan,$leftclass,$rightclass) = @_; 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 ''); + if ($leftclass eq '') { + $leftclass = 'LC_left_item'; + } + if ($rightclass eq '') { + $rightclass = 'LC_right_item'; + } + $output .= ''."\n". + ''; + if ($colspan > 1) { + $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; } sub print_hdrfmt_row { - my ($item,$settings) = @_; + my ($item,$settings,$noedit) = @_; my @curr; my $currnum = 0; my $maxnum = 2; @@ -2452,9 +5364,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; @@ -2514,37 +5426,45 @@ function getIndexByName(item) { ENDJS - $output .= $currstr.&Apache::loncommon::start_data_table(); + $output .= '
'. + ''.&role_checkboxes($cdom,$cnum,$item,$settings,undef,undef,$noedit). '
'; } elsif ($item eq 'pch.users.denied') { - $datatable .= &user_table($cdom,$item,undef, - $settings->{$item},\%lt); + $datatable .= '
'. + &user_table($cdom,$item,undef, + $settings->{$item},\%lt,$noedit); } elsif ($item eq 'allow_limited_html_in_feedback') { - $datatable .= &yesno_radio($item,$settings); + $datatable .= &yesno_radio($item,$settings,undef,undef,undef,$noedit); } elsif ($item eq 'allow_discussion_post_editing') { - $datatable .= &Apache::loncommon::start_data_table(). + $datatable .= '
'. + &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). '
'.&mt('Role').''. &mt('Sections').'
'. + &Apache::loncommon::start_data_table(). + &Apache::loncommon::start_data_table_row(). + '
'.&mt('Sum of likes/dislikes').''.&mt('font-size').''.&mt('font-weight').''.&mt('font-style').''.&mt('Other css').'
'. - &select_sections($item,$role,\@sections,$currsec{$role}). + &select_sections($item,$role,\@sections,$currsec{$role},$noedit). '
'. - &select_sections($item,$role,\@sections,$currsec{$role}). + &select_sections($item,$role,\@sections,$currsec{$role},$noedit). ''.$classtitles->{$cat}.''; + my $selitem = $item; + if ($item eq 'size') { + my ($currsize,$currunit); + if ($curr{'size'} =~ /^(\d+)(px|%)$/) { + ($currsize,$currunit) = ($1,$2); + $curr{'size'} = $currunit; + } + $output .= ''. + ' '; + $selitem = 'unit'; + } + if ((ref($styleitems) eq 'HASH') && (ref($styleitems->{$item}) eq 'ARRAY')) { + $output .= '
'. + ''.$lt{'name'}. + ': '. + (' 'x2). + ''.$lt{'version'}.': '."\n". + (' 'x2). + ''.$lt{'lifetime'}.':'. + '

'. + ''.$lt{'key'}. + ': '. + (' 'x2). + ''.$lt{'secret'}.':'. + ''. + ''. + ''. + '
'."\n". + ''."\n". + ''.&mt('Add').''. + ''.$lt{'name'}. + ': '."\n". + (' 'x2). + ''.$lt{'version'}.': '."\n". + (' 'x2). + ''.$lt{'lifetime'}.': '."\n". + '

'. + ''.$lt{'key'}.': '."\n". + (' 'x2). + ''.$lt{'secret'}.':'. + ' '."\n". + '
'.$text. + ''; } else { - $output .= '
'; } - $output .= ''.$text. - ''; return $output; } @@ -2271,25 +5053,43 @@ sub item_table_row_end { } sub yesno_radio { - my ($item,$settings) = @_; + my ($item,$settings,$unsetdefault,$valueyes,$valueno,$noedit) = @_; my $itemon = ' '; my $itemoff = ' checked="checked" '; + if (($valueyes eq '') && ($valueno eq '')) { + $valueyes = 'yes'; + $valueno = ''; + } if (ref($settings) eq 'HASH') { - if ($settings->{$item} eq 'yes') { + if ($settings->{$item} eq $valueyes) { $itemon = $itemoff; $itemoff = ' '; } + unless (exists($settings->{$item})) { + if ($unsetdefault eq $valueyes) { + $itemon = $itemoff; + $itemoff = ' '; + } + } + } + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; } return ' '. + $itemon.' value="'.$valueyes.'"'.$disabled.' />'.&mt('Yes').' '. ''; + $itemoff.' value="'.$valueno.'"'.$disabled.' />'.&mt('No').''; } sub select_from_options { - my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange) = @_; + my ($item,$order,$options,$curr,$nullval,$multiple,$maxsize,$onchange,$noedit,$id) = @_; my $output; + my $disabled; + if ($noedit) { + $disabled = ' disabled=disabled"'; + } if ((ref($order) eq 'ARRAY') && (ref($options) eq 'HASH')) { $output=''; foreach my $user (sort(@privusers)) { my $hideon = ' checked="checked" '; @@ -2431,19 +5274,88 @@ sub nothidepriv_row { ''. + $hideon.' value=""'.$disabled.' />'.&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,$noedit) = @_; + my $datatable; + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + if (keys(%domains) == 1) { + $datatable = '
'. + &mt("Course's domain is only domain"); + return $datatable; + } + my @excdoms = ($cdom); + my $num = 0; + if ($settings->{$item} eq '') { + $datatable = ''. + &Apache::loncommon::select_dom_form('','checkforpriv_'.$num, + 1,1,undef,undef,\@excdoms, + $noedit); + } else { + my @privdoms = split(/,/,$settings->{$item}); + my %domains=map { $_ => 1; } &Apache::lonnet::all_domains(); + $datatable = '
'. + &Apache::loncommon::start_data_table(); + my $disabled; + if ($noedit) { + $disabled = ' disabled="disabled"'; + } + if (@privdoms > 0) { + foreach my $currdom (@privdoms) { + next unless ($domains{$currdom}); + my $domdesc = &Apache::lonnet::domain($currdom,'description'); + if ($domdesc eq '') { + $domdesc = $currdom; + } + $datatable .= + &Apache::loncommon::start_data_table_row(). + '
'. + &mt('Domain:').' '.$domdesc. + '
'. + '
'. + &mt('Additional domain:'). '
'. + &Apache::loncommon::select_dom_form('','checkforpriv_'.$num,1, + 1,undef,undef,\@excdoms,$noedit). + '

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

'; return $output; } sub position_selector { - my ($pos,$num,$maxnum) = @_; - my $output = ''; for (my $j=1; $j<=$maxnum; $j++) { my $sel = ''; if ($pos == $j) { @@ -2574,14 +5495,22 @@ sub position_selector { } sub substitution_selector { - my ($num,$subst,$limit) = @_; + my ($num,$subst,$limit,$crstype,$disabled) = @_; + my ($stunametxt,$crsidtxt); + if ($crstype eq 'Community') { + $stunametxt = 'member name'; + $crsidtxt = 'community ID', + } else { + $stunametxt = 'student name'; + $crsidtxt = 'course ID', + } my %lt = &Apache::lonlocal::texthash( - n => 'student name', - c => 'course ID', + n => $stunametxt, + c => $crsidtxt, a => 'assignment note', ); my $output .= &mt('Substitution').'
'. - ''; if ($subst eq '') { $output .= ''; } @@ -2595,8 +5524,74 @@ sub substitution_selector { } $output .= '
'.&mt('Size limit').'
'. ''; + '" value="'.$limit.'" size="5"'.$disabled.' />'; return $output; } +sub change_clone { + my ($cdom,$cnum,$clonelist,$oldcloner) = @_; + my $clone_crs = $cnum.':'.$cdom; + if ($cnum && $cdom) { + my $clone_crs = $cnum.':'.$cdom; + my @allowclone; + if ($clonelist =~ /,/) { + @allowclone = split(',',$clonelist); + } else { + $allowclone[0] = $clonelist; + } + foreach my $currclone (@allowclone) { + if (!grep(/^$currclone$/,@$oldcloner)) { + if ($currclone ne '*') { + if ($currclone =~ /:/) { + my ($uname,$udom) = split(/:/,$currclone); + if ($uname && $udom && $uname ne '*') { + if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable'); + if ($currclonecrs{'cloneable'} !~ /\Q$clone_crs\E/) { + if ($currclonecrs{'cloneable'} eq '') { + $currclonecrs{'cloneable'} = $clone_crs; + } else { + $currclonecrs{'cloneable'} .= ','.$clone_crs; + } + &Apache::lonnet::put('environment',\%currclonecrs,$udom,$uname); + } + } + } + } + } + } + } + foreach my $oldclone (@$oldcloner) { + if (!grep(/^\Q$oldclone\E$/,@allowclone)) { + if ($oldclone ne '*') { + if ($oldclone =~ /:/) { + my ($uname,$udom) = split(/:/,$oldclone); + if ($uname && $udom && $uname ne '*' ) { + if (&Apache::lonnet::homeserver($uname,$udom) ne 'no_host') { + my %currclonecrs = &Apache::lonnet::dump('environment',$udom,$uname,'cloneable'); + my %newclonecrs = (); + if ($currclonecrs{'cloneable'} =~ /\Q$clone_crs\E/) { + if ($currclonecrs{'cloneable'} =~ /,/) { + my @currclonecrs = split/,/,$currclonecrs{'cloneable'}; + foreach my $crs (@currclonecrs) { + if ($crs ne $clone_crs) { + $newclonecrs{'cloneable'} .= $crs.','; + } + } + $newclonecrs{'cloneable'} =~ s/,$//; + } else { + $newclonecrs{'cloneable'} = ''; + } + &Apache::lonnet::put('environment',\%newclonecrs,$udom,$uname); + } + } + } + } + } + } + } + } + return; +} + 1; 500 Internal Server Error

Internal Server Error

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

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

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