--- loncom/interface/loncommon.pm 2010/11/09 00:08:06 1.925.2.17 +++ loncom/interface/loncommon.pm 2011/01/03 14:58:05 1.948.2.22 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # a pile of common routines # -# $Id: loncommon.pm,v 1.925.2.17 2010/11/09 00:08:06 raeburn Exp $ +# $Id: loncommon.pm,v 1.948.2.22 2011/01/03 14:58:05 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -483,9 +483,9 @@ ENDAUTHORBRW sub coursebrowser_javascript { my ($domainfilter,$sec_element,$formname,$role_element,$crstype) = @_; - my $wintitle = &mt('Course Browser'); - if ($crstype ne '') { - $wintitle = &mt($crstype); + my $wintitle = 'Course_Browser'; + if ($crstype eq 'Community') { + $wintitle = 'Community_Browser'; } my $id_functions = &javascript_index_functions(); my $output = ' @@ -900,7 +900,7 @@ sub select_language { $langchoices{$code} = &plainlanguagedescription($id); } } - return &select_form($selected,$name,%langchoices); + return &select_form($selected,$name,\%langchoices); } =pod @@ -1072,7 +1072,7 @@ END =pod -=item * &help_open_topic($topic,$text,$stayOnPage,$width,$height) +=item * &help_open_topic($topic,$text,$stayOnPage,$width,$height,$imgid) Returns a string corresponding to an HTML link to the given help $topic, where $topic corresponds to the name of a .tex file in @@ -1095,7 +1095,7 @@ be useful for certain help topics with b =cut sub help_open_topic { - my ($topic, $text, $stayOnPage, $width, $height) = @_; + my ($topic, $text, $stayOnPage, $width, $height, $imgid) = @_; $text = "" if (not defined $text); $stayOnPage = 0 if (not defined $stayOnPage); $width = 350 if (not defined $width); @@ -1124,12 +1124,15 @@ sub help_open_topic { # (Always) Add the graphic my $title = &mt('Online Help'); my $helpicon=&lonhttpdurl("/adm/help/help.png"); + if ($imgid ne '') { + $imgid = ' id="'.$imgid.'"'; + } $template.=' ' .''.&mt('Help: [_1]',$topic).''; - if ($text ne "") { + if ($text ne "") { $template.=''; } return $template; @@ -1719,10 +1722,13 @@ sub create_workbook { my $workbook = Spreadsheet::WriteExcel->new('/home/httpd'.$filename); if (! defined($workbook)) { $r->log_error("Error creating excel spreadsheet $filename: $!"); - $r->print('

'.&mt("Unable to create new Excel file. ". - "This error has been logged. ". - "Please alert your LON-CAPA administrator"). - '

'); + $r->print( + '

' + .&mt('Problems occurred in creating the new Excel file.') + .' '.&mt('This error has been logged.') + .' '.&mt('Please alert your LON-CAPA administrator.') + .'

' + ); return (undef); } # @@ -1762,9 +1768,13 @@ sub create_text_file { $fh = Apache::File->new('>/home/httpd'.$filename); if (! defined($fh)) { $r->log_error("Couldn't open $filename for output $!"); - $r->print(&mt('Problems occurred in creating the output file. ' - .'This error has been logged. ' - .'Please alert your LON-CAPA administrator.')); + $r->print( + '

' + .&mt('Problems occurred in creating the output file.') + .' '.&mt('This error has been logged.') + .' '.&mt('Please alert your LON-CAPA administrator.') + .'

