Bug 14321: Integrate Upload.pm into Koha
[koha.git] / C4 / UploadedFiles.pm
index 246b02b..f426b60 100644 (file)
@@ -1,21 +1,21 @@
 package C4::UploadedFiles;
 
-# Copyright 2011-2012 BibLibre
-#
 # This file is part of Koha.
 #
-# Koha is free software; you can redistribute it and/or modify it under the
-# terms of the GNU General Public License as published by the Free Software
-# Foundation; either version 2 of the License, or (at your option) any later
-# version.
+# Copyright (C) 2011-2012 BibLibre
+#
+# Koha is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
 #
-# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
-# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
-# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
+# Koha is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License along
-# with Koha; if not, write to the Free Software Foundation, Inc.,
-# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+# You should have received a copy of the GNU General Public License
+# along with Koha; if not, see <http://www.gnu.org/licenses>.
 
 =head1 NAME
 
@@ -57,12 +57,16 @@ use Fcntl;
 use Encode;
 
 use C4::Context;
+use C4::Koha;
 
 sub _get_file_path {
-    my ($id, $dirname, $filename) = @_;
+    my ($hash, $dirname, $filename) = @_;
 
-    my $uploadPath = C4::Context->preference('uploadPath');
-    my $filepath = "$uploadPath/$dirname/${id}_$filename";
+    my $upload_path = C4::Context->config('upload_path');
+    if( !-d "$upload_path/$dirname" ) {
+        mkdir "$upload_path/$dirname";
+    }
+    my $filepath = "$upload_path/$dirname/${hash}_$filename";
     $filepath =~ s|/+|/|g;
 
     return $filepath;
@@ -81,7 +85,7 @@ Hash keys are:
 
 =item * filename: name of the file
 
-=item * dir: directory where file is stored (relative to syspref 'uploadPath')
+=item * dir: directory where file is stored (relative to config variable 'upload_path')
 
 =back
 
@@ -90,21 +94,21 @@ It returns undef if file is not found
 =cut
 
 sub GetUploadedFile {
-    my ($id) = @_;
+    my ( $hashvalue ) = @_;
 
-    return unless $id;
+    return unless $hashvalue;
 
     my $dbh = C4::Context->dbh;
     my $query = qq{
-        SELECT id, filename, dir
+        SELECT hashvalue, filename, dir
         FROM uploaded_files
-        WHERE id = ?
+        WHERE hashvalue = ?
     };
     my $sth = $dbh->prepare($query);
-    $sth->execute($id);
+    $sth->execute( $hashvalue );
     my $file = $sth->fetchrow_hashref;
     if ($file) {
-        $file->{filepath} = _get_file_path($file->{id}, $file->{dir},
+        $file->{filepath} = _get_file_path($file->{hashvalue}, $file->{dir},
             $file->{filename});
     }
 
@@ -123,7 +127,7 @@ Parameters:
 
 =item * $filename: name of the file
 
-=item * $dir: directory where to store the file (path relative to syspref 'uploadPath'
+=item * $dir: directory where to store the file (path relative to config variable 'upload_path'
 
 =item * $io_handle: valid IO::Handle object, can be retrieved with
 $cgi->upload('uploaded_file')->handle;
@@ -134,7 +138,6 @@ $cgi->upload('uploaded_file')->handle;
 
 sub UploadFile {
     my ($filename, $dir, $handle) = @_;
-
     $filename = decode_utf8($filename);
     if($filename =~ m#(^|/)\.\.(/|$)# or $dir =~ m#(^|/)\.\.(/|$)#) {
         warn "Filename or dirname contains '..'. Aborting upload";
@@ -150,15 +153,17 @@ sub UploadFile {
 
     my $sha = new Digest::SHA;
     $sha->add($data);
-    my $id = $sha->hexdigest;
+    $sha->add($filename);
+    $sha->add($dir);
+    my $hash = $sha->hexdigest;
 
     # Test if this id already exist
-    my $file = GetUploadedFile($id);
+    my $file = GetUploadedFile($hash);
     if ($file) {
-        return $file->{id};
+        return $file->{hashvalue};
     }
 
-    my $file_path = _get_file_path($id, $dir, $filename);
+    my $file_path = _get_file_path($hash, $dir, $filename);
 
     my $out_fh;
     # Create the file only if it doesn't exist
@@ -168,59 +173,151 @@ sub UploadFile {
     }
 
     print $out_fh $data;
+    my $size= tell($out_fh);
     close $out_fh;
 
     my $dbh = C4::Context->dbh;
     my $query = qq{
-        INSERT INTO uploaded_files (id, filename, dir)
-        VALUES (?,?, ?);
+        INSERT INTO uploaded_files (hashvalue, filename, filesize, dir, categorycode, owner) VALUES (?,?,?,?,?,?);
     };
     my $sth = $dbh->prepare($query);
-    if($sth->execute($id, $filename, $dir)) {
-        return $id;
+    my $uid= C4::Context->userenv? C4::Context->userenv->{number}: undef;
+        # uid is null in unit test
+    if($sth->execute($hash, $filename, $size, $dir, $dir, $uid)) {
+        return $hash;
     }
 
-    return undef;
+    return;
+}
+
+=head2 DanglingEntry
+
+    C4::UploadedFiles::DanglingEntry($id,$isfileuploadurl);
+
+Determine if a entry is dangling.
+
+Returns: 2 == no db entry
+         1 == no plain file
+         0 == both a file and db entry.
+        -1 == N/A (undef id / non-file-upload URL)
+
+=cut
+
+sub DanglingEntry {
+    my ($id,$isfileuploadurl) = @_;
+    my $retval;
+
+    if (defined($id)) {
+        my $file = GetUploadedFile($id);
+        if($file) {
+            my $file_path = $file->{filepath};
+            my $file_deleted = 0;
+            unless( -f $file_path ) {
+                $retval = 1;
+            } else {
+                $retval = 0;
+            }
+        }
+        else {
+            if ( $isfileuploadurl ) {
+                $retval = 2;
+            }
+            else {
+                $retval = -1;
+            }
+        }
+    }
+    else {
+        $retval = -1;
+    }
+    return $retval;
 }
 
 =head2 DelUploadedFile
 
-    C4::UploadedFiles::DelUploadedFile($id);
+    C4::UploadedFiles::DelUploadedFile( $hash );
 
-Remove a previously uploaded file, given its id.
+Remove a previously uploaded file, given its hash value.
 
-Returns a false value if an error occurs.
+Returns: 1 == file deleted
+         0 == file not deleted
+         -1== no file to delete / no meaninful id passed
 
 =cut
 
 sub DelUploadedFile {
-    my ($id) = @_;
-
-    my $file = GetUploadedFile($id);
-    if($file) {
-        my $file_path = $file->{filepath};
-        my $file_deleted = 0;
-        unless( -f $file_path ) {
-            warn "Id $file->{id} is in database but not in filesystem, removing id from database";
-            $file_deleted = 1;
-        } else {
-            if(unlink $file_path) {
+    my ( $hashval ) = @_;
+    my $retval;
+
+    if ( $hashval ) {
+        my $file = GetUploadedFile( $hashval );
+        if($file) {
+            my $file_path = $file->{filepath};
+            my $file_deleted = 0;
+            unless( -f $file_path ) {
+                warn "Id $file->{hashvalue} is in database but no plain file found, removing id from database";
                 $file_deleted = 1;
+            } else {
+                if(unlink $file_path) {
+                    $file_deleted = 1;
+                }
             }
-        }
 
-        unless($file_deleted) {
-            warn "File $file_path cannot be deleted: $!";
-        }
+            unless($file_deleted) {
+                warn "File $file_path cannot be deleted: $!";
+            }
 
-        my $dbh = C4::Context->dbh;
-        my $query = qq{
-            DELETE FROM uploaded_files
-            WHERE id = ?
-        };
-        my $sth = $dbh->prepare($query);
-        return $sth->execute($id);
+            my $dbh = C4::Context->dbh;
+            my $query = qq{
+                DELETE FROM uploaded_files
+                WHERE hashvalue = ?
+            };
+            my $sth = $dbh->prepare($query);
+            my $numrows = $sth->execute( $hashval );
+            # if either a DB entry or file was deleted,
+            # then clearly we have a deletion.
+            if ($numrows>0 || $file_deleted==1) {
+                $retval = 1;
+            }
+            else {
+                $retval = 0;
+            }
+        }
+        else {
+            warn "There was no file for hash $hashval.";
+            $retval = -1;
+        }
+    }
+    else {
+        warn "DelUploadFile called without hash value.";
+        $retval = -1;
     }
+    return $retval;
+}
+
+=head2 getCategories
+
+    getCategories returns a list of upload category codes and names
+
+=cut
+
+sub getCategories {
+    my $cats = C4::Koha::GetAuthorisedValues('UPLOAD');
+    [ map {{ code => $_->{authorised_value}, name => $_->{lib} }} @$cats ];
+}
+
+=head2 httpheaders
+
+    httpheaders returns http headers for a retrievable upload
+    Will be extended by report 14282
+
+=cut
+
+sub httpheaders {
+    my $file= shift;
+    return
+        ( '-type' => 'application/octet-stream',
+          '-attachment' => $file, );
 }
 
 1;