--- loncom/interface/lonparmset.pm 2006/10/16 10:45:24 1.344 +++ loncom/interface/lonparmset.pm 2007/10/05 17:56:29 1.376.2.1 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set parameters for assessments # -# $Id: lonparmset.pm,v 1.344 2006/10/16 10:45:24 foxr Exp $ +# $Id: lonparmset.pm,v 1.376.2.1 2007/10/05 17:56:29 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -65,18 +65,8 @@ use Apache::lonlocal; use Apache::lonnavmaps; use Apache::longroup; use Apache::lonrss; -use LONCAPA; +use LONCAPA qw(:DEFAULT :match); -# --- Caches local to lonparmset - -my $parmhashid; -my %parmhash; -my $symbsid; -my %symbs; -my $rulesid; -my %rules; - -# --- end local caches ################################################## ################################################## @@ -119,10 +109,11 @@ sub parmval { sub parmval_by_symb { my ($what,$symb,$def,$uname,$udom,$csec,$cgroup,$courseopt)=@_; -# load caches - &cacheparmhash(); - my $useropt=&Apache::lonnet::get_userresdata($uname,$udom); + my $useropt; + if ($uname ne '' && $udom ne '') { + $useropt = &Apache::lonnet::get_userresdata($uname,$udom); + } my $result=''; my @outpar=(); @@ -164,7 +155,7 @@ sub parmval_by_symb { # ------------------------------------------------------ third, check map parms - my $thisparm=$parmhash{$symbparm}; + my $thisparm=&parmhash($symbparm); if (defined($thisparm)) { $outpar[11]=$thisparm; $result=11; } if (defined($$courseopt{$courselevelr})) { @@ -173,7 +164,7 @@ sub parmval_by_symb { } # ------------------------------------------------------ fourth, back to course - if (defined($csec)) { + if ($csec ne '') { if (defined($$courseopt{$seclevel})) { $outpar[9]=$$courseopt{$seclevel}; $result=9; @@ -189,7 +180,7 @@ sub parmval_by_symb { } } # ------------------------------------------------------ fifth, check course group - if (defined($cgroup)) { + if ($cgroup ne '') { if (defined($$courseopt{$grplevel})) { $outpar[6]=$$courseopt{$grplevel}; $result=6; @@ -206,7 +197,7 @@ sub parmval_by_symb { # ---------------------------------------------------------- fifth, check user - if (defined($uname)) { + if ($uname ne '') { if (defined($$useropt{$courselevel})) { $outpar[3]=$$useropt{$courselevel}; $result=3; @@ -225,60 +216,90 @@ sub parmval_by_symb { return ($result,@outpar); } -sub resetparmhash { - $parmhashid=''; -} -sub cacheparmhash { - if ($parmhashid eq $env{'request.course.fn'}) { return; } - my %parmhashfile; - if (tie(%parmhashfile,'GDBM_File', - $env{'request.course.fn'}.'_parms.db',&GDBM_READER(),0640)) { - %parmhash=%parmhashfile; - untie %parmhashfile; - $parmhashid=$env{'request.course.fn'}; - } -} -sub resetsymbcache { - $symbsid=''; +# --- Caches local to lonparmset + + +sub reset_caches { + &resetparmhash(); + &resetsymbcache(); + &resetrulescache(); } -sub symbcache { - my $id=shift; - if ($symbsid ne $env{'request.course.id'}) { - %symbs=(); +{ + my $parmhashid; + my %parmhash; + sub resetparmhash { + undef($parmhashid); + undef(%parmhash); } - unless ($symbs{$id}) { - my $navmap = Apache::lonnavmaps::navmap->new(); - if ($id=~/\./) { - my $resource=$navmap->getById($id); - $symbs{$id}=$resource->symb(); - } else { - my $resource=$navmap->getByMapPc($id); - $symbs{$id}=&Apache::lonnet::declutter($resource->src()); + + sub cacheparmhash { + if ($parmhashid eq $env{'request.course.fn'}) { return; } + my %parmhashfile; + if (tie(%parmhashfile,'GDBM_File', + $env{'request.course.fn'}.'_parms.db',&GDBM_READER(),0640)) { + %parmhash=%parmhashfile; + untie(%parmhashfile); + $parmhashid=$env{'request.course.fn'}; } - $symbsid=$env{'request.course.id'}; } - return $symbs{$id}; -} - -sub resetrulescache { - $rulesid=''; -} + + sub parmhash { + my ($id) = @_; + &cacheparmhash(); + return $parmhash{$id}; + } + } + +{ + my $symbsid; + my %symbs; + sub resetsymbcache { + undef($symbsid); + undef(%symbs); + } + + sub symbcache { + my $id=shift; + if ($symbsid ne $env{'request.course.id'}) { + undef(%symbs); + } + if (!$symbs{$id}) { + my $navmap = Apache::lonnavmaps::navmap->new(); + if ($id=~/\./) { + my $resource=$navmap->getById($id); + $symbs{$id}=$resource->symb(); + } else { + my $resource=$navmap->getByMapPc($id); + $symbs{$id}=&Apache::lonnet::declutter($resource->src()); + } + $symbsid=$env{'request.course.id'}; + } + return $symbs{$id}; + } + } -sub rulescache { - my $id=shift; - if ($rulesid ne $env{'request.course.id'}) { - %rules=(); +{ + my $rulesid; + my %rules; + sub resetrulescache { + undef($rulesid); + undef(%rules); } - unless (defined($rules{$id})) { - my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; - my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; - %rules=&Apache::lonnet::dump('parmdefactions',$dom,$crs); - $rulesid=$env{'request.course.id'}; + + sub rulescache { + my $id=shift; + if ($rulesid ne $env{'request.course.id'} + && !defined($rules{$id})) { + my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; + %rules=&Apache::lonnet::dump('parmdefactions',$dom,$crs); + $rulesid=$env{'request.course.id'}; + } + return $rules{$id}; } - return $rules{$id}; } sub preset_defaults { @@ -344,7 +365,6 @@ sub storeparm { # - new type # - username # - userdomain - my %recstack; sub storeparm_by_symb { my ($symb,$spnam,$snum,$nval,$ntype,$uname,$udom,$csec,$recflag,$cgroup)=@_; @@ -553,7 +573,8 @@ sub valout { } $result=~s/\s+$//; } elsif (&isdateparm($type)) { - $result = localtime($value).&date_sanity_info($value); + $result = &Apache::lonlocal::locallocaltime($value). + &date_sanity_info($value); } else { $result = $value; } @@ -933,57 +954,66 @@ sub extractResourceInformation { $$typep{$id}=$1; $$keyp{$id}=''; $$uris{$id}=$srcf; - foreach (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys'))) { - if ($_=~/^parameter\_(.*)/) { - my $key=$_; + foreach my $key (split(/\,/,&Apache::lonnet::metadata($srcf,'allpossiblekeys'))) { + next if ($key!~/^parameter_/); + # Hidden parameters - if (&Apache::lonnet::metadata($srcf,$key.'.hidden') eq 'parm') { - next; - } - my $display= &Apache::lonnet::metadata($srcf,$key.'.display'); - my $name=&Apache::lonnet::metadata($srcf,$key.'.name'); - my $part= &Apache::lonnet::metadata($srcf,$key.'.part'); + next if (&Apache::lonnet::metadata($srcf,$key.'.hidden') eq 'parm'); # # allparms is a hash of parameter names # + my $name=&Apache::lonnet::metadata($srcf,$key.'.name'); + if (!exists($$allparms{$name}) || $$allparms{$name} =~ m/^\s*$/ ) { + my $display= &Apache::lonnet::metadata($srcf,$key.'.display'); my $parmdis = $display; $parmdis =~ s/\[Part.*$//g; - $$allparms{$name}=$parmdis; - $$defkeytype{$name}=&Apache::lonnet::metadata($srcf,$key.'.type'); + $$allparms{$name}=$parmdis; + if (ref($defkeytype)) { + $$defkeytype{$name}= + &Apache::lonnet::metadata($srcf,$key.'.type'); + } + } + # # allparts is a hash of all parts # - $$allparts{$part} = "Part: $part"; + my $part= &Apache::lonnet::metadata($srcf,$key.'.part'); + $$allparts{$part} = "Part: $part"; # # Remember all keys going with this resource # - if ($$keyp{$id}) { - $$keyp{$id}.=','.$key; - } else { - $$keyp{$id}=$key; - } + if ($$keyp{$id}) { + $$keyp{$id}.=','.$key; + } else { + $$keyp{$id}=$key; + } # # Put in order # - unless ($$keyorder{$key}) { - $$keyorder{$key}=$keyordercnt; - $keyordercnt++; - } - + unless ($$keyorder{$key}) { + $$keyorder{$key}=$keyordercnt; + $keyordercnt++; } } - $$mapp{$id}= - &Apache::lonnet::declutter($resource->enclosing_map_src()); - $$mapp{$mapid}=$$mapp{$id}; - $$allmaps{$mapid}=$$mapp{$id}; - if ($mapid eq '1') { - $$maptitles{$mapid}='Main Course Documents'; + + + if (!exists($$mapp{$mapid})) { + $$mapp{$id}= + &Apache::lonnet::declutter($resource->enclosing_map_src()); + $$mapp{$mapid}=$$mapp{$id}; + $$allmaps{$mapid}=$$mapp{$id}; + if ($mapid eq '1') { + $$maptitles{$mapid}='Main Course Documents'; + } else { + $$maptitles{$mapid}= + &Apache::lonnet::gettitle($$mapp{$id}); + } + $$maptitles{$$mapp{$id}}=$$maptitles{$mapid}; + $$symbp{$mapid}=$$mapp{$id}.'___(all)'; } else { - $$maptitles{$mapid}=&Apache::lonnet::gettitle(&Apache::lonnet::clutter($$mapp{$id})); + $$mapp{$id} = $$mapp{$mapid}; } - $$maptitles{$$mapp{$id}}=$$maptitles{$mapid}; $$symbp{$id}=&Apache::lonnet::encode_symb($$mapp{$id},$resid,$srcf); - $$symbp{$mapid}=$$mapp{$id}.'___(all)'; } } @@ -1070,7 +1100,9 @@ ENDSCRIPT if ($$pscat[0] eq "all" || grep $_ eq $tempkey, @{$pscat}) { $r->print(' checked'); } - $r->print('>'.$$allparms{$tempkey}.''); + $r->print('>'.($$allparms{$tempkey}=~/\S/ ? $$allparms{$tempkey} + : $tempkey) + .''); $cnt++; if ($cnt==3) { $r->print("\n"); @@ -2033,6 +2065,29 @@ sub crsenv { if ($name =~ /^default_enrollment_(start|end)_date$/) { $value=&Apache::lonhtmlcommon::get_date_from_form($name.'_value'); } + # + # Deal with the emails + if ($name =~ /\.email$/) { + foreach my $specifier (split(',',$value)) { + my ($user,$sections_or_groups)= + ($specifier=~/^([^\(]+)\(([^\)]+)\)/); + if (!$sections_or_groups) { + $user = $specifier; + } + my ($name,$domain) = split(':',$user); + if (!defined($user) || !defined($domain)) { + $setoutput.= '
'. + &mt("Invalid email address specified, address must be of the form username:domain what was specified was ([_1])",$user). + ''; + undef($value); + } elsif (&Apache::lonnet::homeserver($user,$domain) eq 'no_host') { + $setoutput.= '
'. + &mt("Invalid email address specified, user [_1] is unknown.",$name). + ''; + undef($value); + } + } + } # Get existing cloners my @oldcloner = (); if ($name eq 'cloners') { @@ -2046,13 +2101,13 @@ sub crsenv { # # Let the user know we made the changes if ($name && defined($value)) { - my $failed_cloners; + my %failed_cloners; if ($name eq 'cloners') { $value =~ s/\s//g; $value =~ s/^,//; $value =~ s/,$//; # check requested clones are valid users. - $failed_cloners = &check_cloners(\$value,\@oldcloner); + %failed_cloners = &check_cloners(\$value,\@oldcloner); } my $put_result = &Apache::lonnet::put('environment', {$name=>$value},$dom,$crs); @@ -2069,17 +2124,34 @@ sub crsenv { $setoutput.=&mt('Unable to set').' '.$name.' '.&mt('to'). ' '.$value.' '.&mt('due to').' '.$put_result.'.
'; } - if (($name eq 'cloners') && ($failed_cloners)) { - $setoutput.= &mt('Unable to include').' - '.$failed_cloners.', '. - &mt('reason').' - '.&mt('LON-CAPA user(s) do(es) not exist'). - '.
'.&mt('Please '). - ' '. - &mt('add the user(s)').', '. - &mt('and then return to the '). - ''. - &mt('Course Parameters page').' '. - &mt('to add the new user(s) to the list of possible cloners'). - '.
'; + if (($name eq 'cloners') && (keys(%failed_cloners) > 0)) { + $setoutput.= &mt('Unable to include').': '; + my @fails; + my $num = 0; + if (defined($failed_cloners{'format'})) { + $fails[$num] .= ''.$failed_cloners{'format'}. + ', '.&mt('reason').' - '. + &mt('Invalid format'); + $num ++; + } + if (defined($failed_cloners{'domain'})) { + $fails[$num] .= ''.$failed_cloners{'domain'}. + ', '.&mt('reason').' - '. + &mt('Domain does not exist'); + $num ++; + } + if (defined($failed_cloners{'newuser'})) { + $fails[$num] .= ''.$failed_cloners{'newuser'}. ', '.&mt('reason').' - '. + &mt('LON-CAPA user(s) do(es) not exist.'). + '.
'.&mt('Please '). + ' '. + &mt('add the user(s)').', '. + &mt('and then return to the '). + ''. + &mt('Course Parameters page').' '. + &mt('to add the new user(s) to the list of possible cloners'); + } + $setoutput .= join(';  ',@fails).'.
'; } } } @@ -2110,9 +2182,13 @@ sub crsenv { 'courseid' => ''.&mt('Course ID or number'). '
'. '('.&mt('internal').', '.&mt('optional').')', - 'cloners' => ''.&mt('Users allowed to clone course').'
(user:domain,user:domain)
'.&mt('Users with active Course Coordinator role in the course automatically have the right to clone it, and can be omitted from list.'), + 'cloners' => ''.&mt('Users allowed to clone course').'
(user:domain,user:domain,*:domain)
'.&mt('Users with active Course Coordinator role in course are permitted to clone and need not be included.
+Use *:domain to allow course to be cloned by anyone in the specified domain.
+Use * to allow unrestricted cloning in all domains.'), 'grading' => ''.&mt('Grading').'
'. '"standard", "external", or "spreadsheet" '.&Apache::loncommon::help_open_topic('GradingOptions'), + 'task_grading' => ''.&mt('Bridge Task Grading').'
'. + &mt('Instructors and TAs in sections, when grading bridge tasks, should be allowed to grade other sections, "[_1]" they are allowed (this is the default), "[_2]" no, they can only grade their own section','any','section'), 'default_xml_style' => ''.&mt('Default XML Style File').' '. ' ''.&mt('Feedback Addresses for Resource Content Question'). '
(user:domain,'. 'user:domain(section;section;...;*;...),...)', + 'question.email.text' => ''.&mt('Custom Text for Resource Content Question Option in Feedback'). + '', 'comment.email' => ''.&mt('Feedback Addresses for Course Content Comments').'
'. '(user:domain,user:domain(section;section;...;*;...),...)', + 'comment.email.text' => ''.&mt('Custom Text for Course Content Option in Feedback'). + '', 'policy.email' => ''.&mt('Feedback Addresses for Course Policy').''. '
(user:domain,user:domain(section;section;...;*;...),...)', + 'policy.email.text' => ''.&mt('Custom Text for Course Policy Option in Feedback'). + '', 'hideemptyrows' => ''.&mt('Hide Empty Rows in Spreadsheets').'
'. '('.&mt('"[_1]" for default hiding','yes').')', 'pageseparators' => ''.&mt('Visibly Separate Items on Pages').'
'. '('.&mt('"[_1]" for visible separation','yes').', '. &mt('changes will not show until next login').')', 'student_classlist_view' => ''.&mt('Allow students to view classlist.').''.&mt('("all":students can view all sections,"section":students can only view their own section.blank or "disabled" prevents student view.'), - + 'student_classlist_portfiles' => ''.&mt('Include link to accessible portfolio files').'
'.&mt('"[_1]" for link to each a listing of each student\'s files.','yes'), + 'student_classlist_opt_in' => ''.&mt("Student's agreement needed for listing in student-viewable roster").'
'.&mt('"[_1]" to require students to opt-in to listing in the roster (on the roster page).','yes'), 'plc.roles.denied'=> ''.&mt('Disallow live chatroom use for Roles'). '
"st": '. &mt('student').', "ta": '. @@ -2193,10 +2276,7 @@ sub crsenv { ' Tabloid [11x17 in], Executive [7 1/2x10 in], A2 [420x594 mm],'. ' A3 [297x420 mm], A4 [210x297 mm], A5 [148x210 mm], A6 [105x148 mm])', 'print_header_format' - => 'Print header format; substitutions: %n student name %c course id %a assignment note, numbers after the % limit the field size', - 'anonymous_quiz' - => ''.&mt('Anonymous quiz/exam').'
'. - ' ('.&mt('yes').' '.&mt('to avoid print students names').' )', + => &mtn(' Print header format; substitutions : %n student name %c course id %a assignment note, numbers after the % limit the field size.').'', 'default_enrollment_start_date' => ''.&mt('Default beginning date for student access.').'', 'default_enrollment_end_date' => ''.&mt('Default ending date for student access.').'', 'nothideprivileged' => ''.&mt('Privileged users that should not be hidden on staff listings').''. @@ -2206,7 +2286,7 @@ sub crsenv { => ''.&mt('Disable display of problem receipts').'
'. ' ('.&mt('"[_1]" to disable, anything else if not','yes').')', 'task_messages' - => ''.&mt('Send message to student when clicking Done on Tasks. [_1] to send a message only to student, [_2] to send message to student and add record to user information page for instructors. Leave blank to disable.','only_student','student_and_user_notes_screen').'', + => ''.&mt('Send message to student when clicking Done on Tasks').'
('.&mt('[_1] to send a message only to student, [_2] to send message to student and add record to user information page for instructors. Leave blank to disable.','only_student','student_and_user_notes_screen').')', 'disablesigfigs' => ''.&mt('Disable checking of Significant Figures').'
'. ' ('.&mt('"[_1]" to disable, anything else if not','yes').')', @@ -2216,13 +2296,18 @@ sub crsenv { 'externalsyllabus' => ''.&mt('URL of Syllabus (not using internal handler)').'', 'tthoptions' - => ''.&mt('Default set of options to pass to tth/m when converting tex').'' + => ''.&mt('Default set of options to pass to tth/m when converting tex').'', + + 'texengine' + => ''.&mt('Force all students in the course to use a specific math rendering engine.').'
'.&mt('(Valid options are [_1].)','"tth", "jsMath", "mimetex"').'', ); my @Display_Order = ('url','description','courseid','cloners','grading', 'externalsyllabus', 'default_xml_style','pageseparators', - 'question.email','comment.email','policy.email', + 'question.email','question.email.text','comment.email','comment.email.text','policy.email','policy.email.text', 'student_classlist_view', + 'student_classlist_opt_in', + 'student_classlist_portfiles', 'plc.roles.denied','plc.users.denied', 'pch.roles.denied','pch.users.denied', 'allow_limited_html_in_feedback', @@ -2243,9 +2328,10 @@ sub crsenv { 'default_enrollment_start_date', 'default_enrollment_end_date', 'tthoptions', + 'texengine', 'disablesigfigs', 'disableexampointprint', - 'task_messages' + 'task_messages','task_grading', ); foreach my $parameter (sort(keys(%values))) { unless (($parameter =~ m/^internal\./)||($parameter =~ m/^metadata\./)) { @@ -2326,7 +2412,7 @@ $start_header_row $end_header_row $output $end_table - + $end_page ENDENV @@ -2363,8 +2449,7 @@ sub readdata { my $classlist=&Apache::loncoursedata::get_classlist(); foreach (keys %$classlist) { - # the following undefs are for 'domain', and 'username' respectively. - if ($_=~/^(\w+)\:(\w+)$/) { + if ($_=~/^($match_username)\:($match_domain)$/) { my ($tuname,$tudom)=($1,$2); my $useropt=&Apache::lonnet::get_userresdata($tuname,$tudom); foreach my $userkey (keys %{$useropt}) { @@ -2409,11 +2494,11 @@ sub storedata { $tkey.'.type' => $typeof}, $tudom,$tuname) eq 'ok') { &log_parmset({$tkey=>$data,$tkey.'.type' => $typeof},0,$tuname,$tudom); - $r->print('
'.&mt('Stored modified parameter for').' '. + $r->print('
'.&mt('Saved modified parameter for').' '. &Apache::loncommon::plainname($tuname,$tudom)); } else { $r->print('
'. - &mt('Error storing parameters').'
'); + &mt('Error saving parameters').''); } &Apache::lonnet::devalidateuserresdata($tuname,$tudom); } else { @@ -2443,10 +2528,10 @@ sub storedata { $tkey.'.type' => $typeof}, $tudom,$tuname) eq 'ok') { &log_parmset({$tkey=>$data,$tkey.'.type' => $typeof},0,$tuname,$tudom); - $r->print('
'.&mt('Stored modified date for').' '.&Apache::loncommon::plainname($tuname,$tudom)); + $r->print('
'.&mt('Saved modified date for').' '.&Apache::loncommon::plainname($tuname,$tudom)); } else { $r->print('
'. - &mt('Error storing parameters').'
'); + &mt('Error saving parameters').''); } &Apache::lonnet::devalidateuserresdata($tuname,$tudom); } else { @@ -2475,10 +2560,10 @@ sub storedata { if ($putentries) { if (&Apache::lonnet::put('resourcedata',\%newdata,$dom,$crs) eq 'ok') { &log_parmset(\%newdata,0); - $r->print('

