[LON-CAPA-cvs] cvs: loncom / lonsql /interface lonmeta.pm /lonnet/perl lonnet.pm /metadata_database searchcat.pl /metadata_database/LONCAPA lonmetadata.pm

raeburn lon-capa-cvs@mail.lon-capa.org
Tue, 02 Jan 2007 12:54:40 -0000


This is a MIME encoded message

--raeburn1167742480
Content-Type: text/plain

raeburn		Tue Jan  2 07:54:40 2007 EDT

  Modified files:              
    /loncom	lonsql 
    /loncom/metadata_database	searchcat.pl 
    /loncom/metadata_database/LONCAPA	lonmetadata.pm 
    /loncom/lonnet/perl	lonnet.pm 
    /loncom/interface	lonmeta.pm 
  Log:
  portfolio_metadata, portfolio_addedfields and portfolio_access tables in MySQL updated when portfolio access controls are modified or when portfolio metadata is updated.
  
  Some routines in searchcat.pl moved to LONCAPA::lonmetadata.pm so they are available to lonsql when performing MySQL table updates on the library server which houses the portfolio files.
  
  metadata updates and access control updates from lonmeta and lonnet::modify_access_controls are routed through lonnet::update_portfolio_table() which in turn does a querysend to dispatch a query to lonsql (via lond).
  
  Only access control settings for public and passphrase-protected controls are stored in the portfolio_access MySQL table. 
  
  
--raeburn1167742480
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20070102075440.txt"

Index: loncom/lonsql
diff -u loncom/lonsql:1.77 loncom/lonsql:1.78
--- loncom/lonsql:1.77	Thu May 11 13:53:22 2006
+++ loncom/lonsql	Tue Jan  2 07:51:31 2007
@@ -3,7 +3,7 @@
 # The LearningOnline Network
 # lonsql - LON TCP-MySQL-Server Daemon for handling database requests.
 #
-# $Id: lonsql,v 1.77 2006/05/11 17:53:22 albertel Exp $
+# $Id: lonsql,v 1.78 2007/01/02 12:51:31 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -117,6 +117,8 @@
 use DBI;
 use File::Find;
 use localenroll;
+use GDBM_File;
+use Storable qw(thaw);
 
 ########################################################
 ########################################################
@@ -471,6 +473,10 @@
                 } else {
                     $result = 'success';
                 }
+            } elsif (($query eq 'portfolio_metadata') || 
+                    ($query eq 'portfolio_access')) {
+                $result = &portfolio_table_update($query,$arg1,$arg2,
+                                                  $arg3);
             } else {
                 # Do an sql query
                 $result = &do_sql_query($query,$arg1,$arg2,$searchdomain);
@@ -632,6 +638,166 @@
 } # End of &do_sql_query
 
 } # End of scoping curly braces for &process_file and &do_sql_query