' + ); } return ($fh,$filename) } @@ -1793,7 +1803,7 @@ sub domain_select { return &multiple_select_form($name,$value,4,\%domains); } else { $domains{'select_form_order'} = [sort {lc($a) cmp lc($b) } (keys(%domains))]; - return &select_form($name,$value,%domains); + return &select_form($name,$value,\%domains); } } @@ -1855,29 +1865,36 @@ sub multiple_select_form { =pod -=item * &select_form($defdom,$name,%hash) +=item * &select_form($defdom,$name,$hashref,$onchange) Returns a string containing a \n"; + my ($def,$name,$hashref,$onchange) = @_; + return unless (ref($hashref) eq 'HASH'); + if ($onchange) { + $onchange = ' onchange="'.$onchange.'"'; + } + my $selectform = ""; return $selectform; @@ -1895,9 +1912,9 @@ sub display_filter { &mt('Filter [_1]', &select_form($env{'form.displayfilter'}, 'displayfilter', - ('currentfolder' => 'Current folder/page', + {'currentfolder' => 'Current folder/page', 'containing' => 'Containing phrase', - 'none' => 'None'))). + 'none' => 'None'})). ''; } @@ -1978,16 +1995,7 @@ sub select_dom_form { ($dom eq $defdom ? 'selected="selected" ' : '').'>'.$dom; if ($showdomdesc) { if ($dom ne '') { - my $domdesc; - if ($name eq 'srchdomain') { - if ($dom eq 'gci') { - $domdesc = 'Faculty'; - } else { - $domdesc = 'Students'; - } - } else { - $domdesc = &Apache::lonnet::domain($dom,'description'); - } + my $domdesc = &Apache::lonnet::domain($dom,'description'); if ($domdesc ne '') { $selectdomain .= ' ('.$domdesc.')'; } @@ -2276,12 +2284,16 @@ function changed_text(choice,currentform } function set_auth_radio_buttons(newvalue,currentform) { + var numauthchoices = currentform.login.length; + if (typeof numauthchoices == "undefined") { + return; + } var i=0; - while (i < currentform.login.length) { + while (i < numauthchoices) { if (currentform.login[i].value == newvalue) { break; } i++; } - if (i == currentform.login.length) { + if (i == numauthchoices) { return; } current.radiovalue = newvalue; @@ -2478,11 +2490,9 @@ sub authform_internal{ } $autharg = ''; - my $authtext = '[_1] Internally authenticated (with initial password [_2])'; - if ($in{'caller'} eq 'requestcrs') { - $authtext = "[_1] Students' password, if none in the uploaded file: [_2]"; - } - $result = &mt($authtext,''.$autharg); + $result = &mt + ('[_1] Internally authenticated (with initial password [_2])', + ''.$autharg); $result.="'; return $result; } @@ -3250,8 +3260,7 @@ sub filemimetype { sub filecategoryselect { my ($name,$value)=@_; return &select_form($value,$name, - '' => &mt('Any category'), - map { $_,$_ } sort(keys(%category_extensions))); + {'' => &mt('Any category'), map { $_,$_ } sort(keys(%category_extensions))}); } =pod @@ -3416,12 +3425,26 @@ sub get_previous_attempt { } $prevattempts=&start_data_table().&start_data_table_header_row(); $prevattempts.=''.&mt('History').''; + my (%typeparts,%lasthidden); + my $showsurv=&Apache::lonnet::allowed('vas',$env{'request.course.id'}); foreach my $key (sort(keys(%lasthash))) { my ($ign,@parts) = split(/\./,$key); if ($#parts > 0) { my $data=$parts[-1]; + next if ($data eq 'foilorder'); pop(@parts); - $prevattempts.=''.&mt('Part ').join('.',@parts).'
'.$data.' '; + if ($data eq 'type') { + unless ($showsurv) { + my $id = join(',',@parts); + $typeparts{$ign.'.'.$id} = $lasthash{$key}; + if (($lasthash{$key} eq 'anonsurvey') || ($lasthash{$key} eq 'anonsurveycred')) { + $lasthidden{$ign.'.'.$id} = 1; + } + } + delete($lasthash{$key}); + } else { + $prevattempts.=''.&mt('Part ').join('.',@parts).'
'.$data.' '; + } } else { if ($#parts == 0) { $prevattempts.=''.$parts[0].''; @@ -3433,21 +3456,93 @@ sub get_previous_attempt { $prevattempts.=&end_data_table_header_row(); if ($getattempt eq '') { for ($version=1;$version<=$returnhash{'version'};$version++) { - $prevattempts.=&start_data_table_row(). - ''.&mt('Transaction [_1]',$version).''; - foreach my $key (sort(keys(%lasthash))) { - my $value = &format_previous_attempt_value($key, - $returnhash{$version.':'.$key}); - $prevattempts.=''.$value.' '; - } - $prevattempts.=&end_data_table_row(); + my @hidden; + if (%typeparts) { + foreach my $id (keys(%typeparts)) { + if (($returnhash{$version.':'.$id.'.type'} eq 'anonsurvey') || ($returnhash{$version.':'.$id.'.type'} eq 'anonsurveycred')) { + push(@hidden,$id); + } + } + } + $prevattempts.=&start_data_table_row(). + ''.&mt('Transaction [_1]',$version).''; + if (@hidden) { + foreach my $key (sort(keys(%lasthash))) { + next if ($key =~ /\.foilorder$/); + my $hide; + foreach my $id (@hidden) { + if ($key =~ /^\Q$id\E/) { + $hide = 1; + last; + } + } + if ($hide) { + my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/); + if (($data eq 'award') || ($data eq 'awarddetail')) { + my $value = &format_previous_attempt_value($key, + $returnhash{$version.':'.$key}); + $prevattempts.=''.$value.' '; + } else { + $prevattempts.=' '; + } + } else { + if ($key =~ /\./) { + my $value = &format_previous_attempt_value($key, + $returnhash{$version.':'.$key}); + $prevattempts.=''.$value.' '; + } else { + $prevattempts.=' '; + } + } + } + } else { + foreach my $key (sort(keys(%lasthash))) { + next if ($key =~ /\.foilorder$/); + my $value = &format_previous_attempt_value($key, + $returnhash{$version.':'.$key}); + $prevattempts.=''.$value.' '; + } + } + $prevattempts.=&end_data_table_row(); } } + my @currhidden = keys(%lasthidden); $prevattempts.=&start_data_table_row().''.&mt('Current').''; foreach my $key (sort(keys(%lasthash))) { - my $value = &format_previous_attempt_value($key,$lasthash{$key}); - if ($key =~/$regexp$/ && (defined &$gradesub)) {$value = &$gradesub($value)} - $prevattempts.=''.$value.' '; + next if ($key =~ /\.foilorder$/); + if (%typeparts) { + my $hidden; + foreach my $id (@currhidden) { + if ($key =~ /^\Q$id\E/) { + $hidden = 1; + last; + } + } + if ($hidden) { + my ($id,$data) = ($key =~ /^(.+)\.([^.]+)$/); + if (($data eq 'award') || ($data eq 'awarddetail')) { + my $value = &format_previous_attempt_value($key,$lasthash{$key}); + if ($key =~/$regexp$/ && (defined &$gradesub)) { + $value = &$gradesub($value); + } + $prevattempts.=''.$value.' '; + } else { + $prevattempts.=' '; + } + } else { + my $value = &format_previous_attempt_value($key,$lasthash{$key}); + if ($key =~/$regexp$/ && (defined &$gradesub)) { + $value = &$gradesub($value); + } + $prevattempts.=''.$value.' '; + } + } else { + my $value = &format_previous_attempt_value($key,$lasthash{$key}); + if ($key =~/$regexp$/ && (defined &$gradesub)) { + $value = &$gradesub($value); + } + $prevattempts.=''.$value.' '; + } } $prevattempts.= &end_data_table_row().&end_data_table(); } else { @@ -3470,6 +3565,29 @@ sub format_previous_attempt_value { $value = &Apache::lonlocal::locallocaltime($value); } elsif (ref($value) eq 'ARRAY') { $value = '('.join(', ', @{ $value }).')'; + } elsif ($key =~ /answerstring$/) { + my %answers = &Apache::lonnet::str2hash($value); + my @anskeys = sort(keys(%answers)); + if (@anskeys == 1) { + my $answer = $answers{$anskeys[0]}; + if ($answer =~ m{\Q\0\E}) { + $answer =~ s{\Q\0\E}{, }g; + } + my $tag_internal_answer_name = 'INTERNAL'; + if ($anskeys[0] eq $tag_internal_answer_name) { + $value = $answer; + } else { + $value = $anskeys[0].'='.$answer; + } + } else { + foreach my $ans (@anskeys) { + my $answer = $answers{$ans}; + if ($answer =~ m{\Q\0\E}) { + $answer =~ s{\Q\0\E}{, }g; + } + $value .= $ans.'='.$answer.'
';; + } + } } else { $value = &unescape($value); } @@ -3620,10 +3738,13 @@ sub submlink { } if (!$symb) { $symb=&Apache::lonnet::symbread(); } $symb=&escape($symb); - if ($target) { $target="target=\"$target\""; } - return ''.$text.''; + if ($target) { $target=" target=\"$target\""; } + return + ''.$text.''; } ############################################## @@ -3745,7 +3866,9 @@ sub findallcourses { $udom = $env{'user.domain'}; } if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) { - my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname); + my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); + my %roleshash = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef, + $extra); if (!%roles) { %roles = ( cc => 1, @@ -4150,16 +4273,39 @@ sub get_domainconf { if (defined($cached)) { return %{$result}; } my %domconfig = &Apache::lonnet::get_dom('configuration', - ['login','rolecolors'],$udom); + ['login','rolecolors','autoenroll'],$udom); my (%designhash,%legacy); if (keys(%domconfig) > 0) { if (ref($domconfig{'login'}) eq 'HASH') { if (keys(%{$domconfig{'login'}})) { foreach my $key (keys(%{$domconfig{'login'}})) { if (ref($domconfig{'login'}{$key}) eq 'HASH') { - foreach my $img (keys(%{$domconfig{'login'}{$key}})) { - $designhash{$udom.'.login.'.$key.'_'.$img} = - $domconfig{'login'}{$key}{$img}; + if ($key eq 'loginvia') { + if (ref($domconfig{'login'}{'loginvia'}) eq 'HASH') { + my @ids = &Apache::lonnet::current_machine_ids(); + foreach my $hostname (@ids) { + if (ref($domconfig{'login'}{'loginvia'}{$hostname}) eq 'HASH') { + if ($domconfig{'login'}{'loginvia'}{$hostname}{'server'}) { + my $server = $domconfig{'login'}{'loginvia'}{$hostname}{'server'}; + $designhash{$udom.'.login.loginvia'} = $server; + if ($domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'} eq 'custom') { + + $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'custompath'}; + } else { + $designhash{$udom.'.login.loginvia_'.$hostname} = $server.':'.$domconfig{'login'}{'loginvia'}{$hostname}{'serverpath'}; + } + if ($domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}) { + $designhash{$udom.'.login.loginvia_exempt_'.$hostname} = $domconfig{'login'}{'loginvia'}{$hostname}{'exempt'}; + } + } + } + } + } + } else { + foreach my $img (keys(%{$domconfig{'login'}{$key}})) { + $designhash{$udom.'.login.'.$key.'_'.$img} = + $domconfig{'login'}{$key}{$img}; + } } } else { $designhash{$udom.'.login.'.$key}=$domconfig{'login'}{$key}; @@ -4186,6 +4332,11 @@ sub get_domainconf { } else { $legacy{'rolecolors'} = 1; } + if (ref($domconfig{'autoenroll'}) eq 'HASH') { + if ($domconfig{'autoenroll'}{'co-owners'}) { + $designhash{$udom.'.autoassign.co-owners'}=$domconfig{'autoenroll'}{'co-owners'}; + } + } if (keys(%legacy) > 0) { my %legacyhash = &get_legacy_domconf($udom); foreach my $item (keys(%legacyhash)) { @@ -4345,7 +4496,7 @@ Returns: HTML div with $content sub head_subbox { my ($content)=@_; my $output = - '
' + '
' .$content .'
' } @@ -4463,6 +4614,11 @@ sub bodytag { my ($title,$function,$addentries,$bodyonly,$domain,$forcereg, $no_nav_bar,$bgcolor,$no_inline_link,$args)=@_; + my $public; + if ((($env{'user.name'} eq 'public') && ($env{'user.domain'} eq 'public')) + || ($env{'user.name'} eq '') && ($env{'user.domain'} eq '')) { + $public = 1; + } if (!$args->{'no_auto_mt_title'}) { $title = &mt($title); } $function = &get_users_function() if (!$function); @@ -4478,10 +4634,6 @@ sub bodytag { 'link' => &designparm($function.'.link',$domain),); @design{keys(%$addentries)} = @$addentries{keys(%$addentries)}; - my $custommenu; - if ($env{'environment.remote'} eq 'off') { - $custommenu = &needs_gci_custom(); - } # role and realm my ($role,$realm) = split(/\./,$env{'request.role'},2); if ($role eq 'ca') { @@ -4491,26 +4643,14 @@ sub bodytag { # realm if ($env{'request.course.id'}) { if ($env{'request.role'} !~ /^cr/) { - if (($custommenu) && (($role eq 'cm') || ($env{'form.context'} eq 'requestcrs'))) { - undef($role); - } else { - $role = &Apache::lonnet::plaintext($role,&course_type()); - } + $role = &Apache::lonnet::plaintext($role,&course_type()); } - if (defined($role) && $env{'request.course.sec'}) { + if ($env{'request.course.sec'}) { $role .= (' 'x2).'- '.&mt('section:').' '.$env{'request.course.sec'}; - } - if ($env{'form.context'} eq 'requestcrs') { - undef($realm); - } else { - $realm = $env{'course.'.$env{'request.course.id'}.'.description'}; - } + } + $realm = $env{'course.'.$env{'request.course.id'}.'.description'}; } else { - if (($custommenu) && ($role eq 'cm')) { - undef($role); - } else { - $role = &Apache::lonnet::plaintext($role); - } + $role = &Apache::lonnet::plaintext($role); } if (!$realm) { $realm=' '; } @@ -4528,12 +4668,12 @@ sub bodytag { } my $name = &plainname($env{'user.name'},$env{'user.domain'}); - if ($env{'user.name'} eq 'public' && $env{'user.domain'} eq 'public') { + if ($public) { undef($role); } else { $name = &aboutmewrapper($name,$env{'user.name'},$env{'user.domain'}); } - + my $titleinfo = '

'.$title.'

'; # # Extra info if you are the DC @@ -4549,11 +4689,11 @@ sub bodytag { $role = '('.$role.')' if $role; &get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['inhibitmenu']); - if ($env{'environment.remote'} eq 'off') { + if ($env{'environment.remote'} ne 'on') { # No Remote if ($no_nav_bar || $env{'form.inhibitmenu'} eq 'yes') { - return $bodytag; - } + return $bodytag; + } if ($env{'request.state'} eq 'construct') { $forcereg=1; } @@ -4561,69 +4701,7 @@ sub bodytag { # $titleinfo = &CSTR_pageheader(); #FIXME: Will be removed once all scripts have their own calls # } - my $role_selector; - if (($custommenu) && !($env{'form.context'} eq 'requestcrs') && - ($env{'request.course.id'}) && - ($env{'course.'.$env{'request.course.id'}.'.domain'} eq 'gcitest')) { - $role_selector = &Apache::lonmenu::roles_selector( - $env{'course.' . $env{'request.course.id'} . '.domain'}, - $env{'course.' . $env{'request.course.id'} . '.num'} ); - if ($role_selector) { - $role_selector = '
'.$role_selector; - } - } - my $cid = $env{'request.course.id'}; - my %gcicourses = ( - gci_9615072b469884921gcil1 => 'review', - gci_1H96711d710194bfegcil1 => 'submit', - gci_5422913620b814c90gcil1 => 'tutorial', - ); - if (($custommenu && $cid && !$gcicourses{$cid}) && - !($env{'form.context'} eq 'requestcrs') || - ($env{'user.domain'} eq 'gcitest')) { - my $role = 'st'; - if ($custommenu) { - $role = 'cc'; - } - my ($switcher_js,$switcher,$formname); - $formname = 'pickrole'; - my %courses = &existing_gcitest_courses($role); - my $numcourses = keys(%courses); - my $reqdcount = 0; - if ($cid) { - if ($courses{$cid}) { - $reqdcount = 1; - } - } - if ($numcourses > $reqdcount) { - $switcher = &gcitest_switcher($role,$formname,%courses); - my $current; - if ($cid) { - $current = $role.'./'.$env{'course.'.$cid.'.domain'}. - '/'.$env{'course.'.$cid.'.num'}; - } - $switcher_js = &Apache::loncommon::gcitest_switcher_js($current,$numcourses,$formname); - if ($switcher_js) { - $switcher_js= <<"ENDSCRIPT"; - -ENDSCRIPT - } - } - if ($switcher) { - $switcher = $switcher_js.$switcher; - if ($role_selector) { - $role_selector .= '   '.$switcher; - } else { - $role_selector .= '
'.$switcher; - } - } - } if ($env{'request.noversionuri'} =~ m{^/res/adm/pages/}) { if ($dc_info) { @@ -4633,19 +4711,17 @@ ENDSCRIPT $realm $dc_info
|; return $bodytag; } - if ($env{'request.noversionuri'} eq '/adm/navmaps' && - $env{'environment.remotenavmap'} eq 'on') { + if (($env{'request.noversionuri'} =~ m{^/adm/navmaps}) && + ($env{'environment.remotenavmap'} eq 'on')) { return $bodytag; } - if ($cid && $gcicourses{$cid} eq 'tutorial') { - $bodytag .= '
'; + unless ($env{'request.symb'} =~ m/\.page___\d+___/) { + $bodytag .= qq|
$name $role
|; } - - $bodytag .= qq|
$name $role $role_selector
|; $bodytag .= Apache::lonhtmlcommon::scripttag( - Apache::lonmenu::utilityfunctions('',$custommenu), 'start'); + Apache::lonmenu::utilityfunctions(), 'start'); $bodytag .= Apache::lonmenu::primary_menu(); @@ -4653,18 +4729,10 @@ ENDSCRIPT $dc_info = &dc_courseid_toggle($dc_info); } $bodytag .= qq|
$realm $dc_info
|; - if ($cid && $gcicourses{$cid} eq 'tutorial') { - $bodytag .= '
'; - } #don't show menus for public users - if($env{'user.name'} ne 'public' && $env{'user.domain'} ne 'public'){ - if (($custommenu) && - ($env{'request.role'} !~ m{^st\./gcitest/$match_courseid})) { - $bodytag .= &Apache::lonmenu::gci_secondary_menu(); - } elsif ($env{'request.role'} ne 'cm' || &check_for_gci_dc()) { - $bodytag .= Apache::lonmenu::secondary_menu(); - } + if (!$public){ + $bodytag .= Apache::lonmenu::secondary_menu(); $bodytag .= Apache::lonmenu::serverform(); $bodytag .= Apache::lonhtmlcommon::scripttag('', 'end'); if ($env{'request.state'} eq 'construct') { @@ -4672,28 +4740,6 @@ ENDSCRIPT $args->{'bread_crumbs'}); } elsif ($forcereg) { $bodytag .= &Apache::lonmenu::innerregister($forcereg); - } elsif ($custommenu && $env{'request.course.id'} && - &Apache::lonnet::allowed('mdc', $env{'request.course.id'})) { - if ((($env{'request.noversionuri'} eq '/adm/navmaps') && - ($env{'request.noversionuri'} ne 'on')) || - (($env{'request.noversionuri'} eq '/adm/coursedocs') && - (!($env{'form.context'} eq 'requestcrs'))) || - (($env{'request.noversionuri'} eq '/adm/createuser') && - (!($env{'form.context'} eq 'requestcrs'))) || - ($env{'request.noversionuri'} eq '/adm/whatsnew') || - ($env{'request.noversionuri'} eq '/cgi-bin/printout.pl') || - ($env{'request.noversionuri'} eq '/adm/printout') || - ($env{'request.noversionuri'} eq '/adm/statistics')) { - - my @advtools = &concept_test_manager(); - &Apache::lonhtmlcommon::clear_breadcrumbs(); - &Apache::lonhtmlcommon::add_breadcrumb_tool( - 'advtools',@advtools); - my $advlinks; - my $legendtext = ''.&mt('Management').''; - &Apache::lonhtmlcommon::render_advtools(\$advlinks,$legendtext); - $bodytag .= $advlinks; - } } }else{ # this is to seperate menu from content when there's no secondary @@ -4739,55 +4785,9 @@ $bodytag ENDBODY } -sub concept_test_manager { - my @advtools; - my %items = ( - docs => { - desc => 'Edit Test', - action => "go('/adm/coursedocs')", - tooltip => 'Assemble or modify Concept Test' - }, - cprv => { - desc => 'Enrollment/Activity', - action => "go('/adm/createuser')", - tooltip => 'Enrollment and student activity', - }, - new => { - desc => "What's New?", - action => "go('/adm/whatsnew')", - tooltip => 'Recent events/action items in Concept Test' , - }, - prnt => { - desc => 'Print Test', - action => "go('/adm/printout');", - tooltip => 'Prepare printable Concept Test', - }, - chrt => { - desc => 'Test Statistics', - action => "go('/adm/statistics');", - tooltip => 'Concept Test Statistics', - }, - rcrs => { - desc => 'Create New Test', - action => "switchpage('createtest');", - tooltip => 'Create new Concept Test', - }, - ); - my @ordered = ('docs','cprv','new','prnt','chrt','rcrs'); - foreach my $item (@ordered) { - push(@advtools, - ''. - ''.$items{$item}{tooltip}.
-                  ''. - ''.$items{$item}{desc}.''); - } - return @advtools; -} - sub dc_courseid_toggle { my ($dc_info) = @_; - return ' '. + return ' '. ''. &mt('(More ...)').''. '
'.$dc_info.'
'; @@ -4903,10 +4903,6 @@ sub standard_css { my $vlink = &designparm($function.'.vlink', $domain); my $link = &designparm($function.'.link', $domain); - my $loginbg = &designparm('login.sidebg',$domain); - my $bgcol = &designparm('login.bgcol',$domain); - my $textcol = &designparm('login.textcol',$domain); - my $sans = 'Verdana,Arial,Helvetica,sans-serif'; my $mono = 'monospace'; my $data_table_head = $sidebg; @@ -4925,13 +4921,21 @@ sub standard_css { my $table_header = '#DDDDDD'; my $feedback_link_bg = '#BBBBBB'; my $lg_border_color = '#C8C8C8'; + my $button_hover = '#BF2317'; my $border = ($env{'browser.type'} eq 'explorer' || $env{'browser.type'} eq 'safari' ) ? '0 2px 0 2px' : '0 3px 0 4px'; - return < td.LC_browser_file, table.LC_data_table tr > td.LC_browser_file_published { @@ -5469,23 +5485,23 @@ table.LC_data_table tr > td.LC_roles_is } table.LC_data_table tr > td.LC_roles_future { - background: #FFFF77; + border-right: 8px solid #FFFF77; } table.LC_data_table tr > td.LC_roles_will { - background: #FFAA77; + border-right: 8px solid #FFAA77; } table.LC_data_table tr > td.LC_roles_expired { - background: #FF7777; + border-right: 8px solid #FF7777; } table.LC_data_table tr > td.LC_roles_will_not { - background: #AAFF77; + border-right: 8px solid #AAFF77; } table.LC_data_table tr > td.LC_roles_selected { - background: #11CC55; + border-right: 8px solid #11CC55; } span.LC_current_location { @@ -5520,6 +5536,14 @@ span.LC_parm_symb { color: #AAAAAA; } +ul.LC_parm_parmlist li { + display: inline-block; + padding: 0.3em 0.8em; + vertical-align: top; + width: 150px; + border-top:1px solid $lg_border_color; +} + td.LC_parm_overview_level_menu, td.LC_parm_overview_map_menu, td.LC_parm_overview_parm_selectors, @@ -5709,10 +5733,6 @@ table.LC_notify_front_page td { font-size: 1.2em; } -.LC_topic_bar img { - vertical-align: bottom; -} - table.LC_course_group_status { margin: 20px; } @@ -5951,56 +5971,41 @@ div.LC_clear_float_footer { } div.LC_grade_show_user { - margin-top: 20px; - border: 1px solid black; +/* border-left: 5px solid $sidebg; */ + border-top: 5px solid #000000; + margin: 50px 0 0 0; + padding: 15px 0 5px 10px; } -div.LC_grade_user_name { - background: #DDDDEE; - border-bottom: 1px solid black; - font-weight: bold; - font-size: large; +div.LC_grade_show_user_odd_row { +/* border-left: 5px solid #000000; */ } -div.LC_grade_show_user_odd_row div.LC_grade_user_name { - background: #DDEEDD; +div.LC_grade_show_user div.LC_Box { + margin-right: 50px; } -div.LC_grade_show_problem, div.LC_grade_submissions, div.LC_grade_message_center, -div.LC_grade_info_links, -div.LC_grade_assign { +div.LC_grade_info_links { margin: 5px; width: 99%; background: #FFFFFF; } -div.LC_grade_show_problem_header, div.LC_grade_submissions_header, -div.LC_grade_message_center_header, -div.LC_grade_assign_header { +div.LC_grade_message_center_header { font-weight: bold; font-size: large; } -div.LC_grade_show_problem_problem, div.LC_grade_submissions_body, -div.LC_grade_message_center_body, -div.LC_grade_assign_body { +div.LC_grade_message_center_body { border: 1px solid black; width: 99%; background: #FFFFFF; } -span.LC_grade_check_note { - font-weight: normal; - font-size: medium; - display: inline; - position: absolute; - right: 1em; -} - table.LC_scantron_action { width: 100%; } @@ -6034,15 +6039,8 @@ div.LC_edit_problem_header_title { } table.LC_edit_problem_header_title { - font-size: larger; - font-weight: bold; width: 100%; - border-color: $pgbg; - border-style: solid; - border-width: $border; background: $tabbg; - border-collapse: collapse; - padding: 0; } div.LC_edit_problem_discards { @@ -6075,13 +6073,6 @@ div.LC_createcourse { display:none; } -/* ---- Remove when done ---- -# The following styles is part of the redesign of LON-CAPA and are -# subject to change during this project. -# Don't rely on their current functionality as they might be -# changed or removed. -# --------------------------*/ - a:hover, ol.LC_primary_menu a:hover, ol#LC_MenuBreadcrumbs a:hover, @@ -6089,7 +6080,7 @@ ol#LC_PathBreadcrumbs a:hover, ul#LC_secondary_menu a:hover, .LC_FormSectionClearButton input:hover ul.LC_TabContent li:hover a { - color:#BF2317; + color:$button_hover; text-decoration:none; } @@ -6154,14 +6145,9 @@ fieldset > legend { padding: 0 5px 0 5px; } -div.LC_page_header { - background-color: $pgbg_or_bgcolor; - margin: 0 0 1.0em 0; -} - #LC_nav_bar { float: left; - margin: 0.2em 0 0 0; + margin: 0 0 2px 0; } #LC_realm { @@ -6176,9 +6162,14 @@ div.LC_page_header { font-style: normal; } +/* Preliminary fix to hide nav_bar inside bookmarks window */ +#LC_bookmarks #LC_nav_bar { + display:none; +} + ol.LC_primary_menu { float: right; - margin: 0.2em 0 0 0; + margin: 0; } span.LC_new_message{ @@ -6198,14 +6189,38 @@ ol.LC_primary_menu li { ol.LC_primary_menu li img { vertical-align: bottom; + height: 1.1em; } ol.LC_primary_menu a { - font-size: 90%; color: RGB(80, 80, 80); text-decoration: none; } +ol.LC_docs_parameters { + margin-left: 0; + padding: 0; + list-style: none; +} + +ol.LC_docs_parameters li { + margin: 0; + padding-right: 20px; + display: inline; +} + +ol.LC_docs_parameters li:before { + content: "\\002022 \\0020"; +} + +li.LC_docs_parameters_title { + font-weight: bold; +} + +ol.LC_docs_parameters li.LC_docs_parameters_title:before { + content: ""; +} + ul#LC_secondary_menu { clear: both; color: $fontmenu; @@ -6245,14 +6260,15 @@ ul#LC_secondary_menu li a { } ul.LC_TabContent { - min-height:1.5em; + min-height:20px; } ul.LC_TabContent li { vertical-align:middle; - padding: 0 10px 0 10px; + padding: 0 16px 0 10px; background-color:$tabbg; border-bottom:solid 1px $lg_border_color; + border-right: solid 1px $font; } ul.LC_TabContent .right { @@ -6265,16 +6281,33 @@ ul.LC_TabContent li { text-decoration:none; font-size:95%; font-weight:bold; - padding-right: 16px; + min-height:20px; +} + +ul.LC_TabContent li a:hover, +ul.LC_TabContent li a:focus { + color: $button_hover; + background:none; + outline:none; +} + +ul.LC_TabContent li:hover { + color: $button_hover; + cursor:pointer; } -ul.LC_TabContent li:hover, ul.LC_TabContent li.active { + color: $font; background:#FFFFFF url(/adm/lonIcons/open.gif) no-repeat scroll right center; - border-bottom:solid 2px #FFFFFF; - padding-right: 16px; + border-bottom:solid 1px #FFFFFF; + cursor: default; } +ul.LC_TabContent li.active a { + color:$font; + background:#FFFFFF; + outline: none; +} #maincoursedoc { clear:both; } @@ -6293,6 +6326,10 @@ ul.LC_TabContentBigger li { color: #737373; } +ul.LC_TabContentBigger li.active { + position: relative; + top: 1px; +} ul.LC_TabContentBigger li a { background:url('/adm/lonIcons/tabbgleft.gif') left bottom no-repeat; @@ -6301,31 +6338,33 @@ ul.LC_TabContentBigger li a { text-align: center; display: block; text-decoration: none; + outline: none; } -ul.LC_TabContentBigger li:hover a, ul.LC_TabContentBigger li.active a { background:url('/adm/lonIcons/tabbgleft.gif') left top no-repeat; color:$font; - text-decoration: underline; } - ul.LC_TabContentBigger li b { background: url('/adm/lonIcons/tabbgright.gif') no-repeat right bottom; display: block; float: left; padding: 0 30px; + border-bottom: 1px solid $lg_border_color; +} + +ul.LC_TabContentBigger li:hover b { + color:$button_hover; } -ul.LC_TabContentBigger li:hover b, ul.LC_TabContentBigger li.active b { background:url('/adm/lonIcons/tabbgright.gif') right top no-repeat; color:$font; - border-bottom: 1px solid #FFFFFF; + border: 0; + cursor:default; } - ul.LC_CourseBreadcrumbs { background: $sidebg; line-height: 32px; @@ -6339,7 +6378,6 @@ ol#LC_MenuBreadcrumbs, ol#LC_PathBreadcrumbs { padding-left: 10px; margin: 0; - margin: 0; height: 2.5em; /* equal to #LC_breadcrumbs line-height */ } @@ -6347,7 +6385,7 @@ ol#LC_MenuBreadcrumbs li, ol#LC_PathBreadcrumbs li, ul.LC_CourseBreadcrumbs li { display: inline; - white-space: normal; + white-space: normal; } ol#LC_MenuBreadcrumbs li a, @@ -6460,52 +6498,6 @@ div.LC_columnSection>* { overflow:hidden; } -.LC_loginpage_container { - text-align:left; - margin : 0 auto; - width:90%; - padding: 10px; - height: auto; - background-color:#FFFFFF; - border:1px solid #CCCCCC; -} - - -.LC_loginpage_loginContainer { - float:left; - width: 182px; - padding: 2px; - border:1px solid #CCCCCC; - background-color:$loginbg; -} - -.LC_loginpage_loginContainer h2 { - margin-top: 0; - display:block; - background:$bgcol; - color:$textcol; - padding-left:5px; -} - -.LC_loginpage_loginInfo { - float:left; - width:182px; - border:1px solid #CCCCCC; - padding:2px; -} - -.LC_loginpage_space { - clear: both; - margin-bottom: 20px; - border-bottom: 1px solid #CCCCCC; -} - -.LC_loginpage_floatLeft { - float: left; - width: 200px; - margin: 0; -} - table em { font-weight: bold; font-style: normal; @@ -6569,10 +6561,6 @@ a#LC_content_toolbar_changefolder_toggle background-image:url(/res/adm/pages/open-all-folders.gif); } -a#LC_content_toolbar_management { - background-image:url(/res/adm/pages/conf.png); -} - ul#LC_toolbar li a:hover { background-position: bottom center; } @@ -6613,7 +6601,7 @@ ul.LC_funclist { } ul.LC_funclist > li:first-child { - font-weight:bold; + font-weight:bold; margin-left:0.8em; } @@ -6637,36 +6625,10 @@ ul.LC_funclist li { line-height: 150%; } -#gciheader { - float:left; - width:100%; - background:#DAE0D2 url("/gcimenu_bg.gif") repeat-x bottom; - font-size:93%; - line-height:normal; - margin: 0.5em 0 0.5em 0; -} -#gciheader ul { - margin:0; - padding:10px 10px 0; - list-style:none; -} -#gciheader li { - float:left; - background:url("/gcimenu_left.gif") no-repeat left top; - margin:0; - padding:0 0 0 9px; -} -#gciheader a { - display:block; - background:url("/gcimenu_right.gif") no-repeat right top; - padding:5px 15px 4px 6px; -} -#gciheader #current { - background-image:url("/gcimenu_left_on.gif"); -} -#gciheader #current a { - background-image:url("/gcimenu_right_on.gif"); - padding-bottom:5px; +.ui-accordion .LC_advanced_toggle { + float: right; + font-size: 90%; + padding: 0px 4px } END @@ -6782,10 +6744,6 @@ Inputs: none sub xml_begin { my $output=''; - if ($env{'internal.start_page'}==1) { - &Apache::lonhtmlcommon::init_htmlareafields(); - } - if ($env{'browser.mathml'}) { $output='' #.''."\n" @@ -6885,7 +6843,7 @@ $args - additional optional args support should it have jsmath forced on by the current page bread_crumbs -> Array containing breadcrumbs - bread_crumbs_components -> if exists show it as headline else show only the breadcrumbs + bread_crumbs_component -> if exists show it as headline else show only the breadcrumbs =back @@ -6962,10 +6920,8 @@ sub start_page { #if bread_crumbs_component exists show it as headline else show only the breadcrumbs if(exists($args->{'bread_crumbs_component'})){ $result .= &Apache::lonhtmlcommon::breadcrumbs($args->{'bread_crumbs_component'}); - } elsif (exists($args->{'bread_crumbs_menulink'})) { - $result .= &Apache::lonhtmlcommon::breadcrumbs('','',$args->{'bread_crumbs_menulink'}); - } else { - $result .= &Apache::lonhtmlcommon::breadcrumbs(); + }else{ + $result .= &Apache::lonhtmlcommon::breadcrumbs(); } } return $result; @@ -7082,15 +7038,26 @@ sub simple_error_page { { my @row_count; + + sub start_data_table_count { + unshift(@row_count, 0); + return; + } + + sub end_data_table_count { + shift(@row_count); + return; + } + sub start_data_table { my ($add_class) = @_; my $css_class = (join(' ','LC_data_table',$add_class)); - unshift(@row_count,0); + &start_data_table_count(); return ''."\n"; } sub end_data_table { - shift(@row_count); + &end_data_table_count(); return '
'."\n";; } @@ -7269,7 +7236,8 @@ role status: active, previous or future. sub check_user_status { my ($udom,$uname,$cdom,$crs,$role,$sec) = @_; - my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname); + my $extra = &Apache::lonnet::freeze_escape({'skipcheck' => 1}); + my %userinfo = &Apache::lonnet::dump('roles',$udom,$uname,'.',undef,$extra); my @uroles = keys %userinfo; my $srchstr; my $active_chk = 'none'; @@ -7896,9 +7864,9 @@ sub user_picker { 'whse' => "When searching by last,first you must include at least one character in the first name.", 'thfo' => "The following need to be corrected before the search can be run:", ); - my $domform = &select_dom_form($currdom,'srchdomain',undef,1); + my $domform = &select_dom_form($currdom,'srchdomain',1,1); my $srchinsel = ' \n"; @@ -7958,9 +7925,9 @@ sub user_picker { ); $new_user_create = '

' .&mt("You are not authorized to create new $usertypetext{$usertype} users in this domain.") - .'
' - .&mt('Enter a valid e-mail address as the username for the new user.').' '.&mt('Please contact the [_1]helpdesk[_2] for assistance.' - ,'','') + .' ' + .&mt('Please contact the [_1]helpdesk[_2] for assistance.' + ,'','') .'


'; } } @@ -8309,6 +8276,10 @@ sub get_institutional_codes { return; } +sub get_standard_codeitems { + return ('Year','Semester','Department','Number','Section'); +} + =pod =head1 Slot Helpers @@ -8500,68 +8471,307 @@ sub get_env_multiple { sub ask_for_embedded_content { my ($actionurl,$state,$allfiles,$codebase,$args)=@_; - my $upload_output = ' -
'; - $upload_output .= $state; - $upload_output .= 'Upload embedded files:
'.&start_data_table(); - + my (%subdependencies,%dependencies,%mapping,%existing,%newfiles,%pathchanges); my $num = 0; - foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%{$allfiles})) { + my $numremref = 0; + my $numinvalid = 0; + my $numpathchg = 0; + my $numexisting = 0; + my ($output,$upload_output,$toplevel,$url,$udom,$uname,$getpropath); + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + my $current_path='/'; + if ($env{'form.currentpath'}) { + $current_path = $env{'form.currentpath'}; + } + if ($actionurl eq '/adm/coursegrp_portfolio') { + $udom = $env{'course.'.$env{'request.course.id'}.'.domain'}; + $uname = $env{'course.'.$env{'request.course.id'}.'.num'}; + $url = '/userfiles/groups/'.$env{'form.group'}.'/portfolio'; + } else { + $udom = $env{'user.domain'}; + $uname = $env{'user.name'}; + $url = '/userfiles/portfolio'; + } + $toplevel = $url.'/'; + $url .= $current_path; + $getpropath = 1; + } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || + ($actionurl eq '/adm/imsimport')) { + ($uname,my $rest) = ($args->{'current_path'} =~ m{/priv/($match_username)/?(.*)$}); + $url = '/home/'.$uname.'/public_html/'; + $toplevel = $url; + if ($rest ne '') { + $url .= $rest; + } + } elsif ($actionurl eq '/adm/coursedocs') { + if (ref($args) eq 'HASH') { + $url = $args->{'docs_url'}; + $toplevel = $url; + } + } + my $now = time(); + foreach my $embed_file (keys(%{$allfiles})) { + my $absolutepath; + if ($embed_file =~ m{^\w+://}) { + $newfiles{$embed_file} = 1; + $mapping{$embed_file} = $embed_file; + } else { + if ($embed_file =~ m{^/}) { + $absolutepath = $embed_file; + $embed_file =~ s{^(/+)}{}; + } + if ($embed_file =~ m{/}) { + my ($path,$fname) = ($embed_file =~ m{^(.+)/([^/]*)$}); + $path = &check_for_traversal($path,$url,$toplevel); + my $item = $fname; + if ($path ne '') { + $item = $path.'/'.$fname; + $subdependencies{$path}{$fname} = 1; + } else { + $dependencies{$item} = 1; + } + if ($absolutepath) { + $mapping{$item} = $absolutepath; + } else { + $mapping{$item} = $embed_file; + } + } else { + $dependencies{$embed_file} = 1; + if ($absolutepath) { + $mapping{$embed_file} = $absolutepath; + } else { + $mapping{$embed_file} = $embed_file; + } + } + } + } + foreach my $path (keys(%subdependencies)) { + my %currsubfile; + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + my @subdir_list = &Apache::lonnet::dirlist($url.$path,$udom,$uname,$getpropath); + foreach my $line (@subdir_list) { + my ($file_name,$rest) = split(/\&/,$line,2); + $currsubfile{$file_name} = 1; + } + } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { + if (opendir(my $dir,$url.'/'.$path)) { + my @subdir_list = grep(!/^\./,readdir($dir)); + map {$currsubfile{$_} = 1;} @subdir_list; + } + } + foreach my $file (keys(%{$subdependencies{$path}})) { + if ($currsubfile{$file}) { + my $item = $path.'/'.$file; + unless ($mapping{$item} eq $item) { + $pathchanges{$item} = 1; + } + $existing{$item} = 1; + $numexisting ++; + } else { + $newfiles{$path.'/'.$file} = 1; + } + } + } + my %currfile; + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + my @dir_list = &Apache::lonnet::dirlist($url,$udom,$uname,$getpropath); + foreach my $line (@dir_list) { + my ($file_name,$rest) = split(/\&/,$line,2); + $currfile{$file_name} = 1; + } + } elsif (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { + if (opendir(my $dir,$url)) { + my @dir_list = grep(!/^\./,readdir($dir)); + map {$currfile{$_} = 1;} @dir_list; + } + } + foreach my $file (keys(%dependencies)) { + if ($currfile{$file}) { + unless ($mapping{$file} eq $file) { + $pathchanges{$file} = 1; + } + $existing{$file} = 1; + $numexisting ++; + } else { + $newfiles{$file} = 1; + } + } + foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%newfiles)) { $upload_output .= &start_data_table_row(). - ''.$embed_file.''; + ''.$embed_file.''; + unless ($mapping{$embed_file} eq $embed_file) { + $upload_output .= '
'.&mt('changed from: [_1]',$mapping{$embed_file}).''; + } + $upload_output .= ''; if ($args->{'ignore_remote_references'} && $embed_file =~ m{^\w+://}) { $upload_output.=''.&mt("URL points to other server.").''; + $numremref++; } elsif ($args->{'error_on_invalid_names'} && $embed_file ne &Apache::lonnet::clean_filename($embed_file,{'keep_path' => 1,})) { - $upload_output.=''.&mt("Invalid characters").''; - + $upload_output.=''.&mt('Invalid characters').''; + $numinvalid++; } else { - $upload_output .=' - - '; - my $attrib = join(':',@{$$allfiles{$embed_file}}); - $upload_output .= - "\n\t\t". - ''; - if (exists($$codebase{$embed_file})) { - $upload_output .= - "\n\t\t". - ''; - } - } - $upload_output .= ''.&Apache::loncommon::end_data_table_row(); - $num++; - } - $upload_output .= &Apache::loncommon::end_data_table().'
- - - '.&mt('(only files for which a location has been provided will be uploaded)').' -
'; - return $upload_output; + $upload_output .= &embedded_file_element('upload_embedded',$num, + $embed_file,\%mapping, + $allfiles,$codebase); + $num++; + } + $upload_output .= ''.&Apache::loncommon::end_data_table_row()."\n"; + } + foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%existing)) { + $upload_output .= &start_data_table_row(). + ''.$embed_file.''. + ''.&mt('Already exists').''. + &Apache::loncommon::end_data_table_row()."\n"; + } + if ($upload_output) { + $upload_output = &start_data_table(). + $upload_output. + &end_data_table()."\n"; + } + my $applies = 0; + if ($numremref) { + $applies ++; + } + if ($numinvalid) { + $applies ++; + } + if ($numexisting) { + $applies ++; + } + if ($num) { + $output = '
'."\n". + $state. + '

'.&mt('Upload embedded files'). + ':

'.$upload_output.'
'."\n". + ''."\n"; + if ($actionurl eq '') { + $output .= ''; + } + } elsif ($applies) { + $output = ''.&mt('Referenced files').':
'; + if ($applies > 1) { + $output .= + &mt('No files need to be uploaded, as one of the following applies to each reference:').'
    '; + if ($numremref) { + $output .= '
  • '.&mt('reference is to a URL which points to another server').'
  • '."\n"; + } + if ($numinvalid) { + $output .= '
  • '.&mt('reference is to file with a name containing invalid characters').'
  • '."\n"; + } + if ($numexisting) { + $output .= '
  • '.&mt('reference is to an existing file at the specified location').'
  • '."\n"; + } + $output .= '

'; + } elsif ($numremref) { + $output .= '

'.&mt('None to upload, as all references are to URLs pointing to another server.').'

'; + } elsif ($numinvalid) { + $output .= '

'.&mt('None to upload, as all references are to files with names containing invalid characters.').'

'; + } elsif ($numexisting) { + $output .= '

'.&mt('None to upload, as all references are to existing files.').'

'; + } + $output .= $upload_output.'
'; + } + my ($pathchange_output,$chgcount); + $chgcount = $num; + if (keys(%pathchanges) > 0) { + foreach my $embed_file (sort {lc($a) cmp lc($b)} keys(%pathchanges)) { + if ($num) { + $output .= &embedded_file_element('pathchange',$chgcount, + $embed_file,\%mapping, + $allfiles,$codebase); + } else { + $pathchange_output .= + &start_data_table_row(). + ''. + ''.$mapping{$embed_file}.''. + ''.$embed_file. + &embedded_file_element('pathchange',$numpathchg,$embed_file, + \%mapping,$allfiles,$codebase). + ''.&end_data_table_row(); + } + $numpathchg ++; + $chgcount ++; + } + } + if ($num) { + if ($numpathchg) { + $output .= ''."\n"; + } + if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank') || + ($actionurl eq '/adm/imsimport')) { + $output .= ''."\n"; + } elsif ($actionurl eq '/adm/portfolio' || $actionurl eq '/adm/coursegrp_portfolio') { + $output .= ''; + } + $output .= ''."\n". + &mt('(only files for which a location has been provided will be uploaded)').'
'."\n"; + } elsif ($numpathchg) { + my %pathchange = (); + $output .= &modify_html_form('pathchange',$actionurl,$state,\%pathchange,$pathchange_output); + if (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + $output .= '

