mini-DMS: Filesystem-Backend: undef-Warnung vermeiden
[kivitendo-erp.git] / SL / File / Backend / Filesystem.pm
index a706c38..758142b 100644 (file)
@@ -6,6 +6,7 @@ use parent qw(SL::File::Backend);
 use SL::DB::File;
 use File::Copy;
 use File::Slurp;
+use File::stat;
 use File::Path qw(make_path);
 
 #
@@ -14,38 +15,48 @@ use File::Path qw(make_path);
 
 sub delete {
   my ($self, %params) = @_;
-  $main::lxdebug->message(LXDebug->DEBUG2(), "del in backend " . $self . "  file " . $params{dbfile});
-  $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . ($params{dbfile}->id * 1));
-  die "no dbfile" unless $params{dbfile};
-  my $backend_data = $params{dbfile}->backend_data;
-  $backend_data    = 0                               if $params{last};
-  $backend_data    = $params{dbfile}->backend_data-1 if $params{all_but_notlast};
-
-  if ($backend_data > 0 ) {
-    $main::lxdebug->message(LXDebug->DEBUG2(), "backend_data=" .$backend_data);
-    for my $version ( 1..$backend_data) {
+  die "no dbfile in backend delete" unless $params{dbfile};
+  my $last_version  = $params{dbfile}->backend_data;
+  my $first_version = 1;
+  $last_version     = 0                               if $params{last};
+  $last_version     = $params{dbfile}->backend_data-1 if $params{all_but_notlast};
+  $last_version     = $params{version}                if $params{version};
+  $first_version    = $params{version}                if $params{version};
+
+  if ($last_version > 0 ) {
+    for my $version ( $first_version..$last_version) {
       my $file_path = $self->_filesystem_path($params{dbfile},$version);
-      $main::lxdebug->message(LXDebug->DEBUG2(), "unlink " .$file_path);
       unlink($file_path);
     }
-    if ($params{all_but_notlast}) {
+    if ($params{version}) {
+      for my $version ( $last_version+1 .. $params{dbfile}->backend_data) {
+        my $from = $self->_filesystem_path($params{dbfile},$version);
+        my $to   = $self->_filesystem_path($params{dbfile},$version - 1);
+        die "file not exists in backend delete" unless -f $from;
+        rename($from,$to);
+      }
+      $params{dbfile}->backend_data($params{dbfile}->backend_data-1);
+    }
+    elsif ($params{all_but_notlast}) {
       my $from = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
-      my $to   = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
-      die "file not exists" unless -f $from;
+      my $to   = $self->_filesystem_path($params{dbfile},1);
+      die "file not exists in backend delete" unless -f $from;
       rename($from,$to);
       $params{dbfile}->backend_data(1);
     } else {
       $params{dbfile}->backend_data(0);
+    }
+    unless ($params{dbfile}->backend_data) {
       my $dir_path = $self->_filesystem_path($params{dbfile});
       rmdir($dir_path);
-      $main::lxdebug->message(LXDebug->DEBUG2(), "unlink " .$dir_path);
     }
   } else {
     my $file_path = $self->_filesystem_path($params{dbfile},$params{dbfile}->backend_data);
-    die "file not exists" unless -f $file_path;
+    die "file not exists in backend delete" unless -f $file_path;
     unlink($file_path);
     $params{dbfile}->backend_data($params{dbfile}->backend_data-1);
   }
+  return 1;
 }
 
 sub rename {
@@ -54,16 +65,22 @@ sub rename {
 sub save {
   my ($self, %params) = @_;
   die 'dbfile not exists' unless $params{dbfile};
-  $main::lxdebug->message(LXDebug->DEBUG2(), "in backend " . $self . "  file " . $params{dbfile});
-  $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $params{dbfile}->id . " path=" . $params{file_path});
   my $dbfile = $params{dbfile};
   die 'no file contents' unless $params{file_path} || $params{file_contents};
+
+  # Do not save and do not create a new version of the document if file size of last version is the same.
+  if ($dbfile->source eq 'created' && $self->get_version_count(dbfile => $dbfile)) {
+    my $new_file_size  = $params{file_path} ? stat($params{file_path})->size : length($params{file_contents});
+    my $last_file_size = stat($self->_filesystem_path($dbfile))->size;
+
+    return 1 if $last_file_size == $new_file_size;
+  }
+
   $dbfile->backend_data(0) unless $dbfile->backend_data;
   $dbfile->backend_data($dbfile->backend_data*1+1);
   $dbfile->save->load;
 
   my $tofile = $self->_filesystem_path($dbfile);
-  $main::lxdebug->message(LXDebug->DEBUG2(), "topath=" . $tofile . " from=" . $params{file_path});
   if ($params{file_path} && -f $params{file_path}) {
     File::Copy::copy($params{file_path}, $tofile);
   }
@@ -72,26 +89,28 @@ sub save {
     print OUT $params{file_contents};
     close(OUT);
   }
+  if ($params{mtime}) {
+    utime($params{mtime}, $params{mtime}, $tofile);
+  }
   return 1;
 }
 
 sub get_version_count {
   my ($self, %params) = @_;
   die "no dbfile" unless $params{dbfile};
-  return $params{dbfile}->backend_data * 1;
+  return $params{dbfile}->backend_data//0 * 1;
 }
 
 sub get_mtime {
   my ($self, %params) = @_;
   die "no dbfile" unless $params{dbfile};
-  $main::lxdebug->message(LXDebug->DEBUG2(), "version=" .$params{version});
-  die "unknown version" if $params{version} && 
-                          ($params{version} < 0 || $params{version} > $params{dbfile}->backend_data) ;
-  my $path = $self->_filesystem_path($params{dbfile},$params{version});
-  die "no file found in backend" if !-f $path;
-  my @st = stat($path);
-  my $dt = DateTime->from_epoch(epoch => $st[9])->clone();
-  $main::lxdebug->message(LXDebug->DEBUG2(), "dt=" .$dt);
+  die "unknown version" if $params{version} &&
+                          ($params{version} < 0 || $params{version} > $params{dbfile}->backend_data);
+  my $path = $self->_filesystem_path($params{dbfile}, $params{version});
+
+  die "No file found at $path. Expected: $params{dbfile}{file_name}, file.id: $params{dbfile}{id}" if !-f $path;
+
+  my $dt = DateTime->from_epoch(epoch => stat($path)->mtime, time_zone => $::locale->get_local_time_zone()->name, locale => $::lx_office_conf{system}->{language})->clone();
   return $dt;
 }
 
@@ -99,7 +118,9 @@ sub get_filepath {
   my ($self, %params) = @_;
   die "no dbfile" unless $params{dbfile};
   my $path = $self->_filesystem_path($params{dbfile},$params{version});
-  die "no file" if !-f $path;
+
+  die "No file found at $path. Expected: $params{dbfile}{file_name}, file.id: $params{dbfile}{id}" if !-f $path;
+
   return $path;
 }
 
@@ -112,12 +133,40 @@ sub get_content {
 }
 
 sub enabled {
-  return 0 unless $::instance_conf->get_doc_files || $::instance_conf->get_doc_files_rootpath;
-  $main::lxdebug->message(LXDebug->DEBUG2(), "root path=" . $::instance_conf->get_doc_files_rootpath . " isdir=" .( -d $::instance_conf->get_doc_files_rootpath?"YES":"NO"));
-  return 0 unless -d $::instance_conf->get_doc_files_rootpath;
+  return 0 unless $::instance_conf->get_doc_files;
+  return 0 unless $::lx_office_conf{paths}->{document_path};
+  return 0 unless -d $::lx_office_conf{paths}->{document_path};
   return 1;
 }
 
+sub sync_from_backend {
+  my ($self, %params) = @_;
+  my @query = (file_type => $params{file_type});
+  push @query, (file_name => $params{file_name}) if $params{file_name};
+  push @query, (mime_type => $params{mime_type}) if $params{mime_type};
+  push @query, (source    => $params{source})    if $params{source};
+
+  my $sortby = $params{sort_by} || 'itime DESC,file_name ASC';
+
+  my @files = @{ SL::DB::Manager::File->get_all(query => [@query], sort_by => $sortby) };
+  for (@files) {
+    $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $_->id." version=".$_->backend_data);
+    my $newversion = $_->backend_data;
+    for my $version ( reverse 1 .. $_->backend_data ) {
+      my $path = $self->_filesystem_path($_, $version);
+      $main::lxdebug->message(LXDebug->DEBUG2(), "path=".$path." exists=".( -f $path?1:0));
+      last if -f $path;
+      $newversion = $version - 1;
+    }
+    $main::lxdebug->message(LXDebug->DEBUG2(), "newversion=".$newversion." version=".$_->backend_data);
+    if ( $newversion < $_->backend_data ) {
+      $_->backend_data($newversion);
+      $_->save   if $newversion >  0;
+      $_->delete if $newversion <= 0;
+    }
+  }
+
+}
 
 #
 # internals
@@ -126,13 +175,12 @@ sub enabled {
 sub _filesystem_path {
   my ($self, $dbfile, $version) = @_;
 
-  die "No files backend enabled" unless $::instance_conf->get_doc_files || $::instance_conf->get_doc_files_rootpath;
+  die "No files backend enabled" unless $::instance_conf->get_doc_files || $::lx_office_conf{paths}->{document_path};
 
   # use filesystem with depth 3
   $version    = $dbfile->backend_data if !$version || $version < 1 || $version > $dbfile->backend_data;
   my $iddir   = sprintf("%04d", $dbfile->id % 1000);
-  my $path    = File::Spec->catdir($::instance_conf->get_doc_files_rootpath, $iddir, $dbfile->id);
-  $main::lxdebug->message(LXDebug->DEBUG2(), "file path=" .$path." id=" .$dbfile->id." version=".$version." basename=".$dbfile->id . '_' . $version);
+  my $path    = File::Spec->catdir($::lx_office_conf{paths}->{document_path}, $::auth->client->{id}, $iddir, $dbfile->id);
   if (!-d $path) {
     File::Path::make_path($path, { chmod => 0770 });
   }
@@ -181,5 +229,3 @@ L<SL::File::Backend>
 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>
 
 =cut
-
-