+
+sub portfolio_table_update { 
+    my ($query,$arg1,$arg2,$arg3) = @_;
+    my %tablenames = (
+                       'portfolio'   => 'portfolio_metadata',
+                       'access'      => 'portfolio_access',
+                       'addedfields' => 'portfolio_addedfields',
+                     );
+    my $result = 'ok';
+    my $tablechk = &check_table($query);
+    if ($tablechk == 0) {
+        my $request =
+   &LONCAPA::lonmetadata::create_metadata_storage($query,$query);
+        $dbh->do($request);
+        if ($dbh->err) {
+            &logthis("create $query".
+                     " ERROR: ".$dbh->errstr);
+                     $result = 'error';
+        }
+    }
+    if ($result eq 'ok') {
+        my ($uname,$udom) = split(/:/,&unescape($arg1));
+        my $file_name = &unescape($arg2);
+        my $group = &unescape($arg3);
+        my $is_course = 0;
+        if ($group ne '') {
+            $is_course = 1;
+        }
+        my $urlstart = '/uploaded/'.$udom.'/'.$uname;
+        my $pathstart = &propath($udom,$uname).'/userfiles';
+        my ($fullpath,$url);
+        if ($is_course) {
+            $fullpath = $pathstart.'/groups/'.$group.'/portfolio'.
+                        $file_name;
+            $url = $urlstart.'/groups/'.$group.'/portfolio'.$file_name;
+        } else {
+            $fullpath = $pathstart.'/portfolio'.$file_name;
+            $url = $urlstart.'/portfolio'.$file_name;
+        }
+        my %access = &get_access_hash($uname,$udom,$group.$file_name);
+        if ($query eq 'portfolio_metadata') {
+            if (-e $fullpath.'.meta') {
+                my %loghash = &LONCAPA::lonmetadata::process_portfolio_metadata($dbh,undef,\%tablenames,$url,$fullpath,$is_course,$udom,$uname,$group,'update');
+                if (keys(%loghash) > 0) {
+                    &portfolio_logging(%loghash);
+                }
+            }
+        } elsif ($query eq 'portfolio_access') {
+            my %loghash =
+     &LONCAPA::lonmetadata::process_portfolio_access_data($dbh,undef,
+         \%tablenames,$url,$fullpath,\%access,'update');
+            if (keys(%loghash) > 0) {
+                &portfolio_logging(%loghash);
+            } else {
+                my $available = 0;
+                foreach my $key (keys(%access)) {
+                    my ($num,$scope,$end,$start) =
+                        ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+                    if ($scope eq 'public' || $scope eq 'guest') {
+                        $available = 1;
+                        last;
+                    }
+                }
+                if ($available) {
+                    # Retrieve current values
+                    my $condition = 'url='.$dbh->quote("$url");
+                    my ($error,$row) =
+    &LONCAPA::lonmetadata::lookup_metadata($dbh,$condition,undef,
+                                           'portfolio_metadata');
+                    if (!$error) {
+                        if (!(ref($row->[0]) eq 'ARRAY')) {  
+                            my %loghash =
+     &LONCAPA::lonmetadata::process_portfolio_metadata($dbh,undef,
+         \%tablenames,$url,$fullpath,$is_course,$udom,$uname,$group);
+                            if (keys(%loghash) > 0) {
+                                &portfolio_logging(%loghash);
+                            }
+                        } 
+                    }
+                }
+            }
+        }
+    }
+    return $result;
+}
+
+sub get_access_hash {
+    my ($uname,$udom,$file) = @_;
+    my $hashref = &tie_user_hash($udom,$uname,'file_permissions',
+                                 &GDBM_READER());
+    my %curr_perms;
+    my %access; 
+    if ($hashref) {
+        while (my ($key,$value) = each(%$hashref)) {
+            $key = &unescape($key);
+            next if ($key =~ /^error: 2 /);
+            $curr_perms{$key}=&thaw_unescape($value);
+        }
+        if (!&untie_user_hash($hashref)) {
+            &logthis("error: ".($!+0)." untie (GDBM) Failed");
+        }
+    } else {
+        &logthis("error: ".($!+0)." tie (GDBM) Failed");
+    }
+    if (keys(%curr_perms) > 0) {
+        if (ref($curr_perms{$file."\0".'accesscontrol'}) eq 'HASH') {
+            foreach my $acl (keys(%{$curr_perms{$file."\0".'accesscontrol'}})) {
+                $access{$acl} = $curr_perms{$file."\0".$acl};
+            }
+        }
+    }
+    return %access;
+}
+
+sub thaw_unescape {
+    my ($value)=@_;
+    if ($value =~ /^__FROZEN__/) {
+        substr($value,0,10,undef);
+        $value=&unescape($value);
+        return &thaw($value);
+    }
+    return &unescape($value);
+}
+
+###########################################
+sub check_table {
+    my ($table_id) = @_;
+    my $sth=$dbh->prepare('SHOW TABLES');
+    $sth->execute();
+    my $aref = $sth->fetchall_arrayref;
+    $sth->finish();
+    if ($sth->err()) {
+        &logthis("fetchall_arrayref after SHOW TABLES".
+            " ERROR: ".$sth->errstr);
+        return undef;
+    }
+    my $result = 0;
+    foreach my $table (@{$aref}) {
+        if ($table->[0] eq $table_id) { 
+            $result = 1;
+            last;
+        }
+    }
+    return $result;
+}
+
+###########################################
+
+sub portfolio_logging {
+    my (%portlog) = @_;
+    foreach my $key (keys(%portlog)) {
+        if (ref($portlog{$key}) eq 'HASH') {
+            foreach my $item (keys(%{$portlog{$key}})) {
+                &logthis($portlog{$key}{$item});
+            }
+        }
+    }
+}
+
+
 ########################################################
 ########################################################
 