'.&mt('or').'

'; + } + } + return ($output,$num,$numpathchg); +} + +sub embedded_file_element { + my ($context,$num,$embed_file,$mapping,$allfiles,$codebase) = @_; + return unless ((ref($mapping) eq 'HASH') && (ref($allfiles) eq 'HASH') && + (ref($codebase) eq 'HASH')); + my $output; + if ($context eq 'upload_embedded') { + $output = ''."\n"; + } + $output .= ''; + unless (($context eq 'upload_embedded') && + ($mapping->{$embed_file} eq $embed_file)) { + $output .=' + '; + } + my $attrib; + if (ref($allfiles->{$mapping->{$embed_file}}) eq 'ARRAY') { + $attrib = &escape(join(':',@{$allfiles->{$mapping->{$embed_file}}})); + } + $output .= + "\n\t\t". + ''; + if (exists($codebase->{$mapping->{$embed_file}})) { + $output .= + "\n\t\t". + ''; + } + return $output; } sub upload_embedded { my ($context,$dirpath,$uname,$udom,$dir_root,$url_root,$group,$disk_quota, - $current_disk_usage) = @_; - my $output; + $current_disk_usage,$hiddenstate,$actionurl) = @_; + my (%pathchange,$output,$modifyform,$footer,$returnflag); for (my $i=0; $i<$env{'form.number_embedded_items'}; $i++) { next if (!exists($env{'form.embedded_item_'.$i.'.filename'})); my $orig_uploaded_filename = $env{'form.embedded_item_'.$i.'.filename'}; - - $env{'form.embedded_orig_'.$i} = - &unescape($env{'form.embedded_orig_'.$i}); + foreach my $type ('orig','ref','attrib','codebase') { + if ($env{'form.embedded_'.$type.'_'.$i} ne '') { + $env{'form.embedded_'.$type.'_'.$i} = + &unescape($env{'form.embedded_'.$type.'_'.$i}); + } + } my ($path,$fname) = ($env{'form.embedded_orig_'.$i} =~ m{(.*/)([^/]*)}); # no path, whole string is fname if (!$fname) { $fname = $env{'form.embedded_orig_'.$i} }; - - $path = $env{'form.currentpath'}.$path; $fname = &Apache::lonnet::clean_filename($fname); # See if there is anything left next if ($fname eq ''); @@ -8573,12 +8783,12 @@ sub upload_embedded { if ($group ne '') { $port_path = "groups/$group/$port_path"; } - ($state,$msg) = &check_for_upload($path,$fname,$group,'embedded_item_'.$i, + ($state,$msg) = &check_for_upload($env{'form.currentpath'}.$path, + $fname,$group,'embedded_item_'.$i, $dir_root,$port_path,$disk_quota, $current_disk_usage,$uname,$udom); if ($state eq 'will_exceed_quota' - || $state eq 'file_locked' - || $state eq 'file_exists' ) { + || $state eq 'file_locked') { $output .= $msg; next; } @@ -8592,31 +8802,53 @@ sub upload_embedded { # Check if extension is valid if (($fname =~ /\.(\w+)$/) && (&Apache::loncommon::fileembstyle($1) eq 'hdn')) { - $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1); + $output .= &mt('Invalid file extension ([_1]) - reserved for LONCAPA use - rename the file with a different extension and re-upload. ',$1).'
'; next; } elsif (($fname =~ /\.(\w+)$/) && (!defined(&Apache::loncommon::fileembstyle($1)))) { - $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1); + $output .= &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1).'
'; next; } elsif ($fname=~/\.(\d+)\.(\w+)$/) { - $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2); + $output .= &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2).'
'; next; } $env{'form.embedded_item_'.$i.'.filename'}=$fname; if ($context eq 'portfolio') { - my $result= - &Apache::lonnet::userfileupload('embedded_item_'.$i,'', - $dirpath.$path); + my $result; + if ($state eq 'existingfile') { + $result= + &Apache::lonnet::userfileupload('embedded_item_'.$i,'existingfile', + $dirpath.$env{'form.currentpath'}.$path); + } else { + $result= + &Apache::lonnet::userfileupload('embedded_item_'.$i,'', + $dirpath. + $env{'form.currentpath'}.$path); + if ($result !~ m|^/uploaded/|) { + $output .= '' + .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' + ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}) + .'
'; + next; + } else { + $output .= &mt('Uploaded [_1]',''. + $path.$fname.'').'
'; + } + } + } elsif ($context eq 'coursedoc') { + my $result = + &Apache::lonnet::userfileupload('embedded_item_'.$i,'coursedoc', + $dirpath.'/'.$path); if ($result !~ m|^/uploaded/|) { $output .= '' - .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' + .&mt('An error occurred ([_1]) while trying to upload [_2] for embedded element [_3].' ,$result,$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}) - .'
'; - next; + .'

