\n";
+ my ($def,$name,$hashref,$onchange) = @_;
+ return unless (ref($hashref) eq 'HASH');
+ if ($onchange) {
+ $onchange = ' onchange="'.$onchange.'"';
+ }
+ my $selectform = "\n";
my @keys;
- if (exists($hash{'select_form_order'})) {
- @keys=@{$hash{'select_form_order'}};
+ if (exists($hashref->{'select_form_order'})) {
+ @keys=@{$hashref->{'select_form_order'}};
} else {
- @keys=sort(keys(%hash));
+ @keys=sort(keys(%{$hashref}));
}
foreach my $key (@keys) {
$selectform.=
'&').'" '.
($key eq $def ? 'selected="selected" ' : '').
- ">".$hash{$key}." \n";
+ ">".$hashref->{$key}."\n";
}
$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'})).
' ';
}
@@ -2267,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;
@@ -3239,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
@@ -3405,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].' ';
@@ -3422,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 {
@@ -3459,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);
}
@@ -3609,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.' ';
}
##############################################
@@ -3734,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,
@@ -4139,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};
@@ -4175,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)) {
@@ -4334,7 +4496,7 @@ Returns: HTML div with $content
sub head_subbox {
my ($content)=@_;
my $output =
- ''
+ '
'
.$content
.'
'
}
@@ -4452,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);
@@ -4501,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
@@ -4522,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; }
@@ -4544,8 +4711,14 @@ sub bodytag {
$realm $dc_info
|;
return $bodytag;
}
+ if (($env{'request.noversionuri'} =~ m{^/adm/navmaps}) &&
+ ($env{'environment.remotenavmap'} eq 'on')) {
+ return $bodytag;
+ }
- $bodytag .= qq|$name $role
|;
+ unless ($env{'request.symb'} =~ m/\.page___\d+___/) {
+ $bodytag .= qq|$name $role
|;
+ }
$bodytag .= Apache::lonhtmlcommon::scripttag(
Apache::lonmenu::utilityfunctions(), 'start');
@@ -4558,7 +4731,7 @@ sub bodytag {
$bodytag .= qq|$realm $dc_info
|;
#don't show menus for public users
- if($env{'user.name'} ne 'public' && $env{'user.domain'} ne 'public'){
+ if (!$public){
$bodytag .= Apache::lonmenu::secondary_menu();
$bodytag .= Apache::lonmenu::serverform();
$bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
@@ -4575,8 +4748,6 @@ sub bodytag {
$bodytag .= Apache::lonhtmlcommon::scripttag('', 'end');
}
- #SD testing
- #$bodytag .= Apache::lonmenu::menubuttons($forcereg);
return $bodytag;
}
@@ -4598,10 +4769,13 @@ sub bodytag {
$dc_info = qq|($dc_info) |;
}
- $bodytag .= qq|$name $role
- $realm $dc_info
| unless $env{'form.inhibitmenu'};
+ unless ($env{'form.inhibitmenu'}) {
+ $bodytag .= qq|$name $role
+ $realm $dc_info
|;
+ }
+
return(<
@@ -4616,7 +4790,7 @@ ENDBODY
sub dc_courseid_toggle {
my ($dc_info) = @_;
- return ' '.
+ return ' '.
''.
&mt('(More ...)').' '.
''.$dc_info.'
';
@@ -4732,10 +4906,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;
@@ -4754,13 +4924,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 {
@@ -5275,23 +5490,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 {
@@ -5326,6 +5541,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,
@@ -5753,56 +5976,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%;
}
@@ -5836,15 +6044,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 {
@@ -5877,13 +6078,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,
@@ -5891,7 +6085,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;
}
@@ -5958,7 +6152,8 @@ fieldset > legend {
#LC_nav_bar {
float: left;
- margin: 0.2em 0 0 0;
+ background-color: $pgbg_or_bgcolor;
+ margin: 0 0 2px 0;
}
#LC_realm {
@@ -5966,6 +6161,7 @@ fieldset > legend {
padding: 0;
font-weight: bold;
text-align: center;
+ background-color: $pgbg_or_bgcolor;
}
#LC_nav_bar em {
@@ -5973,9 +6169,20 @@ fieldset > legend {
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;
+ background-color: $pgbg_or_bgcolor;
+}
+
+ol.LC_primary_menu a.LC_new_message {
+ font-weight:bold;
+ color: darkred;
}
ol#LC_PathBreadcrumbs {
@@ -5990,14 +6197,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;
@@ -6006,6 +6237,7 @@ ul#LC_secondary_menu {
padding: 0;
margin: 0;
width: 100%;
+ text-align: left;
}
ul#LC_secondary_menu li {
@@ -6037,14 +6269,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 {
@@ -6057,16 +6290,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;
}
@@ -6085,6 +6335,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;
@@ -6093,31 +6347,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;
@@ -6131,18 +6387,14 @@ ol#LC_MenuBreadcrumbs,
ol#LC_PathBreadcrumbs {
padding-left: 10px;
margin: 0;
- list-style-position: inside;
- /* SD working here
- white-space: nowrap; */
+ height: 2.5em; /* equal to #LC_breadcrumbs line-height */
}
ol#LC_MenuBreadcrumbs li,
ol#LC_PathBreadcrumbs li,
ul.LC_CourseBreadcrumbs li {
display: inline;
- white-space: nowrap;
- /* SD working here
- white-space: normal; */
+ white-space: normal;
}
ol#LC_MenuBreadcrumbs li a,
@@ -6151,6 +6403,14 @@ ul.LC_CourseBreadcrumbs li a {
font-size:90%;
}
+ol#LC_MenuBreadcrumbs h1 {
+ display: inline;
+ font-size: 90%;
+ line-height: 2.5em;
+ margin: 0;
+ padding: 0;
+}
+
ol#LC_PathBreadcrumbs li a {
text-decoration:none;
font-size:100%;
@@ -6247,52 +6507,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;
@@ -6395,6 +6609,11 @@ ul.LC_funclist {
padding: 0.5em 1em 0.5em 0;
}
+ul.LC_funclist > li:first-child {
+ font-weight:bold;
+ margin-left:0.8em;
+}
+
ul.LC_funclist + ul.LC_funclist {
/*
left border as a seperator if we have more than
@@ -6415,6 +6634,11 @@ ul.LC_funclist li {
line-height: 150%;
}
+.ui-accordion .LC_advanced_toggle {
+ float: right;
+ font-size: 90%;
+ padding: 0px 4px
+}
END
}
@@ -6529,10 +6753,6 @@ Inputs: none
sub xml_begin {
my $output='';
- if ($env{'internal.start_page'}==1) {
- &Apache::lonhtmlcommon::init_htmlareafields();
- }
-
if ($env{'browser.mathml'}) {
$output=''
#.''."\n"
@@ -6632,7 +6852,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
@@ -6827,15 +7047,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";;
}
@@ -7014,7 +7245,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';
@@ -7597,7 +7829,7 @@ sub get_secgrprole_info {
}
sub user_picker {
- my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype) = @_;
+ my ($dom,$srch,$forcenewuser,$caller,$cancreate,$usertype,$context) = @_;
my $currdom = $dom;
my %curr_selected = (
srchin => 'dom',
@@ -7688,10 +7920,15 @@ sub user_picker {
$srchtypesel .= "\n \n";
my ($newuserscript,$new_user_create);
-
+ my $context_dom = $env{'request.role.domain'};
+ if ($context eq 'requestcrs') {
+ if ($env{'form.coursedom'} ne '') {
+ $context_dom = $env{'form.coursedom'};
+ }
+ }
if ($forcenewuser) {
if (ref($srch) eq 'HASH') {
- if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $env{'request.role.domain'}) {
+ if ($srch->{'srchby'} eq 'uname' && $srch->{'srchtype'} eq 'exact' && $srch->{'srchin'} eq 'dom' && $srch->{'srchdomain'} eq $context_dom) {
if ($cancreate) {
$new_user_create = '';
- $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";
+ } 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 '');
@@ -8317,12 +8797,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;
}
@@ -8336,31 +8816,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
@@ -8390,19 +8892,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".
+ ''.&mt('For consistency between the reference(s) and the location of the corresponding stored file within LON-CAPA.').' '."\n".
+ ''.&mt('To change absolute paths to relative paths, or replace directory traversal via "../" within the original reference.').' '."\n".
+ ' '."\n".''.
+ &mt('LON-CAPA can make the required changes to your HTML file.').'
'."\n".
+ ''."\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;
}
@@ -8426,22 +9099,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);
+ }
+ }
}
}
}
@@ -8459,15 +9181,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
@@ -9989,19 +10751,19 @@ sub check_clone {
my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
my $clonemsg;
my $can_clone = 0;
- my $lctype = lc($args->{'type'});
+ my $lctype = lc($args->{'crstype'});
if ($lctype ne 'community') {
$lctype = 'course';
}
if ($clonehome eq 'no_host') {
- if ($args->{'type'} eq 'Community') {
+ if ($args->{'crstype'} eq 'Community') {
$clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
} else {
$clonemsg = &mt('No new course created.').$linefeed.&mt('A new course could not be cloned from the specified original - [_1] - because it is a non-existent course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
}
} else {
my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
- if ($args->{'type'} eq 'Community') {
+ if ($args->{'crstype'} eq 'Community') {
if ($clonedesc{'type'} ne 'Community') {
$clonemsg = &mt('No new community created.').$linefeed.&mt('A new community could not be cloned from the specified original - [_1] - because it is a course not a community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
return ($can_clone, $clonemsg, $cloneid, $clonehome);
@@ -10020,7 +10782,7 @@ sub check_clone {
$can_clone = 1;
} else {
my $ccrole = 'cc';
- if ($args->{'type'} eq 'Community') {
+ if ($args->{'crstype'} eq 'Community') {
$ccrole = 'co';
}
my %roleshash =
@@ -10029,9 +10791,11 @@ 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 {
- if ($args->{'type'} eq 'Community') {
+ $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 {
$clonemsg = &mt('No new course created.').$linefeed.&mt('The new course could not be cloned from the existing course because the new course owner ([_1]) does not have cloning rights in the existing course ([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'});
@@ -10090,11 +10854,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;
#
@@ -10113,6 +10885,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
@@ -10359,7 +11135,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';
}
@@ -10589,16 +11365,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";
@@ -10677,6 +11457,36 @@ sub clean_symb {
return ($symb,$enc);
}
+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);
+ }
+ } elsif ($item eq 'resourcetag') {
+ if ($name eq 'responsetype') {
+ $checkresponsetypes->{$value} = $Apache::lonnet::needsrelease{$key}
+ }
+ } elsif ($item eq 'course') {
+ if ($name eq 'crstype') {
+ $checkcrstypes->{$value} = $Apache::lonnet::needsrelease{$key};
+ }
+ }
+ }
+ ($anonsurvey->{major},$anonsurvey->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:anonsurvey'});
+ ($randomizetry->{major},$randomizetry->{minor}) = split(/\./,$Apache::lonnet::needsrelease{'parameter:type:randomizetry'});
+ return;
+}
+
=pod
=back