Index: loncom/metadata_database/searchcat.pl
diff -u loncom/metadata_database/searchcat.pl:1.74 loncom/metadata_database/searchcat.pl:1.75
--- loncom/metadata_database/searchcat.pl:1.74	Tue Jan  2 04:12:51 2007
+++ loncom/metadata_database/searchcat.pl	Tue Jan  2 07:52:22 2007
@@ -2,7 +2,7 @@
 # The LearningOnline Network
 # searchcat.pl "Search Catalog" batch script
 #
-# $Id: searchcat.pl,v 1.74 2007/01/02 09:12:51 raeburn Exp $
+# $Id: searchcat.pl,v 1.75 2007/01/02 12:52:22 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -237,7 +237,7 @@
         my $is_course = &Apache::lonnet::is_course($dom,$uname);
         my $curr_perm = &Apache::lonnet::get_portfile_permissions($dom,$uname);
         my %access = &Apache::lonnet::get_access_controls($curr_perm);
-        foreach my $file (keys(%access)) { 
+        foreach my $file (keys(%access)) {
             my ($group,$url,$fullpath);
             if ($is_course) {
                 ($group, my ($path)) = ($file =~ /^(\w+)(\/.+)$/);
@@ -248,10 +248,13 @@
                 $url = $urlstart.'/portfolio'.$file;
             }
             if (ref($access{$file}) eq 'HASH') {
-                &process_portfolio_access_data($url,$access{$file});
+                my %portaccesslog = 
+                    &LONCAPA::lonmetadata::process_portfolio_access_data($dbh,
+                           $simulate,\%newnames,$url,$fullpath,$access{$file});
+                &portfolio_logging(%portaccesslog);
             }
-            &process_portfolio_metadata($url,$fullpath,$is_course,$dom,
-                                        $uname,$group);
+            my %portmetalog = &LONCAPA::lonmetadata::process_portfolio_metadata($dbh,$simulate,\%newnames,$url,$fullpath,$is_course,$dom,$uname,$group);
+            &portfolio_logging(%portmetalog);
         }
     }
 }
@@ -302,6 +305,17 @@
     }
 }
 
+sub portfolio_logging {
+    my (%portlog) = @_;
+    foreach my $key (keys(%portlog)) {
+        if (ref($portlog{$key}) eq 'HASH') {
+            foreach my $item (keys(%{$portlog{$key}})) {
+                &log(0,$portlog{$key}{$item});
+            }
+        }
+    }
+}
+
 sub descend_tree {
     my ($dir,$depth,$alldomusers) = @_;
     if (-d $dir) {
@@ -322,89 +336,6 @@
     } 
 }
 
-sub process_portfolio_access_data {
-    my ($url,$access_hash) = @_;
-    foreach my $key (keys(%{$access_hash})) {
-        my $acc_data;
-        $acc_data->{url} = $url;
-        $acc_data->{keynum} = $key;
-        my ($num,$scope,$end,$start) =
-                        ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
-        next if (($scope ne 'public') && ($scope ne 'guest'));
-        $acc_data->{scope} = $scope;
-        if ($end != 0) {
-            $acc_data->{end} = &LONCAPA::lonmetadata::sqltime($end);
-        }
-        $acc_data->{start} = &LONCAPA::lonmetadata::sqltime($start);
-        if (! $simulate) {
-            my ($count,$err) =
-              &LONCAPA::lonmetadata::store_metadata($dbh,
-                                                $newnames{'access'},
-                                                'portfolio_access',$acc_data);
-            if ($err) {
-                &log(0,"MySQL Error Insert: ".$err);
-            }
-            if ($count < 1) {
-                &log(0,"Unable to insert record into MySQL database for $url");
-            }
-        }
-    }
-}
-
-sub process_portfolio_metadata {
-    my ($url,$fullpath,$is_course,$dom,$uname,$group) = @_;
-    my ($ref,$crs,$addedfields) = &portfolio_metadata($fullpath,$dom,$uname,
-                                                      $group);
-    &getfiledates($ref,$fullpath);
-    if ($is_course) {
-        $ref->{'groupname'} = $group;
-    }
-    my %Data;
-    if (ref($ref) eq 'HASH') {
-        %Data = %{$ref};
-    }
-    %Data = (
-             %Data,
-             'url'=>$url,
-             'version'=>'current',
-    );
-    if (! $simulate) {
-        my ($count,$err) =
-         &LONCAPA::lonmetadata::store_metadata($dbh,
-                                               $newnames{'portfolio'},
-                                               'portfolio_metadata',\%Data);
-        if ($err) {
-            &log(0,"MySQL Error Insert: ".$err);
-        }
-        if ($count < 1) {
-            &log(0,"Unable to insert record into MySQL portfolio_metadata database table for $url");
-        }
-        if (ref($addedfields) eq 'HASH') {
-            if (keys(%{$addedfields}) > 0) {
-                foreach my $key (keys(%{$addedfields})) {
-                    my $added_data = {
-                                'url'   => $url,
-                                'field' => $key,
-                                'value' => $addedfields->{$key},
-                                'courserestricted' => $crs,
-                    };
-                    ($count,$err) = &LONCAPA::lonmetadata::store_metadata($dbh,
-                                            $newnames{'addedfields'},
-                                            'portfolio_addedfields',
-                                            $added_data);
-                    if ($err) {
-                        &log(0,"MySQL Error Insert: ".$err);
-                    }
-                    if ($count < 1) {
-                        &log(0,"Unable to insert record into MySQL portfolio_addedfields database table for url = $url and field = $key");
-                    }
-                }
-            }
-        }
-    }
-    return;
-}
-
 ########################################################
 ########################################################
 ###                                                  ###