'; + next; } else { - $output .= '

'.&mt('Uploaded [_1]',''. - $path.$fname.'').'

'; + $output .= &mt('Uploaded [_1]',''. + $path.$fname.'').'
'; } } else { # Save the file @@ -8646,19 +8878,190 @@ sub upload_embedded { &mt('An error occurred while writing the file [_1] for embedded element [_2].',$orig_uploaded_filename,$env{'form.embedded_orig_'.$i}). '
'; } else { - if ($context eq 'testbank') { - $output .= &mt('Embedded file uploaded successfully:'). - ' '. - $orig_uploaded_filename.'
'; - } else { - $output .= ''. - &mt('View embedded file: [_1]',''. - $orig_uploaded_filename.'').'
'; + $output .= &mt('Uploaded [_1]',''. + $url.'').'
'; + unless ($context eq 'testbank') { + $footer .= &mt('View embedded file: [_1]', + ''.$fname.'').'
'; } } close($fh); } } + if ($env{'form.embedded_ref_'.$i}) { + $pathchange{$i} = 1; + } + } + if ($output) { + $output = '

'.$output.'

'; + } + $output .= &modify_html_form('upload_embedded',$actionurl,$hiddenstate,\%pathchange); + $returnflag = 'ok'; + if (keys(%pathchange) > 0) { + if ($context eq 'portfolio') { + $output .= '