'.&mt('Stored [_1] parameter(s)',$putentries/2).'

'); + $r->print('

'.&mt('Saved [_1] parameter(s)',$putentries/2).'

'); } else { $r->print('
'. - &mt('Error storing parameters').'
'); + &mt('Error saving parameters').''); } &Apache::lonnet::devalidatecourseresdata($crs,$dom); } @@ -2486,7 +2571,7 @@ sub storedata { sub extractuser { my $key=shift; - return ($key=~/^$env{'request.course.id'}.\[useropt\:(\w+)\:(\w+)\]\./); + return ($key=~/^$env{'request.course.id'}.\[useropt\:($match_username)\:($match_domain)\]\./); } sub listdata { @@ -2544,7 +2629,7 @@ sub listdata { my $section=&mt('All Students'); if ($middle=~/^\[(.*)\]/) { my $issection=$1; - if ($issection=~/^useropt\:(\w+)\:(\w+)/) { + if ($issection=~/^useropt\:($match_username)\:($match_domain)/) { $section=&mt('User').": ".&Apache::loncommon::plainname($1,$2); } else { $section=&mt('Group/Section').': '.$issection; @@ -2682,8 +2767,8 @@ ENDOVER my @selected_sections = &Apache::loncommon::get_env_multiple('form.Section'); @selected_sections = ('all') if (! @selected_sections); - foreach (@selected_sections) { - if ($_ eq 'all') { + foreach my $sec (@selected_sections) { + if ($sec eq 'all') { @selected_sections = ('all'); } } @@ -2703,6 +2788,9 @@ ENDOVER \%mapp, \%symbp,\%maptitles,\%uris, \%keyorder,\%defkeytype); + if (grep {$_ eq 'all'} (@psprt)) { + @psprt = keys(%allparts); + } # Menu to select levels, etc $r->print(' @@ -2759,7 +2847,7 @@ ENDOVER &listdata($r,$resourcedata,$listdata,$sortorder); } $r->print(&tableend(). - ((($env{'form.store'}) || ($env{'form.dis'}))?'

':''). + ((($env{'form.store'}) || ($env{'form.dis'}))?'

':''). ''.&Apache::loncommon::end_page()); } @@ -2875,6 +2963,11 @@ ENDOVER '' ); $r->print(''); } @@ -2918,7 +3011,7 @@ sub parse_key { $data{'scope_type'} = 'all'; if ($middle=~/^\[(.*)\]/) { $data{'scope'} = $1; - if ($data{'scope'}=~/^useropt\:(\w+)\:(\w+)/) { + if ($data{'scope'}=~/^useropt\:($match_username)\:($match_domain)/) { $data{'scope_type'} = 'user'; $data{'scope'} = [$1,$2]; } else { @@ -2935,7 +3028,6 @@ sub parse_key { $data{'realm_type'} = 'folder'; $data{'realm_title'} = &Apache::lonnet::gettitle($data{'realm'}); ($data{'realm_exists'}) = &Apache::lonnet::is_on_map($data{'realm'}); - &Apache::lonnet::logthis($1." siad ". $data{'realm_exists'} ); } elsif ($middle) { $data{'realm'} = $middle; $data{'realm_type'} = 'symb'; @@ -2982,48 +3074,63 @@ where $action is add or drop, and $clone user for whom cloning ability is to be changed in course. =cut - + ################################################## ################################################## sub extract_cloners { my ($clonelist,$allowclone) = @_; if ($clonelist =~ /,/) { - @{$allowclone} = split/,/,$clonelist; + @{$allowclone} = split(/,/,$clonelist); } else { $$allowclone[0] = $clonelist; } } - sub check_cloners { my ($clonelist,$oldcloner) = @_; - my ($clean_clonelist,$disallowed); + my ($clean_clonelist,%disallowed); my @allowclone = (); &extract_cloners($$clonelist,\@allowclone); foreach my $currclone (@allowclone) { - if (!grep/^$currclone$/,@$oldcloner) { - my ($uname,$udom) = split/:/,$currclone; - if ($uname && $udom) { - if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { - $disallowed .= $currclone.','; + if (!grep(/^\Q$currclone\E$/,@$oldcloner)) { + if ($currclone eq '*') { + $clean_clonelist .= $currclone.','; + } else { + my ($uname,$udom) = split(/:/,$currclone); + if ($uname eq '*') { + if ($udom =~ /^$match_domain$/) { + if (!&Apache::lonnet::domain($udom)) { + $disallowed{'domain'} .= $currclone.','; + } else { + $clean_clonelist .= $currclone.','; + } + } else { + $disallowed{'format'} .= $currclone.','; + } + } elsif ($currclone !~/^($match_username)\:($match_domain)$/) { + $disallowed{'format'} .= $currclone.','; } else { - $clean_clonelist .= $currclone.','; + if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { + $disallowed{'newuser'} .= $currclone.','; + } else { + $clean_clonelist .= $currclone.','; + } } } } else { $clean_clonelist .= $currclone.','; } } - if ($disallowed) { - $disallowed =~ s/,$//; + foreach my $key (keys(%disallowed)) { + $disallowed{$key} =~ s/,$//; } if ($clean_clonelist) { $clean_clonelist =~ s/,$//; } $$clonelist = $clean_clonelist; - return $disallowed; -} + return %disallowed; +} sub change_clone { my ($clonelist,$oldcloner) = @_; @@ -3036,43 +3143,47 @@ sub change_clone { my @allowclone; &extract_cloners($clonelist,\@allowclone); foreach my $currclone (@allowclone) { - if (!grep/^$currclone$/,@$oldcloner) { - ($uname,$udom) = split/:/,$currclone; - if ($uname && $udom) { - unless (&Apache::lonnet::homeserver($uname,$udom) eq '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; + if (!grep(/^$currclone$/,@$oldcloner)) { + if ($currclone ne '*') { + ($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); } - &Apache::lonnet::put('environment',\%currclonecrs,$udom,$uname); } } } } } foreach my $oldclone (@$oldcloner) { - if (!grep/^$oldclone$/,@allowclone) { - ($uname,$udom) = split/:/,$oldclone; - if ($uname && $udom) { - unless (&Apache::lonnet::homeserver($uname,$udom) eq '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 (@currclonecrs) { - unless ($_ eq $clone_crs) { - $newclonecrs{'cloneable'} .= $_.','; + if (!grep(/^\Q$oldclone\E$/,@allowclone)) { + if ($oldclone ne '*') { + ($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'} = ''; } - $newclonecrs{'cloneable'} =~ s/,$//; - } else { - $newclonecrs{'cloneable'} = ''; + &Apache::lonnet::put('environment',\%newclonecrs,$udom,$uname); } - &Apache::lonnet::put('environment',\%newclonecrs,$udom,$uname); } } } @@ -3111,6 +3222,7 @@ ENDMAINFORMHEAD my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'}; my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $vgr = &Apache::lonnet::allowed('vgr',$env{'request.course.id'}); + my $mgr = &Apache::lonnet::allowed('mgr',$env{'request.course.id'}); my @menu = ( { divider=>'Settings for Your Course', @@ -3128,6 +3240,11 @@ ENDMAINFORMHEAD url => '/adm/slotrequest?command=showslots', permission => $vgr, }, + { text => 'Reset Student Access Times', + url => '/adm/helper/resettimes.helper', + permission => $mgr, + }, + { text => 'Set Parameter Setting Default Actions', action => 'setdefaults', permission => $parm_permission, @@ -3197,21 +3314,47 @@ sub output_row { $values = ''; } if (!($options =~ /deleted/)) { - $output.=''.$field_text.':'; - $output.='
'; - my @options= ( ['active', 'Show to student'], - ['onlyone','Student may select only one choice'], - ['stuadd', 'Student may type choices']); + ['stuadd', 'Provide text area for students to type catalog information'], + ['choices','Provide choices for students to select from']); +# ['onlyone','Student may select only one choice']); if ($added_flag) { push @options,['deleted', 'Delete Metadata Field']; } + $output = &Apache::loncommon::start_data_table_row(); + $output .= ''; + $output .= &Apache::loncommon::end_data_table_row(); foreach my $opt (@options) { my $checked = ($options =~ m/$opt->[0]/) ? ' checked="checked" ' : '' ; - $output.=(' 'x5).'
'; - } + $output .= &Apache::loncommon::continue_data_table_row(); + $output .= ''; + $output .= &Apache::loncommon::end_data_table_row(); + } + $output .= &Apache::loncommon::continue_data_table_row(); + $output .= ''; + $output .= &Apache::loncommon::end_data_table_row(); + my $multiple_checked; + my $single_checked; + if ($options =~ m/onlyone/) { + $multiple_checked = ""; + $single_checked = " CHECKED "; + } else { + $multiple_checked = " CHECKED "; + $single_checked = ""; + } + $output .= &Apache::loncommon::continue_data_table_row(); + $output .= ''; + $output .= &Apache::loncommon::end_data_table_row(); + $output .= &Apache::loncommon::continue_data_table_row(); + $output .= ''; + $output .= &Apache::loncommon::end_data_table_row(); } return ($output); } @@ -3221,7 +3364,11 @@ sub order_meta_fields { my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; $r->print(&Apache::loncommon::start_page('Order Metadata Fields')); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Order Metadata Fields')); + &Apache::lonhtmlcommon::add_breadcrumb + ({href=>"/adm/parmset?action=setrestrictmeta", + text=>"Restrict Metadata"}, + {text=>"Order Metadata"}); + $r->print(&Apache::lonhtmlcommon::breadcrumbs('Order Metadata')); if ($env{'form.storeorder'}) { my $newpos = $env{'form.newpos'} - 1; my $currentpos = $env{'form.currentpos'} - 1; @@ -3258,7 +3405,7 @@ sub order_meta_fields { {'metadata.addedorder'=>$ordered_fields},$dom,$crs); &Apache::lonnet::appenv('course.'.$env{'request.course.id'}.'.metadata.addedorder' => $ordered_fields); } - my $fields = &get_added_meta_fieldnames(); + my $fields = &get_added_meta_fieldnames($env{'request.course.id'}); my $ordered_fields; my @fields_in_order = split /,/,$env{'course.'.$env{'request.course.id'}.'.metadata.addedorder'}; if (!@fields_in_order) { @@ -3293,6 +3440,13 @@ sub order_meta_fields { $r->print('
'); + my $display_value = $resourcedata->{$thiskey}; + if (&isdateparm($resourcedata->{$thiskey.'.type'})) { + $display_value = + &Apache::lonlocal::locallocaltime($display_value); + } $r->print(&mt('Parameter: "[_1]" with value: "[_2]"', &standard_parameter_names($data{'parameter_name'}), $resourcedata->{$thiskey})); @@ -2899,7 +2992,7 @@ ENDOVER $r->print(&mt('Resource: [_1]
   with ID: [_2]
   in folder [_3]', $url,$resid,$map)); } - $r->print(&mt('Part: [_1]',$data{'parameter_part'})); + $r->print('
   '.&mt('Part: [_1]',$data{'parameter_part'})); $r->print('
'.(' ' x 5).' '.(' ' x 10).''.(' ' x 10).''.(' ' x 10).'
'); return 'ok'; } +sub continue { + my $output; + $output .= '
'; + $output .= ''; + $output .= ''; + return ($output); +} sub addmetafield { my ($r)=@_; $r->print(&Apache::loncommon::start_page('Add Metadata Field')); @@ -3300,7 +3454,7 @@ sub addmetafield { my $dom = $env{'course.'.$env{'request.course.id'}.'.domain'}; my $crs = $env{'course.'.$env{'request.course.id'}.'.num'}; if (exists($env{'form.undelete'})) { - my @meta_fields = &Apache::loncommon::get_env_multiple('form.undelete'); + my @meta_fields = &Apache::loncommon::get_env_multiple('form.undeletefield'); foreach my $meta_field(@meta_fields) { my $options = $env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.options'}; $options =~ s/deleted//; @@ -3310,9 +3464,7 @@ sub addmetafield { $r->print('Undeleted Metadata Field '.$env{'course.'.$env{'request.course.id'}.'.metadata.'.$meta_field.'.added'}." with result ".$put_result.'
'); } - $r->print(''); - $r->print(''); - $r->print(''); + $r->print(&continue()); } elsif (exists($env{'form.fieldname'})) { my $meta_field = $env{'form.fieldname'}; my $display_field = $env{'form.fieldname'}; @@ -3322,14 +3474,15 @@ sub addmetafield { {'metadata.'.$meta_field.'.values'=>"", 'metadata.'.$meta_field.'.added'=>"$display_field", 'metadata.'.$meta_field.'.options'=>""},$dom,$crs); - $r->print('Added new Metadata Field '.$env{'form.fieldname'}." with result ".$put_result); + $r->print('Added new Metadata Field '.$env{'form.fieldname'}." with result ".$put_result.'
'); + $r->print(&continue()); } else { - my $fields = &get_deleted_meta_fieldnames(); + my $fields = &get_deleted_meta_fieldnames($env{'request.course.id'}); if ($fields) { $r->print('You may undelete previously deleted fields.
Check those you wish to undelete and click Undelete.
'); $r->print(''); foreach my $key(keys(%$fields)) { - $r->print(''.$$fields{$key}.'
print(''.$$fields{$key}.'
print(''); $r->print('
'); @@ -3337,8 +3490,8 @@ sub addmetafield { $r->print('
Or you may enter a new metadata field name.
print('
'); $r->print(''); - $r->print('
'); } + $r->print(''); } sub setrestrictmeta { my ($r)=@_; @@ -3363,7 +3516,10 @@ sub setrestrictmeta { if ($env{'form.'.$meta_field.'_stuadd'}) { $options.='stuadd,'; } - if ($env{'form.'.$meta_field.'_onlyone'}) { + if ($env{'form.'.$meta_field.'_choices'}) { + $options.='choices,'; + } + if ($env{'form.'.$meta_field.'_onlyone'} eq 'single') { $options.='onlyone,'; } if ($env{'form.'.$meta_field.'_active'}) { @@ -3372,7 +3528,6 @@ sub setrestrictmeta { if ($env{'form.'.$meta_field.'_deleted'}) { $options.='deleted,'; } - my $name = $save_field; $put_result = &Apache::lonnet::put('environment', {'metadata.'.$meta_field.'.options'=>$options, @@ -3387,28 +3542,35 @@ sub setrestrictmeta { # Get the default metadata fields my %metadata_fields = &Apache::lonmeta::fieldnames('portfolio'); # Now get possible added metadata fields - my $added_metadata_fields = &get_added_meta_fieldnames(\%metadata_fields); + my $added_metadata_fields = &get_added_meta_fieldnames($env{'request.course.id'}); + my $row_alt = 1; + $output .= &Apache::loncommon::start_data_table(); foreach my $field (sort(keys(%metadata_fields))) { if ($field ne 'courserestricted') { + $row_alt = $row_alt ? 0 : 1; $output.= &output_row($r, $field, $metadata_fields{$field}); } } + my $buttons = (< +
+
+ +
+
+
+ +ENDButtons my $added_flag = 1; foreach my $field (sort(keys(%$added_metadata_fields))) { - $output.= &output_row($r, $field, $$added_metadata_fields{$field},$added_flag); + $row_alt = $row_alt ? 0 : 1; + $output.= &output_row($r, $field, $$added_metadata_fields{$field},$added_flag, $row_alt); } + $output .= &Apache::loncommon::end_data_table(); $r->print(< -

$output - -


-
- -
-
-
- + $buttons
ENDenv $r->print(&Apache::loncommon::end_page()); @@ -3416,9 +3578,10 @@ ENDenv } ################################################## sub get_added_meta_fieldnames { + my ($cid) = @_; my %fields; foreach my $key(%env) { - if ($key =~ m/\.metadata\.(.+)\.added$/) { + if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) { my $field_name = $1; my ($display_field_name) = $env{$key}; $fields{$field_name} = $display_field_name; @@ -3427,10 +3590,10 @@ sub get_added_meta_fieldnames { return \%fields; } sub get_deleted_meta_fieldnames { + my ($cid) = @_; my %fields; - my ($default_fields) = @_; foreach my $key(%env) { - if ($key =~ m/\.metadata\.(.+)\.added$/) { + if ($key =~ m/\Q$cid\E\.metadata\.(.+)\.added$/) { my $field_name = $1; if ($env{'course.'.$env{'request.course.id'}.'.metadata.'.$field_name.'.options'} =~ m/deleted/) { my ($display_field_name) = $env{$key}; @@ -3595,7 +3758,7 @@ ENDYESNO } $r->print(&Apache::loncommon::end_data_table(). "\n\n". + &mt('Save Rules')."' />\n". &Apache::loncommon::end_page()); return; } @@ -3692,13 +3855,7 @@ sub parm_change_log { \%saveable_parameters); &Apache::loncommon::restore_course_settings('parameter_log', \%saveable_parameters); - if (!$env{'form.show'}) { $env{'form.show'}=10; } - - my $countselect = - &Apache::lonmeta::selectbox('show',$env{'form.show'},undef, - (&mt('all'),10,20,50,100,1000,10000)); - - $r->print(''.&mt('[_1] Records',$countselect).''. + $r->print(&Apache::loncommon::display_filter(). ''. ''); @@ -3710,7 +3867,25 @@ sub parm_change_log { &mt('Parameter').''.&mt('Part').''.&mt('New Value').''.&mt('Announce').''. &Apache::loncommon::end_data_table_header_row()); my $shown=0; - foreach my $id (sort { $parmlog{$b}{'exe_time'}<=>$parmlog{$a}{'exe_time'} } (keys(%parmlog))) { + my $folder=''; + if ($env{'form.displayfilter'} eq 'currentfolder') { + my $last=''; + if (tie(my %hash,'GDBM_File',$env{'request.course.fn'}.'_symb.db', + &GDBM_READER(),0640)) { + $last=$hash{'last_known'}; + untie(%hash); + } + if ($last) { ($folder) = &Apache::lonnet::decode_symb($last); } + } + foreach my $id (sort + { + if ($parmlog{$b}{'exe_time'} ne $parmlog{$a}{'exe_time'}) { + return $parmlog{$b}{'exe_time'} <=>$parmlog{$a}{'exe_time'} + } + my $aid = (split('00000',$a))[-1]; + my $bid = (split('00000',$b))[-1]; + return $bid<=>$aid; + } (keys(%parmlog))) { my @changes=keys(%{$parmlog{$id}{'logentry'}}); my $count = 0; my $time = @@ -3731,7 +3906,6 @@ sub parm_change_log { $parmlog{$id}{'exe_udom'}); } my $row_start=&Apache::loncommon::start_data_table_row(); - $r->print($row_start); my $makenewrow=0; my %istype=(); my $output; @@ -3741,6 +3915,11 @@ sub parm_change_log { !exists($parmlog{$id}{'logentry'}{$changed.'.type'})); my ($realm,$section,$parmname,$part,$what,$middle,$uname,$udom,$issection,$realmdescription)= &components($changed,$parmlog{$id}{'uname'},$parmlog{$id}{'udom'},undef,undef,$typeflag); + if ($env{'form.displayfilter'} eq 'currentfolder') { + if ($folder) { + if ($middle!~/^\Q$folder\E/) { next; } + } + } if ($typeflag) { $istype{$parmname}=$value; if (!$env{'form.includetypes'}) { next; } @@ -3793,13 +3972,20 @@ sub parm_change_log { } $output .= ''.&Apache::loncommon::end_data_table_row(); } - $r->print(''.$time.' + if ($env{'form.displayfilter'} eq 'containing') { + my $wholeentry=$about_me_link.':'. + $parmlog{$id}{'exe_uname'}.':'.$parmlog{$id}{'exe_udom'}.':'. + $output; + if ($wholeentry!~/\Q$env{'form.containingphrase'}\E/i) { next; } + } + if ($count) { + $r->print($row_start.''.$time.' '.$about_me_link. '
'.$parmlog{$id}{'exe_uname'}. ':'.$parmlog{$id}{'exe_udom'}.''. $send_msg_link.''.$output); - - $shown++; + $shown++; + } if (!($env{'form.show'} eq &mt('all') || $shown<=$env{'form.show'})) { last; } } @@ -3807,6 +3993,12 @@ sub parm_change_log { $r->print(&Apache::loncommon::end_page()); } +sub check_for_course_info { + my $navmap = Apache::lonnavmaps::navmap->new(); + return 1 if ($navmap); + return 0; +} + ################################################## ################################################## @@ -3817,14 +4009,15 @@ sub parm_change_log { Main handler. Calls &assessparms and &crsenv subroutines. =cut + ################################################## ################################################## -# use Data::Dumper; - sub handler { my $r=shift; + &reset_caches(); + if ($r->header_only) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; @@ -3850,17 +4043,15 @@ sub handler { (&Apache::lonnet::allowed('opa',$env{'request.course.id'}) || &Apache::lonnet::allowed('opa',$env{'request.course.id'}.'/'. $env{'request.course.sec'})); - if ($env{'request.course.id'} && $parm_permission) { + my $exists = &check_for_course_info(); + + if ($env{'request.course.id'} && $parm_permission && $exists) { # Start Page &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - # id numbers can change on re-ordering of folders - - &resetsymbcache(); - # # Main switch on form.action and form.state, as appropriate # @@ -3920,10 +4111,17 @@ sub handler { } } else { # ----------------------------- Not in a course, or not allowed to modify parms - $env{'user.error.msg'}= - "/adm/parmset:opa:0:0:Cannot modify assessment parameters"; + if ($exists) { + $env{'user.error.msg'}= + "/adm/parmset:opa:0:0:Cannot modify assessment parameters"; + } else { + $env{'user.error.msg'}= + "/adm/parmset::0:1:Course environment gone, reinitialize the course"; + } return HTTP_NOT_ACCEPTABLE; } + &reset_caches(); + return OK; }