@@ -508,7 +439,7 @@
         %dyn=&get_dynamic_metadata($url);
         &count_type($url);
     }
-    &getfiledates($ref,$target);
+    &LONCAPA::lonmetadata::getfiledates($ref,$target);
     #
     my %Data = (
                 %$ref,
@@ -549,7 +480,8 @@
     if ($filename !~ /\.meta$/) { 
         $filename.='.meta';
     }
-    my $metastring=&getfile($Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'.$filename);
+    my $metastring = 
+        &LONCAPA::lonmetadata::getfile($Apache::lonnet::perlvar{'lonDocRoot'}.'/res/'.$filename);
     return undef if (! defined($metastring));
     my $parser=HTML::TokeParser->new(\$metastring);
     my $token;
@@ -580,125 +512,6 @@
     return \%metacache;
 }
 
-###############################################################
-###############################################################
-###                                                         ###
-###  &portfolio_metadata($filepath,$dom,$uname,$group) ###
-###   Retrieve metadata for the given file                  ###
-###   Returns array -                                       ###
-###      contains reference to metadatahash and             ###
-###         optional reference to addedfields hash          ###
-###                                                         ###
-###############################################################
-###############################################################
-sub portfolio_metadata {
-    my ($fullpath,$dom,$uname,$group)=@_;
-    my ($mime) = ( $fullpath=~/\.(\w+)$/ );
-    my %metacache=();
-    if ($fullpath !~ /\.meta$/) {
-        $fullpath .= '.meta';
-    }
-    my (@standard_fields,%addedfields);
-    my $colsref = 
-       $LONCAPA::lonmetadata::Portfolio_metadata_table_description;
-    if (ref($colsref) eq 'ARRAY') {
-        my @columns = @{$colsref};
-        foreach my $coldata (@columns) {
-            push(@standard_fields,$coldata->{'name'});
-        }
-    }
-    my $metastring=&getfile($fullpath);
-    if (! defined($metastring)) {
-        $metacache{'keys'}= 'owner,domain,mime';
-        $metacache{'owner'} = $uname.':'.$dom;
-        $metacache{'domain'} = $dom;
-        $metacache{'mime'} = $mime;
-        if ($group ne '') {
-            $metacache{'keys'} .= ',courserestricted';
-            $metacache{'courserestricted'} = 'course.'.$dom.'_'.$uname;
-        } 
-    } else {
-        my $parser=HTML::TokeParser->new(\$metastring);
-        my $token;
-        while ($token=$parser->get_token) {
-            if ($token->[0] eq 'S') {
-                my $entry=$token->[1];
-                if ($metacache{'keys'}) {
-                    $metacache{'keys'}.=','.$entry;
-                } else {
-                    $metacache{'keys'}=$entry;
-                }
-                my $value = $parser->get_text('/'.$entry);
-                if (!grep(/^\Q$entry\E$/,@standard_fields)) {
-                    my $clean_value = lc($value);
-                    $clean_value =~ s/\s/_/g;
-                    if ($clean_value ne $entry) {
-                        if (defined($addedfields{$entry})) {
-                            $addedfields{$entry} .=','.$value;
-                        } else {
-                            $addedfields{$entry} = $value;
-                        }
-                    }
-                } else {
-                    $metacache{$entry} = $value;
-                }
-            }
-        } # End of ($token->[0] eq 'S')
-    }
-    if (keys(%addedfields) > 0) {
-        foreach my $key (sort keys(%addedfields)) {
-            $metacache{'addedfieldnames'} .= $key.',';
-            $metacache{'addedfieldvalues'} .= $addedfields{$key}.'&&&';
-        }
-        $metacache{'addedfieldnames'} =~ s/,$//;
-        $metacache{'addedfieldvalues'} =~ s/\&\&\&$//;
-        if ($metacache{'keys'}) {
-            $metacache{'keys'}.=',addedfieldnames';
-        } else {
-            $metacache{'keys'}='addedfieldnames';
-        }
-        $metacache{'keys'}.=',addedfieldvalues';
-    }
-    return (\%metacache,$metacache{'courserestricted'},\%addedfields);
-}
-
-##
-## &getfile($filename)
-##   Slurps up an entire file into a scalar.  
-##   Returns undef if the file does not exist
-sub getfile {
-    my $file = shift();
-    if (! -e $file ) { 
-        return undef; 
-    }
-    my $fh=IO::File->new($file);
-    my $contents = '';
-    while (<$fh>) { 
-        $contents .= $_;
-    }
-    return $contents;
-}
-
-##
-## &getfiledates() 
-## Converts creationdate and modifieddates to SQL format 
-## Applies stat() to file to retrieve dates if missing
-sub getfiledates {
-    my ($ref,$target) = @_;
-    if (! defined($ref->{'creationdate'}) ||
-        $ref->{'creationdate'} =~ /^\s*$/) {
-        $ref->{'creationdate'} = (stat($target))[9];
-    }
-    if (! defined($ref->{'lastrevisiondate'}) ||
-        $ref->{'lastrevisiondate'} =~ /^\s*$/) {
-        $ref->{'lastrevisiondate'} = (stat($target))[9];
-    }
-    $ref->{'creationdate'}     = 
-        &LONCAPA::lonmetadata::sqltime($ref->{'creationdate'});
-    $ref->{'lastrevisiondate'} = 
-        &LONCAPA::lonmetadata::sqltime($ref->{'lastrevisiondate'});
-}
-
 ########################################################
 ########################################################
 ###                                                  ###
Index: loncom/metadata_database/LONCAPA/lonmetadata.pm
diff -u loncom/metadata_database/LONCAPA/lonmetadata.pm:1.15 loncom/metadata_database/LONCAPA/lonmetadata.pm:1.16
--- loncom/metadata_database/LONCAPA/lonmetadata.pm:1.15	Fri Dec 29 14:15:28 2006
+++ loncom/metadata_database/LONCAPA/lonmetadata.pm	Tue Jan  2 07:53:27 2007
@@ -1,6 +1,6 @@
 # The LearningOnline Network with CAPA
 #
-# $Id: lonmetadata.pm,v 1.15 2006/12/29 19:15:28 raeburn Exp $
+# $Id: lonmetadata.pm,v 1.16 2007/01/02 12:53:27 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -30,6 +30,7 @@
 
 use strict;
 use DBI;
+use HTML::TokeParser;
 use vars qw($Metadata_Table_Description $Portfolio_metadata_table_description 
 $Portfolio_access_table_description $Fulltext_indicies $Portfolio_metadata_indices $Portfolio_access_indices $Portfolio_addedfields_table_description $Portfolio_addedfields_indices);
 
@@ -502,7 +503,7 @@
                 $error = $sth->errstr;
             }
         }