'.&mt('or').'

'; + } elsif ($context eq 'testbank') { + $output .= '

'.&mt('Or [_1]continue[_2] the testbank import without modifying the reference(s).','','').'

'; + $returnflag = 'modify_orightml'; + } + } + return ($output.$footer,$returnflag); +} + +sub modify_html_form { + my ($context,$actionurl,$hiddenstate,$pathchange,$pathchgtable) = @_; + my $end = 0; + my $modifyform; + if ($context eq 'upload_embedded') { + return unless (ref($pathchange) eq 'HASH'); + if ($env{'form.number_embedded_items'}) { + $end += $env{'form.number_embedded_items'}; + } + if ($env{'form.number_pathchange_items'}) { + $end += $env{'form.number_pathchange_items'}; + } + if ($end) { + for (my $i=0; $i<$end; $i++) { + if ($i < $env{'form.number_embedded_items'}) { + next unless($pathchange->{$i}); + } + $modifyform .= + &start_data_table_row(). + ''. + ''.$env{'form.embedded_ref_'.$i}. + ''. + ''. + ''. + ''.$env{'form.embedded_orig_'.$i}. + ''. + &end_data_table_row(); + } + } + } else { + $modifyform = $pathchgtable; + if (($actionurl eq '/adm/upload') || ($actionurl eq '/adm/testbank')) { + $hiddenstate .= ''; + } elsif (($actionurl eq '/adm/portfolio') || ($actionurl eq '/adm/coursegrp_portfolio')) { + $hiddenstate .= ''; + } + } + if ($modifyform) { + return '

