Diff for /loncom/metadata_database/searchcat.pl between versions 1.54 and 1.55

version 1.54, 2004/01/05 15:54:22 version 1.55, 2004/04/08 15:57:32
Line 66  and correct user experience. Line 66  and correct user experience.
   
 use strict;  use strict;
   
   use DBI;
 use lib '/home/httpd/lib/perl/';  use lib '/home/httpd/lib/perl/';
 use LONCAPA::Configuration;  use LONCAPA::Configuration;
   use LONCAPA::lonmetadata;
   
 use IO::File;  use IO::File;
 use HTML::TokeParser;  use HTML::TokeParser;
 use DBI;  
 use GDBM_File;  use GDBM_File;
 use POSIX qw(strftime mktime);  use POSIX qw(strftime mktime);
   use File::Find;
   
 require "find.pl";  ##
   ## Use variables for table names so we can test this routine a little easier
 my @metalist;  my $oldname = 'metadata';
   my $newname = 'newmetadata';
 my $simplestatus='';  
 my %countext=();  
   
 # ----------------------------------------------------- write out simple status  
 sub writesimple {  
     open(SMP,'>/home/httpd/html/lon-status/mysql.txt');  
     print SMP $simplestatus."\n";  
     close(SMP);  
 }  
   
 sub writecount {  
     open(RSMP,'>/home/httpd/html/lon-status/rescount.txt');  
     foreach (keys %countext) {  
  print RSMP $_.'='.$countext{$_}.'&';  
     }  
     print RSMP 'time='.time."\n";  
     close(RSMP);  
 }  
   
 # -------------------------------------- counts files with different extensions  
 sub count {  
     my $file=shift;  
     $file=~/\.(\w+)$/;  
     my $ext=lc($1);  
     if (defined($countext{$ext})) {  
  $countext{$ext}++;  
     } else {  
  $countext{$ext}=1;  
     }  
 }  
 # ----------------------------------------------------- Un-Escape Special Chars  
   
 sub unescape {  
     my $str=shift;  
     $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;  
     return $str;  
 }  
   
 # -------------------------------------------------------- Escape Special Chars  
   
 sub escape {  #
     my $str=shift;  # Read loncapa_apache.conf and loncapa.conf
     $str =~ s/(\W)/"%".unpack('H2',$1)/eg;  
     return $str;  
 }  
   
 # ------------------------------------------- Code to evaluate dynamic metadata  
   
 sub dynamicmeta {  
     my $url=&declutter(shift);  
     $url=~s/\.meta$//;  
     my %returnhash=(  
     'count' => 0,  
     'course' => 0,  
     'course_list' => '',  
     'avetries' => 'NULL',  
     'avetries_list' => '',  
     'stdno' => 0,  
     'stdno_list' => '',  
     'usage' => 0,  
     'usage_list' => '',  
     'goto' => 0,  
     'goto_list' => '',  
     'comefrom' => 0,  
     'comefrom_list' => '',  
     'difficulty' => 'NULL',  
     'difficulty_list' => '',  
                     'clear' => 'NULL',  
                     'technical' => 'NULL',  
     'correct' => 'NULL',  
     'helpful' => 'NULL',  
     'depth' => 'NULL',  
     'comments' => ''  
     );  
     my ($adomain,$aauthor)=($url=~/^(\w+)\/(\w+)\//);  
     my $prodir=&propath($adomain,$aauthor);  
   
 # Get metadata except counts  
     if (tie(my %evaldata,'GDBM_File',  
             $prodir.'/nohist_resevaldata.db',&GDBM_READER(),0640)) {  
  my %sum=();  
  my %cnt=();  
  my %concat=();  
  my %listitems=(  
        'course'       => 'add',  
        'goto'         => 'add',  
        'comefrom'     => 'add',  
        'avetries'     => 'avg',  
        'stdno'        => 'add',  
        'difficulty'   => 'avg',  
        'clear'        => 'avg',  
        'technical'    => 'avg',  
        'helpful'      => 'avg',  
        'correct'      => 'avg',  
        'depth'        => 'avg',  
        'comments'     => 'app',  
        'usage'        => 'cnt'  
        );  
   
  my $regexp=$url;  
  $regexp=~s/(\W)/\\$1/g;  
  $regexp='___'.$regexp.'___([a-z]+)$';  
  while (my ($esckey,$value)=each %evaldata) {  
     my $key=&unescape($esckey);  
     if ($key=~/$regexp/) {  
  my ($item,$purl,$cat)=split(/___/,$key);  
  if (defined($cnt{$cat})) { $cnt{$cat}++; } else { $cnt{$cat}=1; }  
  unless ($listitems{$cat} eq 'app') {  
     if (defined($sum{$cat})) {  
  $sum{$cat}+=&unescape($evaldata{$esckey});  
  $concat{$cat}.=','.$item;  
     } else {  
  $sum{$cat}=&unescape($evaldata{$esckey});  
  $concat{$cat}=$item;  
     }  
  } else {  
     if (defined($sum{$cat})) {  
  if ($evaldata{$esckey}=~/\w/) {  
     $sum{$cat}.='<hr />'.&unescape($evaldata{$esckey});  
  }  
     } else {  
  $sum{$cat}=''.&unescape($evaldata{$esckey});  
     }  
  }  
     }  
  }  
  untie(%evaldata);  
 # transfer gathered data to returnhash, calculate averages where applicable  
  while (my $cat=each(%cnt)) {  
     if ($cnt{$cat} eq 'nan') { next; }  
     if ($sum{$cat} eq 'nan') { next; }  
     if ($listitems{$cat} eq 'avg') {  
  if ($cnt{$cat}) {  
     $returnhash{$cat}=int(($sum{$cat}/$cnt{$cat})*100.0+0.5)/100.0;  
  } else {  
     $returnhash{$cat}='NULL';  
  }  
     } elsif ($listitems{$cat} eq 'cnt') {  
  $returnhash{$cat}=$cnt{$cat};  
     } else {  
  $returnhash{$cat}=$sum{$cat};  
     }  
     $returnhash{$cat.'_list'}=$concat{$cat};  
  }  
     }  
 # get count  
     if (tie(my %evaldata,'GDBM_File',  
             $prodir.'/nohist_accesscount.db',&GDBM_READER(),0640)) {  
  my $escurl=&escape($url);  
  if (! exists($evaldata{$escurl})) {  
     $returnhash{'count'}=0;  
  } else {  
     $returnhash{'count'}=$evaldata{$escurl};  
  }  
  untie %evaldata;  
     }  
     return %returnhash;  
 }  
     
 # ---------------  Read loncapa_apache.conf and loncapa.conf and get variables  
 my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');  my $perlvarref=LONCAPA::Configuration::read_conf('loncapa.conf');
 my %perlvar=%{$perlvarref};  my %perlvar=%{$perlvarref};
 undef $perlvarref;  undef $perlvarref;
 delete $perlvar{'lonReceipt'}; # remove since sensitive and not needed  delete $perlvar{'lonReceipt'}; # remove since sensitive (really?) & not needed
   #
 # ------------------------------------- Only run if machine is a library server  # Only run if machine is a library server
 exit unless $perlvar{'lonRole'} eq 'library';  exit if ($perlvar{'lonRole'} ne 'library');
   #
 # ----------------------------- Make sure this process is running from user=www  #  Make sure this process is running from user=www
   
 my $wwwid=getpwnam('www');  my $wwwid=getpwnam('www');
 if ($wwwid!=$<) {  if ($wwwid!=$<) {
     my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";      my $emailto="$perlvar{'lonAdmEMail'},$perlvar{'lonSysEMail'}";
Line 257  if ($wwwid!=$<) { Line 101  if ($wwwid!=$<) {
  mailto $emailto -s '$subj' > /dev/null");   mailto $emailto -s '$subj' > /dev/null");
     exit 1;      exit 1;
 }  }
   #
   # Let people know we are running
 # ---------------------------------------------------------- We are in business  
   
 open(LOG,'>'.$perlvar{'lonDaemons'}.'/logs/searchcat.log');  open(LOG,'>'.$perlvar{'lonDaemons'}.'/logs/searchcat.log');
 print LOG '==== Searchcat Run '.localtime()."====\n\n";  print LOG '==== Searchcat Run '.localtime()."====\n";
 $simplestatus='time='.time.'&';  #
   # Connect to database
 my $dbh;  my $dbh;
 # ------------------------------------- Make sure that database can be accessed  if (! ($dbh = DBI->connect("DBI:mysql:loncapa","www",$perlvar{'lonSqlAccess'},
 {                            { RaiseError =>0,PrintError=>0}))) {
     unless (      print LOG "Cannot connect to database!\n";
     $dbh = DBI->connect("DBI:mysql:loncapa","www",$perlvar{'lonSqlAccess'},{ RaiseError =>0,PrintError=>0})      die "MySQL Error: Cannot connect to database!\n";
     ) {   }
  print LOG "Cannot connect to database!\n";  # This can return an error and still be okay, so we do not bother checking.
  $simplestatus.='mysql=defunct';  # (perhaps it should be more robust and check for specific errors)
  &writesimple();  $dbh->do('DROP TABLE IF EXISTS '.$newname);
  exit;  #
     }  # Create the new table
   my $request = &LONCAPA::lonmetadata::create_metadata_storage($newname);
 # Make temporary table  $dbh->do($request);
     $dbh->do("DROP TABLE IF EXISTS newmetadata");  if ($dbh->err) {
     my $make_metadata_table = "CREATE TABLE IF NOT EXISTS newmetadata (".      $dbh->disconnect();
         "title TEXT, author TEXT, subject TEXT, url TEXT, keywords TEXT, ".      print LOG "\nMySQL Error Create: ".$dbh->errstr."\n";
         "version TEXT, notes TEXT, abstract TEXT, mime TEXT, language TEXT, ".      die $dbh->errstr;
         "creationdate DATETIME, lastrevisiondate DATETIME, owner TEXT, ".  
         "copyright TEXT, dependencies TEXT, ".  
  "modifyinguser TEXT, authorspace TEXT, ".  
  "lowestgradelevel INTEGER UNSIGNED, highestgradelevel INTEGER UNSIGNED, ".  
  "standards TEXT, ".  
         "count INTEGER UNSIGNED, ".  
         "course INTEGER UNSIGNED, course_list TEXT, ".  
         "goto INTEGER UNSIGNED, goto_list TEXT, ".  
         "comefrom INTEGER UNSIGNED, comefrom_list TEXT, ".  
         "sequsage INTEGER UNSIGNED, sequsage_list TEXT, ".  
         "stdno INTEGER UNSIGNED, stdno_list TEXT, ".  
  "avetries FLOAT, avetries_list TEXT, ".  
         "difficulty FLOAT, difficulty_list TEXT, ".  
  "clear FLOAT, technical FLOAT, correct FLOAT, helpful FLOAT, depth FLOAT, ".  
  "comments TEXT, ".  
 # For backward compatibility, only insert new fields below  
 # ...  
 # For backward compatibility, end new fields above  
         "FULLTEXT idx_title (title), ".  
         "FULLTEXT idx_author (author), FULLTEXT idx_subject (subject), ".  
         "FULLTEXT idx_url (url), FULLTEXT idx_keywords (keywords), ".  
         "FULLTEXT idx_notes (notes), ".  
         "FULLTEXT idx_abstract (abstract), FULLTEXT idx_mime (mime), ".  
         "FULLTEXT idx_owner (owner), ".  
  "FULLTEXT idx_standards (standards))".  
         "TYPE=MyISAM";  
     # It would sure be nice to have some logging mechanism.  
     unless ($dbh->do($make_metadata_table)) {  
  print LOG "\nMySQL Error Create: ".$dbh->errstr."\n";  
  die $dbh->errstr;  
     }  
 }  }
   #
 # ------------------------------------------------------------- get .meta files  # find out which users we need to examine
 opendir(RESOURCES,"$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}");  opendir(RESOURCES,"$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}");
 my @homeusers = grep {  my @homeusers = 
     &ishome("$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}/$_")      grep {
     } grep {!/^\.\.?$/} readdir(RESOURCES);          &ishome("$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}/$_");
       } grep { 
           !/^\.\.?$/;
       } readdir(RESOURCES);
 closedir RESOURCES;  closedir RESOURCES;
   
 #  #
 # Create the statement handlers we need  # Loop through the users
   
 my $insert_sth = $dbh->prepare  
     ("INSERT INTO newmetadata VALUES (".  
      "?,".   # title  
      "?,".   # author  
      "?,".   # subject  
      "?,".   # declutter url  
      "?,".   # version  
      "?,".   # current  
      "?,".   # notes  
      "?,".   # abstract  
      "?,".   # mime  
      "?,".   # language  
      "?,".   # creationdate  
      "?,".   # revisiondate  
      "?,".   # owner  
      "?,".   # copyright  
      "?,".   # dependencies  
      "?,".   # modifyinguser  
      "?,".   # authorspace  
      "?,".   # lowestgradelevel  
      "?,".   # highestgradelevel  
      "?,".   # standards  
      "?,".   # count  
      "?,".   # course  
      "?,".   # course_list  
      "?,".   # goto  
      "?,".   # goto_list  
      "?,".   # comefrom  
      "?,".   # comefrom_list  
      "?,".   # usage  
      "?,".   # usage_list  
      "?,".   # stdno  
      "?,".   # stdno_list  
      "?,".   # avetries  
      "?,".   # avetries_list  
      "?,".   # difficulty  
      "?,".   # difficulty_list  
      "?,".   # clear  
      "?,".   # technical  
      "?,".   # correct  
      "?,".   # helpful  
      "?,".   # depth  
      "?".    # comments  
      ")"  
      );  
   
 foreach my $user (@homeusers) {  foreach my $user (@homeusers) {
     print LOG "\n=== User: ".$user."\n\n";      print LOG "=== User: ".$user."\n";
   
     my $prodir=&propath($perlvar{'lonDefDomain'},$user);      my $prodir=&propath($perlvar{'lonDefDomain'},$user);
     # Use find.pl      #
     undef @metalist;      # Use File::Find to get the files we need to read/modify
     @metalist=();      find(
     &find("$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}/$user");           {preprocess => \&only_meta_files,
     # -- process each file to get metadata and put into search catalog SQL  #          wanted     => \&print_filename,
     # database.  Also, check to see if already there.  #          wanted     => \&log_metadata,
     # I could just delete (without searching first), but this works for now.            wanted     => \&process_meta_file,
     foreach my $m (@metalist) {            }, 
         print LOG "- ".$m."\n";           "$perlvar{'lonDocRoot'}/res/$perlvar{'lonDefDomain'}/$user");
         my $ref=&metadata($m);  
         my $m2='/res/'.&declutter($m);  
         $m2=~s/\.meta$//;  
   if ($ref->{'obsolete'}) { print LOG "obsolete\n"; next; }  
  if ($ref->{'copyright'} eq 'private') { print LOG "private\n"; next; }  
  my %dyn=();  
  if ($m2=~/\/default$/) {  
     $m2=~s/\/default$/\//;  
  } else {  
     %dyn=&dynamicmeta($m2);  
     &count($m2);  
  }  
         unless ($insert_sth->execute(  
      $ref->{'title'},  
                              $ref->{'author'},  
                              $ref->{'subject'},  
                              $m2,  
                              $ref->{'keywords'},  
                              'current',  
                              $ref->{'notes'},  
                              $ref->{'abstract'},  
                              $ref->{'mime'},  
                              $ref->{'language'},  
                              sqltime($ref->{'creationdate'}),  
                              sqltime($ref->{'lastrevisiondate'}),  
                              $ref->{'owner'},  
                              $ref->{'copyright'},  
      $ref->{'dependencies'},  
      $ref->{'modifyinguser'},  
      $ref->{'authorspace'},  
      $ref->{'lowestgradelevel'},  
      $ref->{'highestgradelevel'},  
      $ref->{'standards'},  
      $dyn{'count'},  
      $dyn{'course'},  
      $dyn{'course_list'},  
      $dyn{'goto'},  
      $dyn{'goto_list'},  
      $dyn{'comefrom'},  
      $dyn{'comefrom_list'},  
      $dyn{'usage'},  
      $dyn{'usage_list'},  
      $dyn{'stdno'},  
      $dyn{'stdno_list'},  
      $dyn{'avetries'},  
      $dyn{'avetries_list'},  
      $dyn{'difficulty'},  
      $dyn{'difficulty_list'},       
      $dyn{'clear'},  
      $dyn{'technical'},  
      $dyn{'correct'},  
      $dyn{'helpful'},  
      $dyn{'depth'},  
      $dyn{'comments'}       
      )) {  
     print LOG "\nMySQL Error Insert: ".$dbh->errstr."\n";  
     die $dbh->errstr;  
  }  
         $ref = undef;  
     }  
 }  }
 # --------------------------------------------------- Close database connection  #
 $dbh->do("DROP TABLE IF EXISTS metadata");  # Rename the table
 unless ($dbh->do("RENAME TABLE newmetadata TO metadata")) {  $dbh->do('DROP TABLE IF EXISTS '.$oldname);
     print LOG "\nMySQL Error Rename: ".$dbh->errstr."\n";  if (! $dbh->do('RENAME TABLE '.$newname.' TO '.$oldname)) {
       print LOG "MySQL Error Rename: ".$dbh->errstr."\n";
     die $dbh->errstr;      die $dbh->errstr;
 }  }
 unless ($dbh->disconnect) {  if (! $dbh->disconnect) {
     print LOG "\nMySQL Error Disconnect: ".$dbh->errstr."\n";      print LOG "MySQL Error Disconnect: ".$dbh->errstr."\n";
     die $dbh->errstr;      die $dbh->errstr;
 }  }
 print LOG "\n==== Searchcat completed ".localtime()." ====\n";  ##
   ## Finished!
   print LOG "==== Searchcat completed ".localtime()." ====\n";
 close(LOG);  close(LOG);
 &writesimple();  
 &writecount();  &write_type_count();
   &write_copyright_count();
   
 exit 0;  exit 0;
   
   ########################################################
   ########################################################
   ###                                                  ###
   ###          File::Find support routines             ###
   ###                                                  ###
   ########################################################
   ########################################################
   ##
   ## &only_meta_files
   ##
   ## Called by File::Find.
   ## Takes a list of files/directories in and returns a list of files/directories
   ## to search.
   sub only_meta_files {
       my @PossibleFiles = @_;
       my @ChosenFiles;
       foreach my $file (@PossibleFiles) {
           if ( ($file =~ /\.meta$/ &&            # Ends in meta
                 $file !~ /\.\d+\.[^\.]+\.meta$/  # is not for a prior version
                ) || (-d $file )) { # directories are okay
                    # but we do not want /. or /..
               push(@ChosenFiles,$file);
           }
       }
       return @ChosenFiles;
   }
   
   ##
   ##
   ## Debugging routines, use these for 'wanted' in the File::Find call
   ##
   sub print_filename {
       my ($file) = $_;
       my $fullfilename = $File::Find::name;
       if (-d $file) {
           print LOG " Got directory ".$fullfilename."\n";
       } else {
           print LOG " Got file ".$fullfilename."\n";
       }
       $_=$file;
   }
   
   sub log_metadata {
       my ($file) = $_;
       my $fullfilename = $File::Find::name;
       return if (-d $fullfilename); # No need to do anything here for directories
       print LOG $fullfilename."\n";
       my $ref=&metadata($fullfilename);
       if (! defined($ref)) {
           print LOG "    No data\n";
           return;
       }
       while (my($key,$value) = each(%$ref)) {
           print LOG "    ".$key." => ".$value."\n";
       }
       &count_copyright($ref->{'copyright'});
       $_=$file;
   }
   
 # =============================================================================  
   
 # ---------------------------------------------------------------- Get metadata  ##
 # significantly altered from subroutine present in lonnet  ## process_meta_file
   ##   Called by File::Find. 
   ##   Only input is the filename in $_.  
   sub process_meta_file {
       my ($file) = $_;
       my $filename = $File::Find::name;
       return if (-d $filename); # No need to do anything here for directories
       #
       print LOG $filename."\n";
       #
       my $ref=&metadata($filename);
       #
       # $url is the original file url, not the metadata file
       my $url='/res/'.&declutter($filename);
       $url=~s/\.meta$//;
       print LOG "    ".$url."\n";
       #
       # Ignore some files based on their metadata
       if ($ref->{'obsolete'}) { 
           print LOG "obsolete\n"; 
           return; 
       }
       &count_copyright($ref->{'copyright'});
       if ($ref->{'copyright'} eq 'private') { 
           print LOG "private\n"; 
           return; 
       }
       #
       # Find the dynamic metadata
       my %dyn;
       if ($url=~ m:/default$:) {
           $url=~ s:/default$:/:;
       } else {
           # %dyn=&dynamicmeta($url);
           &count_type($url);
       }
       #
       $ref->{'creationdate'}     = &sqltime($ref->{'creationdate'});
       $ref->{'lastrevisiondate'} = &sqltime($ref->{'lastrevisiondate'});
       my %Data = (
                   %$ref,
                   %dyn,
                   'url'=>$url,
                   'version'=>'current');
       my ($count,$err) = &LONCAPA::lonmetadata::store_metadata($dbh,$newname,
                                                                \%Data);
       if ($err) {
           print LOG "\nMySQL Error Insert: ".$err."\n";
           die $err;
       }
       if ($count < 1) {
           print LOG "Unable to insert record into MySQL database for $url\n";
           die "Unable to insert record into MySQl database for $url";
       } else {
           print LOG "Count = ".$count."\n";
       }
       #
       # Reset $_ before leaving
       $_ = $file;
   }
   
   ########################################################
   ########################################################
   ###                                                  ###
   ###  &metadata($uri)                                 ###
   ###   Retrieve metadata for the given file           ###
   ###                                                  ###
   ########################################################
   ########################################################
 sub metadata {  sub metadata {
     my ($uri,$what)=@_;      my ($uri)=@_;
     my %metacache=();      my %metacache=();
     $uri=&declutter($uri);      $uri=&declutter($uri);
     my $filename=$uri;      my $filename=$uri;
     $uri=~s/\.meta$//;      $uri=~s/\.meta$//;
     $uri='';      $uri='';
     unless ($metacache{$uri.'keys'}) {      if ($filename !~ /\.meta$/) { 
         unless ($filename=~/\.meta$/) { $filename.='.meta'; }          $filename.='.meta';
  my $metastring=&getfile($perlvar{'lonDocRoot'}.'/res/'.$filename);      }
         my $parser=HTML::TokeParser->new(\$metastring);      my $metastring=&getfile($perlvar{'lonDocRoot'}.'/res/'.$filename);
         my $token;      return undef if (! defined($metastring));
         while ($token=$parser->get_token) {      my $parser=HTML::TokeParser->new(\$metastring);
             if ($token->[0] eq 'S') {      my $token;
                 my $entry=$token->[1];      while ($token=$parser->get_token) {
                 my $unikey=$entry;          if ($token->[0] eq 'S') {
                 if (defined($token->[2]->{'part'})) {               my $entry=$token->[1];
                     $unikey.='_'.$token->[2]->{'part'};               my $unikey=$entry;
                 }              if (defined($token->[2]->{'part'})) { 
                 if (defined($token->[2]->{'name'})) {                   $unikey.='_'.$token->[2]->{'part'}; 
                     $unikey.='_'.$token->[2]->{'name'};               }
                 }              if (defined($token->[2]->{'name'})) { 
                 if ($metacache{$uri.'keys'}) {                  $unikey.='_'.$token->[2]->{'name'}; 
                     $metacache{$uri.'keys'}.=','.$unikey;              }
               if ($metacache{$uri.'keys'}) {
                   $metacache{$uri.'keys'}.=','.$unikey;
               } else {
                   $metacache{$uri.'keys'}=$unikey;
               }
               foreach ( @{$token->[3]}) {
                   $metacache{$uri.''.$unikey.'.'.$_}=$token->[2]->{$_};
               } 
               if (! ($metacache{$uri.''.$unikey}=$parser->get_text('/'.$entry))){
                   $metacache{$uri.''.$unikey} = 
                       $metacache{$uri.''.$unikey.'.default'};
               }
           } # End of ($token->[0] eq 'S')
       }
       return \%metacache;
   }
   
   ##
   ## &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;
   }
   
   ########################################################
   ########################################################
   ###                                                  ###
   ###    Dynamic Metadata                              ###
   ###                                                  ###
   ########################################################
   ########################################################
   sub dynamicmeta {
       my $url = &declutter(shift());
       $url =~ s/\.meta$//;
       my %data = ('count'         => 0,
                   'course'        => 0,
                   'course_list'   => '',
                   'avetries'      => 'NULL',
                   'avetries_list' => '',
                   'stdno'         => 0,
                   'stdno_list'    => '',
                   'usage'         => 0,
                   'usage_list'    => '',
                   'goto'          => 0,
                   'goto_list'     => '',
                   'comefrom'      => 0,
                   'comefrom_list' => '',
                   'difficulty'    => 'NULL',
                   'difficulty_list' => '',
                   'sequsage'      => '0',
                   'sequsage_list' => '',
                   'clear'         => 'NULL',
                   'technical'     => 'NULL',
                   'correct'       => 'NULL',
                   'helpful'       => 'NULL',
                   'depth'         => 'NULL',
                   'comments'      => '',                
                   );
       my ($dom,$auth)=($url=~/^(\w+)\/(\w+)\//);
       my $prodir=&propath($dom,$auth);
       #
       # Get metadata except counts
       my %evaldata;
       if (! tie(%evaldata,'GDBM_File',
                 $prodir.'/nohist_resevaldata.db',&GDBM_READER(),0640)) {
           return (undef);
       }
       my %sum=();
       my %count=();
       my %concat=();
       my %listitems=(
                      'course'       => 'add',
                      'goto'         => 'add',
                      'comefrom'     => 'add',
                      'avetries'     => 'average',
                      'stdno'        => 'add',
                      'difficulty'   => 'average',
                      'clear'        => 'average',
                      'technical'    => 'average',
                      'helpful'      => 'average',
                      'correct'      => 'average',
                      'depth'        => 'average',
                      'comments'     => 'append',
                      'usage'        => 'count'
                      );
       #
       my $regexp=$url;
       $regexp=~s/(\W)/\\$1/g;
       $regexp='___'.$regexp.'___([a-z]+)$';
       while (my ($esckey,$value)=each %evaldata) {
           my $key=&unescape($esckey);
           if ($key=~/$regexp/) {
               my ($item,$purl,$cat)=split(/___/,$key);
               $count{$cat}++;
               if ($listitems{$cat} ne 'append') {
                   if (defined($sum{$cat})) {
                       $sum{$cat}+=&unescape($value);
                       $concat{$cat}.=','.$item;
                 } else {                  } else {
                     $metacache{$uri.'keys'}=$unikey;                      $sum{$cat}=&unescape($value);
                       $concat{$cat}=$item;
                 }                  }
                 map {              } else {
                     $metacache{$uri.''.$unikey.'.'.$_}=$token->[2]->{$_};                  if (defined($sum{$cat})) {
                 } @{$token->[3]};                      if ($evaldata{$esckey}=~/\w/) {
                 unless (                          $sum{$cat}.='<hr />'.&unescape($evaldata{$esckey});
                         $metacache{$uri.''.$unikey}=$parser->get_text('/'.$entry)                      }
                         ) { $metacache{$uri.''.$unikey}=                  } else {
                                 $metacache{$uri.''.$unikey.'.default'};                      $sum{$cat}=''.&unescape($evaldata{$esckey});
                         }      }
             }              }
         }          }
     }      }
     return \%metacache;      untie(%evaldata);
       # transfer gathered data to returnhash, calculate averages where applicable
       my %returnhash;
       while (my $cat=each(%count)) {
           if ($count{$cat} eq 'nan') { next; }
           if ($sum{$cat} eq 'nan') { next; }
           if ($listitems{$cat} eq 'average') {
               if ($count{$cat}) {
                   $returnhash{$cat}=int(($sum{$cat}/$count{$cat})*100.0+0.5)/100.0;
               } else {
                   $returnhash{$cat}='NULL';
               }
           } elsif ($listitems{$cat} eq 'count') {
               $returnhash{$cat}=$count{$cat};
           } else {
               $returnhash{$cat}=$sum{$cat};
           }
           $returnhash{$cat.'_list'}=$concat{$cat};
       }
       #
       # get count
       if (tie(my %evaldata,'GDBM_File',
               $prodir.'/nohist_accesscount.db',&GDBM_READER(),0640)) {
    my $escurl=&escape($url);
    if (! exists($evaldata{$escurl})) {
       $returnhash{'count'}=0;
    } else {
       $returnhash{'count'}=$evaldata{$escurl};
    }
    untie %evaldata;
       }
       return %returnhash;
 }  }
   
 # ------------------------------------------------------------ Serves up a file  ########################################################
 # returns either the contents of the file or a -1  ########################################################
 sub getfile {  ###                                                  ###
   ###   Counts                                         ###
   ###                                                  ###
   ########################################################
   ########################################################
   {
   
   my %countext;
   
   sub count_type {
     my $file=shift;      my $file=shift;
     if (! -e $file ) { return -1; };      $file=~/\.(\w+)$/;
     my $fh=IO::File->new($file);      my $ext=lc($1);
     my $a='';      $countext{$ext}++;
     while (<$fh>) { $a .=$_; }  
     return $a;  
 }  }
   
 # ------------------------------------------------------------- Declutters URLs  sub write_type_count {
 sub declutter {      open(RESCOUNT,'>/home/httpd/html/lon-status/rescount.txt');
     my $thisfn=shift;      while (my ($extension,$count) = each(%countext)) {
     $thisfn=~s/^$perlvar{'lonDocRoot'}//;   print RESCOUNT $extension.'='.$count.'&';
     $thisfn=~s/^\///;      }
     $thisfn=~s/^res\///;      print RESCOUNT 'time='.time."\n";
     return $thisfn;      close(RESCOUNT);
 }  }
   
 # --------------------------------------- Is this the home server of an author?  } # end of scope for %countext
 # (copied from lond, modification of the return value)  
   {
   
   my %copyrights;
   
   sub count_copyright {
       $copyrights{@_[0]}++;
   }
   
   sub write_copyright_count {
       open(COPYCOUNT,'>/home/httpd/html/lon-status/copyrightcount.txt');
       while (my ($copyright,$count) = each(%copyrights)) {
    print COPYCOUNT $copyright.'='.$count.'&';
       }
       print COPYCOUNT 'time='.time."\n";
       close(COPYCOUNT);
   }
   
   } # end of scope for %copyrights
   
   ########################################################
   ########################################################
   ###                                                  ###
   ###   Miscellanous Utility Routines                  ###
   ###                                                  ###
   ########################################################
   ########################################################
   ##
   ## &ishome($username)
   ##   Returns 1 if $username is a LON-CAPA author, 0 otherwise
   ##   (copied from lond, modification of the return value)
 sub ishome {  sub ishome {
     my $author=shift;      my $author=shift;
     $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;      $author=~s/\/home\/httpd\/html\/res\/([^\/]*)\/([^\/]*).*/$1\/$2/;
Line 541  sub ishome { Line 553  sub ishome {
     }      }
 }  }
   
 # -------------------------------------------- Return path to profile directory  ##
 # (copied from lond)  ## &propath($udom,$uname)
   ##   Returns the path to the users LON-CAPA directory
   ##   (copied from lond)
 sub propath {  sub propath {
     my ($udom,$uname)=@_;      my ($udom,$uname)=@_;
     $udom=~s/\W//g;      $udom=~s/\W//g;
Line 553  sub propath { Line 567  sub propath {
     return $proname;      return $proname;
 }   } 
   
 # ---------------------------- convert 'time' format into a datetime sql format  ##
   ## &sqltime($timestamp)
   ##
   ## Convert perl $timestamp to MySQL time.  MySQL expects YYYY-MM-DD HH:MM:SS
   ##
 sub sqltime {  sub sqltime {
     my $time=&unsqltime(@_[0]);      my ($time) = @_;
     unless ($time) { return 'NULL'; }      my $mysqltime;
     my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =      if ($time =~ 
  localtime($time);          /(\d+)-(\d+)-(\d+) # YYYY-MM-DD
     $mon++; $year+=1900;          \s                 # a space
     return "$year-$mon-$mday $hour:$min:$sec";          (\d+):(\d+):(\d+)  # HH:MM::SS
           /x ) { 
           # Some of the .meta files have the time in mysql
           # format already, so just make sure they are 0 padded and
           # pass them back.
           $mysqltime = sprintf('%04d-%02d-%02d %02d:%02d:%02d',
                                $1,$2,$3,$4,$5,$6);
       } elsif ($time =~ /^\d+$/) {
           my @TimeData = gmtime($time);
           # Alter the month to be 1-12 instead of 0-11
           $TimeData[4]++;
           # Alter the year to be from 0 instead of from 1900
           $TimeData[5]+=1900;
           $mysqltime = sprintf('%04d-%02d-%02d %02d:%02d:%02d',
                                @TimeData[5,4,3,2,1,0]);
       } else {
           print LOG "    Unable to decode time ".$time."\n";
           $mysqltime = 0;
       }
       return $mysqltime;
 }  }
   
 sub maketime {  ##
     my %th=@_;  ## &declutter($filename)
     return POSIX::mktime(($th{'seconds'},$th{'minutes'},$th{'hours'},  ##   Given a filename, returns a url for the filename.
                           $th{'day'},$th{'month'}-1,  sub declutter {
                           $th{'year'}-1900,0,0,$th{'dlsav'}));      my $thisfn=shift;
       $thisfn=~s/^$perlvar{'lonDocRoot'}//;
       $thisfn=~s/^\///;
       $thisfn=~s/^res\///;
       return $thisfn;
 }  }
   
   ##
 #########################################  ## Escape / Unescape special characters
 #  sub unescape {
 # Retro-fixing of un-backward-compatible time format      my $str=shift;
       $str =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;
 sub unsqltime {      return $str;
     my $timestamp=shift;  
     if ($timestamp=~/^(\d+)\-(\d+)\-(\d+)\s+(\d+)\:(\d+)\:(\d+)$/) {  
         $timestamp=&maketime('year'=>$1,'month'=>$2,'day'=>$3,  
                              'hours'=>$4,'minutes'=>$5,'seconds'=>$6);  
     }  
     return $timestamp;  
 }  }
   
 # ----------------- Code to enable 'find' subroutine listing of the .meta files  sub escape {
       my $str=shift;
 no strict "vars";      $str =~ s/(\W)/"%".unpack('H2',$1)/eg;
       return $str;
 sub wanted {  
     (($dev,$ino,$mode,$nlink,$uid,$gid) = lstat($_)) &&  
          -f _ &&  
          /^.*\.meta$/ && !/^.+\.\d+\.[^\.]+\.meta$/ &&  
          push(@metalist,"$dir/$_");  
 }  }

Removed from v.1.54  
changed lines
  Added in v.1.55


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>