-    }
+    } 
     return ($error,$returnvalue);
 }
 
@@ -928,10 +929,237 @@
     return %Store;
 }
 
+###############################################################
+###############################################################
+###                                                         ###
+###  &portfolio_metadata($filepath,$dom,$uname,$group)      ###
+###   Retrieve metadata for the given file                  ###
+###   Returns array -                                       ###
+###      contains reference to metadatahash and             ###
+###         optional reference to addedfields hash          ###
+###                                                         ###
+###############################################################
+###############################################################
+
+sub portfolio_metadata {
+    my ($fullpath,$dom,$uname,$group)=@_;
+    my ($mime) = ( $fullpath=~/\.(\w+)$/ );
+    my %metacache=();
+    if ($fullpath !~ /\.meta$/) {
+        $fullpath .= '.meta';
+    }
+    my (@standard_fields,%addedfields);
+    my $colsref = $Portfolio_metadata_table_description;
+    if (ref($colsref) eq 'ARRAY') {
+        my @columns = @{$colsref};
+        foreach my $coldata (@columns) {
+            push(@standard_fields,$coldata->{'name'});
+        }
+    }
+    my $metastring=&getfile($fullpath);
+    if (! defined($metastring)) {
+        $metacache{'keys'}= 'owner,domain,mime';
+        $metacache{'owner'} = $uname.':'.$dom;
+        $metacache{'domain'} = $dom;
+        $metacache{'mime'} = $mime;
+        if ($group ne '') {
+            $metacache{'keys'} .= ',courserestricted';
+            $metacache{'courserestricted'} = 'course.'.$dom.'_'.$uname;
+        }
+    } else {
+        my $parser=HTML::TokeParser->new(\$metastring);
+        my $token;
+        while ($token=$parser->get_token) {
+            if ($token->[0] eq 'S') {
+                my $entry=$token->[1];
+                if ($metacache{'keys'}) {
+                    $metacache{'keys'}.=','.$entry;
+                } else {
+                    $metacache{'keys'}=$entry;
+                }
+                my $value = $parser->get_text('/'.$entry);
+                if (!grep(/^\Q$entry\E$/,@standard_fields)) {
+                    my $clean_value = lc($value);
+                    $clean_value =~ s/\s/_/g;
+                    if ($clean_value ne $entry) {
+                        if (defined($addedfields{$entry})) {
+                            $addedfields{$entry} .=','.$value;
+                        } else {
+                            $addedfields{$entry} = $value;
+                        }
+                    }
+                } else {
+                    $metacache{$entry} = $value;
+                }
+            }
+        } # End of ($token->[0] eq 'S')
+    }
+    if (keys(%addedfields) > 0) {
+        foreach my $key (sort keys(%addedfields)) {
+            $metacache{'addedfieldnames'} .= $key.',';
+            $metacache{'addedfieldvalues'} .= $addedfields{$key}.'&&&';
+        }
+        $metacache{'addedfieldnames'} =~ s/,$//;
+        $metacache{'addedfieldvalues'} =~ s/\&\&\&$//;
+        if ($metacache{'keys'}) {
+            $metacache{'keys'}.=',addedfieldnames';
+        } else {
+            $metacache{'keys'}='addedfieldnames';
+        }
+        $metacache{'keys'}.=',addedfieldvalues';
+    }
+    return (\%metacache,$metacache{'courserestricted'},\%addedfields);
+}
+
+sub process_portfolio_access_data {
+    my ($dbh,$simulate,$newnames,$url,$fullpath,$access_hash,$caller) = @_;
+    my %loghash;
+    if ($caller eq 'update') {
+        # Delete old data (no error if deleting non-existent record).
+        my $error=&delete_metadata($dbh,$newnames->{'access'},$url);
+        if (defined($error)) {
+            $loghash{'access'}{'err'} = "MySQL Error Delete: ".$error;
+            return %loghash;
+        }
+    }
+    # Check the file exists
+    if (-e $fullpath) {
+        foreach my $key (keys(%{$access_hash})) {
+            my $acc_data;
+            $acc_data->{url} = $url;
+            $acc_data->{keynum} = $key;
+            my ($num,$scope,$end,$start) =
+                            ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+            next if (($scope ne 'public') && ($scope ne 'guest'));
+            $acc_data->{scope} = $scope;
+            if ($end != 0) {
+                $acc_data->{end} = &sqltime($end);
+            }
+            $acc_data->{start} = &sqltime($start);
+            if (! $simulate) {
+                my ($count,$err) =
+                     &store_metadata($dbh,$newnames->{'access'},
+                                     'portfolio_access',$acc_data);
+                if ($err) {
+                    $loghash{$key}{'err'} = "MySQL Error Insert: ".$err;
+                }
+                if ($count < 1) {
+                    $loghash{$key}{'count'} = 
+                        "Unable to insert record into MySQL database for $url";
+                }
+            }
+        }
+    }
+    return %loghash;
+}
+
+sub process_portfolio_metadata {
+    my ($dbh,$simulate,$newnames,$url,$fullpath,$is_course,$dom,$uname,$group,$caller) = @_;
+    my %loghash;
+    if ($caller eq 'update') {
+        # Delete old data (no error if deleting non-existent record).
+        my $error=&delete_metadata($dbh,$newnames->{'portfolio'},$url);
+        if (defined($error)) {
+            $loghash{'metadata'}{'err'} = "MySQL Error delete metadata: ".
+                                               $error;
+            return %loghash;
+        }
+        $error=&delete_metadata($dbh,$newnames->{'addedfields'},$url);
+        if (defined($error)) {
+            $loghash{'addedfields'}{'err'}="MySQL Error delete addedfields: ".$error;
+        }
+    }
+    # Check the file exists.
+    if (-e $fullpath) {
+        my ($ref,$crs,$addedfields) = &portfolio_metadata($fullpath,$dom,$uname,
+                                                          $group);
+        &getfiledates($ref,$fullpath);
+        if ($is_course) {
+            $ref->{'groupname'} = $group;
+        }
+        my %Data;
+        if (ref($ref) eq 'HASH') {
+            %Data = %{$ref};
+        }
+        %Data = (
+                 %Data,
+                 'url'=>$url,
+                 'version'=>'current',
+        );
+        my %loghash;
+        if (! $simulate) {
+            my ($count,$err) =
+            &store_metadata($dbh,$newnames->{'portfolio'},'portfolio_metadata',
+                            \%Data);
+            if ($err) {
+                $loghash{'metadata'."\0"}{'err'} = "MySQL Error Insert: ".$err;
+            }
+            if ($count < 1) {
+                $loghash{'metadata'."\0"}{'count'} = "Unable to insert record into MySQL portfolio_metadata database table for $url";
+            }
+            if (ref($addedfields) eq 'HASH') {
+                if (keys(%{$addedfields}) > 0) {
+                    foreach my $key (keys(%{$addedfields})) {
+                        my $added_data = {
+                                    'url'   => $url,
+                                    'field' => $key,
+                                    'value' => $addedfields->{$key},
+                                    'courserestricted' => $crs,
+                        };
+                        my ($count,$err) = 
+                            &store_metadata($dbh,$newnames->{'addedfields'},
+                                   'portfolio_addedfields',$added_data);
+                        if ($err) {
+                            $loghash{$key}{'err'} = 
+                                "MySQL Error Insert: ".$err;
+                        }
+                        if ($count < 1) {
+                            $loghash{$key}{'count'} = "Unable to insert record into MySQL portfolio_addedfields database table for url = $url and field = $key";
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return %loghash;
+}
+
 ######################################################################
 ######################################################################
 
-## Utility originally in searchcat.pl.  Moved to be more widely available. 
+## Utilities originally in searchcat.pl.  Moved to be more widely available.
+
+sub getfile {
+    my $file = shift();
+    if (! -e $file ) { 
+        return undef; 
+    }
+    my $fh=IO::File->new($file);
+    my $contents = '';
+    while (<$fh>) { 
+        $contents .= $_;
+    }
+    return $contents;
+}
+
+##
+## &getfiledates()
+## Converts creationdate and modifieddates to SQL format
+## Applies stat() to file to retrieve dates if missing
+sub getfiledates {
+    my ($ref,$target) = @_;
+    if (! defined($ref->{'creationdate'}) ||
+        $ref->{'creationdate'} =~ /^\s*$/) {
+        $ref->{'creationdate'} = (stat($target))[9];
+    }
+    if (! defined($ref->{'lastrevisiondate'}) ||
+        $ref->{'lastrevisiondate'} =~ /^\s*$/) {
+        $ref->{'lastrevisiondate'} = (stat($target))[9];
+    }
+    $ref->{'creationdate'}     = &sqltime($ref->{'creationdate'});
+    $ref->{'lastrevisiondate'} = &sqltime($ref->{'lastrevisiondate'});
+}
+ 
 ##
 ## &sqltime($timestamp)
 ##
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.817 loncom/lonnet/perl/lonnet.pm:1.818
--- loncom/lonnet/perl/lonnet.pm:1.817	Thu Dec 28 15:09:10 2006
+++ loncom/lonnet/perl/lonnet.pm	Tue Jan  2 07:53:58 2007
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.817 2006/12/28 20:09:10 raeburn Exp $
+# $Id: lonnet.pm,v 1.818 2007/01/02 12:53:58 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -4096,6 +4096,18 @@
     return get_query_reply($queryid);
 }
 
+# -------------------------- Update MySQL table for portfolio file
+
+sub update_portfolio_table {
+    my ($uname,$udom,$file_name,$query,$group) = @_;
+    my $homeserver = &homeserver($uname,$udom);
+    my $queryid=
+        &reply("querysend:".$query.':'.&escape($uname.':'.$udom).':'.
+              &escape($file_name).':'.&escape($group),$homeserver);
+    my $reply = &get_query_reply($queryid);
+    return $reply;
+}
+
 # ------- Request retrieval of institutional classlists for course(s)
 
 sub fetch_enrollment_query {
@@ -5259,6 +5271,15 @@
         #  remove lock
         my @del_lock = ($file_name."\0".'locked_access_records');
         my $dellockoutcome = &del('file_permissions',\@del_lock,$domain,$user);
+        my ($file,$group);
+        if (&is_course($domain,$user)) {
+            ($group,$file) = split(/\//,$file_name,2);
+        } else {
+            $file = $file_name;
+        }
+        my $sqlresult =
+            &update_portfolio_table($user,$domain,$file,'portfolio_access',
+                                    $group);
     } else {
         $outcome = "error: could not obtain lockfile\n";  
     }
Index: loncom/interface/lonmeta.pm
diff -u loncom/interface/lonmeta.pm:1.191 loncom/interface/lonmeta.pm:1.192
--- loncom/interface/lonmeta.pm:1.191	Tue Jan  2 06:38:28 2007
+++ loncom/interface/lonmeta.pm	Tue Jan  2 07:54:40 2007
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Metadata display handler
 #
-# $Id: lonmeta.pm,v 1.191 2007/01/02 11:38:28 raeburn Exp $
+# $Id: lonmeta.pm,v 1.192 2007/01/02 12:54:40 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1349,7 +1349,7 @@
 		    ($path, $new_fn) = ($fn =~ m|/(portfolio.*)/([^/]*)$|);
 	        }
                 $r->print(&store_portfolio_metadata($formname,$file_content,$path,
-                                                    $new_fn));
+                                                    $new_fn,$uri));
             } else {
 		if (! ($mfh=Apache::File->new('>'.$fn))) {
 		    $r->print('<p><font color="red">'.
@@ -1358,6 +1358,7 @@
 		} else {
 		    print $mfh ($file_content);
                     close($mfh);
+                    &update_metadata_table($uri);
 		    $r->print('<p><font color="blue">'.&mt('Wrote Metadata').
 			      ' '.&Apache::lonlocal::locallocaltime(time).
 			      '</font></p>');
@@ -1388,7 +1389,7 @@
 }
 
 sub store_portfolio_metadata {
-    my ($formname,$content,$path,$new_fn) = @_;
+    my ($formname,$content,$path,$new_fn,$uri) = @_;
     $env{'form.'.$formname}=$content."\n";
     $env{'form.'.$formname.'.filename'}=$new_fn;
     my $result =&Apache::lonnet::userfileupload($formname,'',$path);
@@ -1397,11 +1398,50 @@
                   &mt('Could not write metadata').', '.
                   &mt('FAIL').'</font></p>';
     } else {
+        &update_metadata_table($uri);
         return '<p><font color="blue">'.&mt('Wrote Metadata').
                   ' '.&Apache::lonlocal::locallocaltime(time).'</font></p>';
     }
 }
 
+sub update_metadata_table {
+    my ($uri) = @_;
+    my ($group,$file_name);
+    my ($udom,$uname,$remainder) =
+        ($uri=~m -^/+(?:uploaded|editupload)/+($match_domain)/+($match_name)/+(.*)$-);
+
+    if ($remainder =~ /groups\/(\w+)\/portfolio(\/.+)$/) {
+        $group = $1;
+        $file_name = $2;
+    } elsif ($remainder =~ /portfolio(\/.+)$/) {
+        $file_name = $1;
+    }
+    $file_name =~ s/\.meta$//;
+    my $current_permissions =
+        &Apache::lonnet::get_portfile_permissions($udom,$uname);
+    my %access_controls =
+        &Apache::lonnet::get_access_controls($current_permissions,$group,
+                                             $group.$file_name);
+    my $access_hash = $access_controls{$file_name};
+    my $available = 0;
+    if (ref($access_hash) eq 'HASH') {
+        foreach my $key (keys(%{$access_hash})) {
+            my ($num,$scope,$end,$start) =
+                ($key =~ /^([^:]+):([a-z]+)_(\d*)_?(\d*)$/);
+            if ($scope eq 'public' || $scope eq 'guest') {
+                $available = 1;
+                last;
+            }
+        }
+    }
+    if ($available) {
+        my $result =
+            &Apache::lonnet::update_portfolio_table($uname,$udom,
+            $file_name,'portfolio_metadata',$group);
+    }
+}
+
+
 1;
 __END__
 

--raeburn1167742480--