--- loncom/interface/portfolio.pm	2014/12/07 19:45:19	1.255
+++ loncom/interface/portfolio.pm	2019/08/07 16:08:04	1.260
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # portfolio browser
 #
-# $Id: portfolio.pm,v 1.255 2014/12/07 19:45:19 raeburn Exp $
+# $Id: portfolio.pm,v 1.260 2019/08/07 16:08:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -112,13 +112,17 @@ sub display_common {
 END
         }
 
+        # Find space available before uploading
+        my $free_space = &free_space($group);
+
         # Upload File
         $r->print('<div class="LC_left_float">'
                  .'<form method="post" enctype="multipart/form-data" action="'.$escuri.'">'
                  .'<fieldset>'
                  .'<legend>'.$lt{'upload_label'}.'</legend>'
                  .$groupitem 
-                 .'<input name="uploaddoc" type="file" />'
+                 .'<input name="uploaddoc" type="file" class="LC_flUpload" />'
+                 .'<input type="hidden" id="free_space" value="'.$free_space.'" />'
                  .'<input type="hidden" name="currentpath" value="'.$current_path.'" />'
                  .'<input type="hidden" name="action" value="'.$env{"form.action"}.'" />'
                  .'<input type="hidden" name="symb" value="'.$env{"form.symb"}.'" />'
@@ -199,7 +203,8 @@ sub display_portfolio_usage {
                     .$helpitem
                     .'</div>'
                     .'<div>'
-                    .&Apache::lonhtmlcommon::display_usage($current_disk_usage,$disk_quota)
+                    .&Apache::lonhtmlcommon::display_usage($current_disk_usage,
+                                                           $disk_quota,'portfolio')
                     .'</div>');
 }
 
@@ -1068,7 +1073,7 @@ sub build_access_summary {
                     $r->print(&mt('Users: ').$curr_user_list);
                 } elsif ($scope eq 'ip') {
                     my $curr_ips_list = &sort_ips($content->{'ip'});
-                    $r->print(&mt('IP(s): ').$curr_ips_list);
+                    $r->print(&mt('IP(s):').' '.$curr_ips_list);
                 } else {
                     $r->print('&nbsp;');
                 }
@@ -2567,7 +2572,7 @@ sub get_quota {
     } else {
         $disk_quota = &Apache::loncommon::get_user_quota($env{'user.name'},
                                     $env{'user.domain'}); #expressed in MB
-        $disk_quota = 1000 * $disk_quota; # convert from MB to kB
+        $disk_quota = 1024 * $disk_quota; # convert from MB to kB
     }
     return $disk_quota;
 }
@@ -2597,6 +2602,58 @@ STATE
     return $state;
 }
 
+# Find space available in a user's portfolio (convert to bytes)
+sub free_space {
+    my ($group) = @_;
+    my $disk_quota = &get_quota($group); # Expressed in kB
+    my ($uname,$udom) = &get_name_dom($group);
+    my $portfolio_root = &get_portfolio_root();
+    my $getpropath = 1;
+    my $current_disk_usage = &Apache::lonnet::diskusage($udom, $uname,
+                             $portfolio_root, $getpropath); # Expressed in kB
+    my $free_space = 1024 * ($disk_quota - $current_disk_usage);
+    return $free_space;
+}
+
+sub valid_container {
+    my ($uname,$udom,$group) = @_;
+    my $container_prefix;
+    if ($group ne '') {
+        $container_prefix = "/uploaded/$udom/$uname/groups/$group/portfolio";
+    } else {
+        $container_prefix = "/uploaded/$udom/$uname/portfolio";
+    }
+    if ($env{'form.currentpath'}) {
+        $container_prefix .= $env{'form.currentpath'};
+    } else {
+        $container_prefix .= '/';
+    }
+    if ($env{'form.container'} =~ m{^\Q$container_prefix\E(.+)$}) {
+        my $filename = $1;
+        if ($filename eq &Apache::lonnet::clean_filename($filename)) {
+            return 1;
+        }
+    }
+    return;
+}
+
+sub invalid_parms {
+    my ($r,$url,$currentpath) = @_;
+    my $escpath = &HTML::Entities::encode($currentpath,'&<>"');
+    my $rtnlink = '<a href="'.$url;
+    if ($url =~ /\?/) {
+        $rtnlink .= '&';
+    } else {
+        $rtnlink .= '?';
+    }
+    $rtnlink .= 'currentpath='.$escpath;
+    $rtnlink .= '">'.&mt('Return to directory').'</a>';
+    $r->print('<h3>'.&mt('Action disallowed').'</h3>');
+    $r->print(&mt('Some of the data included with this request were invalid'));
+    $r->print('<br />'.$rtnlink);
+    return;
+}
+
 sub handler {
     # this handles file management
     my $r = shift;
@@ -2684,16 +2741,19 @@ sub handler {
     # Give the LON-CAPA page header
     my $brcrum = [{href=>"/adm/portfolio",text=>"Portfolio Manager"}];
 
+    my $js = '<script type="text/javascript"
+                src="/res/adm/includes/file_upload.js"></script>';
+    
     if ($env{"form.mode"} eq 'selectfile'){
-        $r->print(&Apache::loncommon::start_page($title,undef,
+        $r->print(&Apache::loncommon::start_page($title, $js,
 						 {'only_body' => 1}));
     } elsif ($env{'form.action'} eq 'rolepicker') {
-        $r->print(&Apache::loncommon::start_page('New role-based condition',undef,
+        $r->print(&Apache::loncommon::start_page('New role-based condition', $js,
                                                  {'no_nav_bar'  => 1, }));
     } elsif ($caller eq 'coursegrp_portfolio') {
-        $r->print(&Apache::loncommon::start_page($title));
+        $r->print(&Apache::loncommon::start_page($title, $js));
     } else {
-        $r->print(&Apache::loncommon::start_page($title,undef,
+        $r->print(&Apache::loncommon::start_page($title, $js,
                                                  {'bread_crumbs' => $brcrum}));
         if (!&Apache::lonnet::usertools_access($uname,$udom,'portfolio')) {
             $r->print('<h2>'.&mt('No user portfolio available') .'</h2>'.
@@ -2742,6 +2802,21 @@ sub handler {
             $r->print(&Apache::loncommon::end_page());
             return OK;
         }
+    }
+    if (($env{'form.currentpath'}) && ($env{'form.currentpath'} ne '/')) {
+        my $clean_currentpath = '/'.&Apache::loncommon::clean_path($env{'form.currentpath'}).'/';
+        unless ($env{'form.currentpath'} eq $clean_currentpath) {
+            &invalid_parms($r,$url);
+            $r->print(&Apache::loncommon::end_page());
+            return OK;
+        }
+    }
+    if ($env{'form.container'}) {
+        unless (&valid_container($uname,$udom,$group)) {
+            &invalid_parms($r,$url,$env{'form.currentpath'});
+            $r->print(&Apache::loncommon::end_page());
+            return OK;
+        }
     }
     if (($env{'form.storeupl'}) & (!$env{'form.uploaddoc.filename'})){
    	$r->print(