'.&mt('Changes in content of HTML file required').'

'."\n". + '

'.&mt('Changes need to be made to the reference(s) used for one or more of the dependencies, if your HTML file is to work correctly:').'

    '."\n". + '
  1. '.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').'
  2. '."\n". + '
  3. '.&mt('To change absolute paths to relative paths, or replace directory traversal via "../" within the original reference.').'
  4. '."\n". + '

'."\n".'

'. + &mt('LON-CAPA can make the required changes to your HTML file.').'

'."\n". + '
'. + &start_data_table()."\n". + &start_data_table_header_row(). + ''.&mt('Change?').''. + ''.&mt('Current reference').''. + ''.&mt('Required reference').''. + &end_data_table_header_row()."\n". + $modifyform. + &end_data_table().'
'."\n".$hiddenstate. + ''. + '
'."\n"; + } + return; +} + +sub modify_html_refs { + my ($context,$dirpath,$uname,$udom,$dir_root) = @_; + my $container; + if ($context eq 'portfolio') { + $container = $env{'form.container'}; + } elsif ($context eq 'coursedoc') { + $container = $env{'form.primaryurl'}; + } else { + $container = $env{'form.filename'}; + $container =~ s{^/priv/(\Q$uname\E)/(.*)}{/home/$1/public_html/$2}; + } + my (%allfiles,%codebase,$output,$content); + my @changes = &get_env_multiple('form.namechange'); + return unless (@changes > 0); + if (($context eq 'portfolio') || ($context eq 'coursedoc')) { + return unless ($container =~ m{^/uploaded/\Q$udom\E/\Q$uname\E/}); + $content = &Apache::lonnet::getfile($container); + return if ($content eq '-1'); + } else { + return unless ($container =~ /^\Q$dir_root\E/); + if (open(my $fh,"<$container")) { + $content = join('', <$fh>); + close($fh); + } else { + return; + } + } + my ($count,$codebasecount) = (0,0); + my $mm = new File::MMagic; + my $mime_type = $mm->checktype_contents($content); + if ($mime_type eq 'text/html') { + my $parse_result = + &Apache::lonnet::extract_embedded_items($container,\%allfiles, + \%codebase,\$content); + if ($parse_result eq 'ok') { + foreach my $i (@changes) { + my $orig = &unescape($env{'form.embedded_orig_'.$i}); + my $ref = &unescape($env{'form.embedded_ref_'.$i}); + if ($allfiles{$ref}) { + my $newname = $orig; + my ($attrib_regexp,$codebase); + my $attrib_regexp = &unescape($env{'form.embedded_attrib_'.$i}); + if ($attrib_regexp =~ /:/) { + $attrib_regexp =~ s/\:/|/g; + } + if ($content =~ m{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}) { + my $numchg = ($content =~ s{($attrib_regexp\s*=\s*['"]?)\Q$ref\E(['"]?)}{$1$newname$2}gi); + $count += $numchg; + } + if ($env{'form.embedded_codebase_'.$i} ne '') { + my $codebase = &unescape($env{'form.embedded_codebase_'.$i}); + my $numchg = ($content =~ s/(codebase\s*=\s*["']?)\Q$codebase\E(["']?)/$1.$2/i); #' stupid emacs + $codebasecount ++; + } + } + } + if ($count || $codebasecount) { + my $saveresult; + if ($context eq 'portfolio' || $context eq 'coursedoc') { + my $url = &Apache::lonnet::store_edited_file($container,$content,$udom,$uname,\$saveresult); + if ($url eq $container) { + my ($fname) = ($container =~ m{/([^/]+)$}); + $output = '

'.&mt('Updated [quant,_1,reference] in [_2].', + $count,''. + $fname.'').'

'; + } else { + $output = '

'. + &mt('Error: update failed for: [_1].', + ''. + $container.'').'

'; + } + } else { + if (open(my $fh,">$container")) { + print $fh $content; + close($fh); + $output = '

'.&mt('Updated [quant,_1,reference] in [_2].', + $count,''. + $container.'').'

'; + } else { + $output = '

'. + &mt('Error: could not update [_1].', + ''. + $container.'').'

'; + } + } + } + } else { + &logthis('Failed to parse '.$container. + ' to modify references: '.$parse_result); + } } return $output; } @@ -8682,22 +9085,71 @@ sub check_for_existing { sub check_for_upload { my ($path,$fname,$group,$element,$portfolio_root,$port_path, $disk_quota,$current_disk_usage,$uname,$udom) = @_; - my $filesize = (length($env{'form.'.$element})) / 1000; #express in k (1024?) + my $filesize = length($env{'form.'.$element}); + if (!$filesize) { + my $msg = ''. + &mt('Unable to upload [_1]. (size = [_2] bytes)', + ''.$fname.'', + $filesize).'
'. + &mt('Either the file you attempted to upload was empty, or your web browser was unable to read its contents.').'
'; + '
'; + return ('zero_bytes',$msg); + } + $filesize = $filesize/1000; #express in k (1024?) my $getpropath = 1; my @dir_list = &Apache::lonnet::dirlist($portfolio_root.$path,$udom,$uname, $getpropath); my $found_file = 0; my $locked_file = 0; + my @lockers; + my $navmap; + if ($env{'request.course.id'}) { + $navmap = Apache::lonnavmaps::navmap->new(); + } foreach my $line (@dir_list) { - my ($file_name)=split(/\&/,$line,2); + my ($file_name,$rest)=split(/\&/,$line,2); if ($file_name eq $fname){ $file_name = $path.$file_name; if ($group ne '') { $file_name = $group.$file_name; } $found_file = 1; - if (&Apache::lonnet::is_locked($file_name,$udom,$uname) eq 'true') { - $locked_file = 1; + if (&Apache::lonnet::is_locked($file_name,$udom,$uname,\@lockers) eq 'true') { + foreach my $lock (@lockers) { + if (ref($lock) eq 'ARRAY') { + my ($symb,$crsid) = @{$lock}; + if ($crsid eq $env{'request.course.id'}) { + if (ref($navmap)) { + my $res = $navmap->getBySymb($symb); + foreach my $part (@{$res->parts()}) { + my ($slot_status,$slot_time,$slot_name)=$res->check_for_slot($part); + unless (($slot_status == $res->RESERVED) || + ($slot_status == $res->RESERVED_LOCATION)) { + $locked_file = 1; + } + } + } else { + $locked_file = 1; + } + } else { + $locked_file = 1; + } + } + } + } else { + my @info = split(/\&/,$rest); + my $currsize = $info[6]/1000; + if ($currsize < $filesize) { + my $extra = $filesize - $currsize; + if (($current_disk_usage + $extra) > $disk_quota) { + my $msg = ''. + &mt('Unable to upload [_1]. (size = [_2] kilobytes). Disk quota will be exceeded if existing (smaller) file with same name (size = [_3] kilobytes) is replaced.', + ''.$fname.'',$filesize,$currsize).''. + '
'.&mt('Disk quota is [_1] kilobytes. Your current disk usage is [_2] kilobytes.', + $disk_quota,$current_disk_usage); + return ('will_exceed_quota',$msg); + } + } } } } @@ -8715,15 +9167,55 @@ sub check_for_upload { return ('file_locked',$msg); } else { my $msg = ''; - $msg .= &mt('Unable to upload [_1]. A file by that name was found in [_2].',''.$fname.'',$port_path.$env{'form.currentpath'}); + $msg .= &mt(' A file by that name: [_1] was found in [_2].',''.$fname.'',$port_path.$env{'form.currentpath'}); $msg .= ''; - $msg .= '
'; - $msg .= &mt('To upload, rename or delete existing [_1] in [_2].',''.$fname.'', $port_path.$env{'form.currentpath'}); - return ('file_exists',$msg); + return ('existingfile',$msg); } } } +sub check_for_traversal { + my ($path,$url,$toplevel) = @_; + my @parts=split(/\//,$path); + my $cleanpath; + my $fullpath = $url; + for (my $i=0;$i<@parts;$i++) { + next if ($parts[$i] eq '.'); + if ($parts[$i] eq '..') { + $fullpath =~ s{([^/]+/)$}{}; + } else { + $fullpath .= $parts[$i].'/'; + } + } + if ($fullpath =~ /^\Q$url\E(.*)$/) { + $cleanpath = $1; + } elsif ($fullpath =~ /^\Q$toplevel\E(.*)$/) { + my $curr_toprel = $1; + my @parts = split(/\//,$curr_toprel); + my ($url_toprel) = ($url =~ /^\Q$toplevel\E(.*)$/); + my @urlparts = split(/\//,$url_toprel); + my $doubledots; + my $startdiff = -1; + for (my $i=0; $i<@urlparts; $i++) { + if ($startdiff == -1) { + unless ($urlparts[$i] eq $parts[$i]) { + $startdiff = $i; + $doubledots .= '../'; + } + } else { + $doubledots .= '../'; + } + } + if ($startdiff > -1) { + $cleanpath = $doubledots; + for (my $i=$startdiff; $i<@parts; $i++) { + $cleanpath .= $parts[$i].'/'; + } + } + } + $cleanpath =~ s{(/)$}{}; + return $cleanpath; +} =pod @@ -10285,8 +10777,10 @@ sub check_clone { 'userroles',['active'],[$ccrole], [$args->{'clonedomain'}]); if (($roleshash{$args->{'clonecourse'}.':'.$args->{'clonedomain'}.':'.$ccrole}) || (grep(/^\Q$args->{'ccuname'}\E:\Q$args->{'ccdomain'}\E$/,@cloners))) { - $can_clone = 1; - } else { + $can_clone = 1; + } elsif (&Apache::lonnet::is_course_owner($args->{'clonedomain'},$args->{'clonecourse'},$args->{'ccuname'},$args->{'ccdomain'})) { + $can_clone = 1; + } else { if ($args->{'crstype'} eq 'Community') { $clonemsg = &mt('No new community created.').$linefeed.&mt('The new community could not be cloned from the existing community because the new community owner ([_1]) does not have cloning rights in the existing community ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); } else { @@ -10346,11 +10840,19 @@ sub construct_course { # if anyone ever decides to not show this, and Utils::Course::new # will need to be suitably modified. $outcome .= &mt('New LON-CAPA [_1] ID: [_2]',$crstype,$$courseid).$linefeed; + if ($$courseid =~ /^error:/) { + return (0,$outcome); + } + # # Check if created correctly # ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid); my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom); + if ($crsuhome eq 'no_host') { + $outcome .= &mt('Course creation failed, unrecognized course home server.').$linefeed; + return (0,$outcome); + } $outcome .= &mt('Created on').': '.$crsuhome.$linefeed; # @@ -10369,6 +10871,10 @@ sub construct_course { $cenv{'url'}=$oldcenv{'url'}; # Restore title $cenv{'description'}=$oldcenv{'description'}; +# Restore creation date, creator and creation context. + $cenv{'internal.created'}=$oldcenv{'internal.created'}; + $cenv{'internal.creator'}=$oldcenv{'internal.creator'}; + $cenv{'internal.creationcontext'}=$oldcenv{'internal.creationcontext'}; # Mark as cloned $cenv{'clonedfrom'}=$cloneid; # Need to clone grading mode @@ -10615,7 +11121,7 @@ sub construct_course { $title=&mt('Syllabus'); $url='/public/'.$$crsudom.'/'.$$crsunum.'/syllabus'; } else { - $title=&mt('Navigate Contents'); + $title=&mt('Table of Contents'); $url='/adm/navmaps'; } @@ -10626,21 +11132,6 @@ sub construct_course { $outcome .= ($fatal?$errtext:'write ok').$linefeed; } - if ($args->{'cloneroster'}) { - my ($numadded,$clisterror) = &Apache::lonclonecourse::copyroster($cloneid,$$courseid,$args->{'startaccess'},$args->{'endaccess'}); - if ($clisterror) { - $outcome .= "\0".&mt('An error occurred when copying the student roster from the old course to the new course; the error was: [_1].',$clisterror).$linefeed; - if ($numadded) { - $outcome .= &mt('Although [quant,_1,student] have received roles in the new course the roster does not report this. It is ').$linefeed; - } - } else { - if ($numadded) { - $outcome .= "\0".&mt('[quant,_1,student] copied from roster for old course to roster for new course.',$numadded).$linefeed; - } else { - $outcome .= "\0".&mt('No students have been enrolled in the new Concept Test.').' '.&mt('This is because either (a) an error occurred, or (b) there were no students with either current access or access which ended on/after the current default end date set for access to the old course.').$linefeed; - } - } - } return (1,$outcome); } @@ -10860,16 +11351,20 @@ sub init_user_environment { $initial_env{"browser.interface"} = $form->{'interface'}; $env{'browser.interface'}=$form->{'interface'}; } + my %is_adv = ( is_adv => $env{'user.adv'} ); + my %domdef = &Apache::lonnet::get_domain_defaults($domain); foreach my $tool ('aboutme','blog','portfolio') { $userenv{'availabletools.'.$tool} = - &Apache::lonnet::usertools_access($username,$domain,$tool,'reload'); + &Apache::lonnet::usertools_access($username,$domain,$tool,'reload', + undef,\%userenv,\%domdef,\%is_adv); } foreach my $crstype ('official','unofficial','community') { $userenv{'canrequest.'.$crstype} = &Apache::lonnet::usertools_access($username,$domain,$crstype, - 'reload','requestcourses'); + 'reload','requestcourses', + \%userenv,\%domdef,\%is_adv); } $env{'user.environment'} = "$lonids/$cookie.id"; @@ -10907,60 +11402,6 @@ sub _add_to_env { } } -sub new_roles_update { - my $rolecount = 0; - foreach my $envkey (keys(%env)) { - next unless ($envkey =~ /^user\.role\./); - $rolecount ++; - } - my $newrolecount = 0; - if (!$rolecount) { - my %userenv; - foreach my $crstype ('official','unofficial','community') { - $userenv{'canrequest.'.$crstype} = - &Apache::lonnet::usertools_access($env{'user.name'}, - $env{'user.domain'},$crstype,'reload','requestcourses'); - } - my $then=$env{'user.login.time'}; - my $refresh=time; - my (%userroles,%allroles,%allgroups,@newroles); - my %roleshash = - &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'},'userroles',['active','future','previous'],undef,undef,1); - foreach my $item (keys(%roleshash)) { - my ($uname,$udom,$role,$section) = split(':',$item); - my $where = '/'.$udom.'/'.$uname; - my ($tstart,$tend) = split(':',$roleshash{$item}); - if ($section ne '') { - $where .= '/'.$section; - } - my $spec = $role.'.'.$where; - &Apache::lonnet::set_arearole($role,$where,$tstart,$tend, - $env{'user.domain'},$env{'user.name'}); - $userroles{'user.role.'.$spec} = $tstart.'.'.$tend; - $newrolecount ++; - unless (grep(/^\Q$role\E$/,@newroles)) { - push(@newroles,$role); - } - my $status = - &Apache::lonnet::curr_role_status($tstart,$tend,$refresh,$then); - if ($status eq 'active') { - &Apache::lonnet::gather_roleprivs(\%allroles,\%allgroups,\%userroles, - $where,$role,$tstart,$tend); - } - } - if (@newroles) { - my ($author,$adv) = &Apache::lonnet::set_userprivs(\%userroles,\%allroles, - \%allgroups); - &Apache::lonnet::appenv(\%userroles,[@newroles,'cm']); - $userenv{'user.adv'} = $adv; - $userenv{'user.author'} = $author; - $userenv{'user.refresh.time'} = $refresh; - } - &Apache::lonnet::appenv(\%userenv); - } - return $newrolecount; -} - # --- Get the symbolic name of a problem and the url sub get_symb { my ($request,$silent) = @_; @@ -11002,151 +11443,36 @@ sub clean_symb { return ($symb,$enc); } -sub needs_gci_custom { - my $custommenu; - my $numdc = &check_for_gci_dc(); - unless ($numdc) { - my $then=$env{'user.login.time'}; - my $now = time; - my %cnums = ( - review => '9615072b469884921gcil1', - submit => '1H96711d710194bfegcil1', - ); - if ($env{'user.role.st./gci/'.$cnums{'review'}}) { - my ($start,$end) = - split('.',$env{'user.role.st./gci/'.$cnums{'review'}}); - if (((!$start) || ($start && $start <= $now)) && - ((!$end) || ($end > $now))) { - $custommenu = 1; - if ($env{'user.role.cc./gci/'.$cnums{'review'}}) { - my ($ccstart,$ccend) = - split('.',$env{'user.role.cc./gci/'.$cnums{'review'}}); - if (((!$start) || ($start && $start <= $now)) && - ((!$end) || ($end > $now))) { - $custommenu = ''; - } +sub build_release_hashes { + my ($checkparms,$checkresponsetypes,$checkcrstypes,$anonsurvey,$randomizetry) = @_; + return unless((ref($checkparms) eq 'HASH') && (ref($checkresponsetypes) eq 'HASH') && + (ref($checkcrstypes) eq 'HASH') && (ref($anonsurvey) eq 'HASH') && + (ref($randomizetry) eq 'HASH')); + foreach my $key (keys(%Apache::lonnet::needsrelease)) { + my ($item,$name,$value) = split(/:/,$key); + if ($item eq 'parameter') { + if (ref($checkparms->{$name}) eq 'ARRAY') { + unless(grep(/^\Q$name\E$/,@{$checkparms->{$name}})) { + push(@{$checkparms->{$name}},$value); } + } else { + push(@{$checkparms->{$name}},$value); } - } - } - return $custommenu; -} - -sub check_for_gci_dc { - my $then=$env{'user.login.time'}; - my $numdc = 0; - foreach my $dom ('gci','gcitest') { - if ($env{'user.role.dc./'.$dom.'/'}) { - my $livedc = 1; - my ($tstart,$tend)=split(/\./,$env{'user.role.dc./'.$dom.'/'}); - if ($tstart && $tstart>$then) { $livedc = 0; } - if ($tend && $tend <$then) { $livedc = 0; } - if ($livedc) { - $numdc++; - } - } - } - return $numdc; -} - -sub existing_gcitest_courses { - my ($role) = @_; - my %courses; - my $cdom = 'gcitest'; - my $now = time; - foreach my $envkey (keys(%env)) { - my $cnum; - if ($envkey =~ m{^user\.role\.\Q$role\E\./\Q$cdom\E/($match_courseid)$}) { - $cnum = $1; - } else { - next; - } - my ($tstart,$tend) = split(/\./,$env{$envkey}); - if (((!$tstart) || ($tstart < $now)) && ((!$tend) || ($tend > $now))) { - my $descr = $env{'course.'.$cdom.'_'.$cnum.'.description'}; - if ($descr ne '') { - $courses{$cdom.'_'.$cnum}{'description'} = $descr; + } elsif ($item eq 'resourcetag') { + if ($name eq 'responsetype') { + $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key} } - } - } - return %courses; -} - -sub gcitest_switcher { - my ($role,$formname,%courses) = @_; - my $output; - my %Sortby; - foreach my $course (sort(keys(%courses))) { - next unless (ref($courses{$course}) eq 'HASH'); - my $clean_title = $courses{$course}{'description'}; - $clean_title =~ s/\W+//g; - if ($clean_title eq '') { - $clean_title = $courses{$course}{'description'}; - } - push(@{$Sortby{$clean_title}},$course); - } - my @sorted_courses = sort { lc($a) cmp lc($b) } (keys(%Sortby)); - my $default; - if (@sorted_courses > 1) { - if (($env{'request.course.id'}) && ($courses{$env{'request.course.id'}})) { - $default = &mt('Switch concept test ...'); - } else { - $default = &mt('Select a concept test ...'); - } - } else { - unless (($env{'request.course.id'}) && ($courses{$env{'request.course.id'}})) { - $default = &mt('Select concept test ...'); - } - } - if ($default) { - $output = '
'. - '
'; - } - return $output; -} - -sub gcitest_switcher_js { - my ($current,$numcourses,$formname) = @_; - my $output = <<"ENDJS"; - -function courseswitcher(caller) { - var numcourses = $numcourses; - var current = '$current'; - var choice = document.$formname.newrole.options[document.$formname.newrole.selectedIndex].value; - if (choice == '') { - if (caller == 'icon') { - alert('No Concept Test selected'); - } - document.$formname.selectrole.value = ''; - return; - } - if (choice == current) { - if ((caller != 'icon') && (numcourses > 1)) { - alert('You have selected the current course.\\nPlease select a different Concept Test course'); - } - document.$formname.newrole.selectedIndex = 0; - document.$formname.selectrole.value = ''; - return; } - document.$formname.selectrole.value = '1'; - document.$formname.submit(); + ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'}); + ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'}); return; } -ENDJS - return $output; -} - - - =pod =back