1 package SL::File::Backend::Webdav;
 
   5 use parent qw(SL::File::Backend);
 
   8 use SL::System::Process;
 
  12 use File::Path qw(make_path);
 
  13 use File::MimeInfo::Magic;
 
  21   my ($self, %params) = @_;
 
  22   $main::lxdebug->message(LXDebug->DEBUG2(), "del in backend " . $self . "  file " . $params{dbfile});
 
  23   $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $params{dbfile}->id * 1);
 
  24   return 0 unless $params{dbfile};
 
  25   my ($file_path, undef, undef) = $self->webdav_path($params{dbfile});
 
  31   my ($self, %params) = @_;
 
  32   return 0 unless $params{dbfile};
 
  33   my (undef, $oldwebdavname) = split(/:/, $params{dbfile}->location, 2);
 
  34   my ($tofile, $basepath, $basename) = $self->webdav_path($params{dbfile});
 
  35   my $fromfile = File::Spec->catfile($basepath, $oldwebdavname);
 
  36   $main::lxdebug->message(LXDebug->DEBUG2(), "renamefrom=" . $fromfile . " to=" . $tofile);
 
  37   move($fromfile, $tofile);
 
  41   my ($self, %params) = @_;
 
  42   die 'dbfile not exists' unless $params{dbfile};
 
  43   $main::lxdebug->message(LXDebug->DEBUG2(), "in backend " . $self . "  file " . $params{dbfile});
 
  44   $main::lxdebug->message(LXDebug->DEBUG2(), "file id=" . $params{dbfile}->id);
 
  45   my $dbfile = $params{dbfile};
 
  46   die 'no file contents' unless $params{file_path} || $params{file_contents};
 
  48   if ($params{dbfile}->id * 1 == 0) {
 
  50     # new element: need id for file
 
  51     $params{dbfile}->save;
 
  53   my ($tofile, undef, $basename) = $self->webdav_path($params{dbfile});
 
  54   if ($params{file_path} && -f $params{file_path}) {
 
  55     copy($params{file_path}, $tofile);
 
  57   elsif ($params{file_contents}) {
 
  58     open(OUT, "> " . $tofile);
 
  59     print OUT $params{file_contents};
 
  65 sub get_version_count {
 
  66   my ($self, %params) = @_;
 
  67   die "no dbfile" unless $params{dbfile};
 
  73   my ($self, %params) = @_;
 
  74   die "no dbfile" unless $params{dbfile};
 
  75   $main::lxdebug->message(LXDebug->DEBUG2(), "version=" .$params{version});
 
  76   my ($path, undef, undef) = $self->webdav_path($params{dbfile});
 
  77   die "No file found in Backend: " . $path unless -f $path;
 
  78   my $dt = DateTime->from_epoch(epoch => stat($path)->mtime, time_zone => $::locale->get_local_time_zone()->name)->clone();
 
  79   $main::lxdebug->message(LXDebug->DEBUG2(), "dt=" .$dt);
 
  84   my ($self, %params) = @_;
 
  85   die "no dbfile" unless $params{dbfile};
 
  86   my ($path, undef, undef) = $self->webdav_path($params{dbfile});
 
  87   die "No file found in Backend: " . $path unless -f $path;
 
  92   my ($self, %params) = @_;
 
  93   my $path = $self->get_filepath(%params);
 
  94   return "" unless $path;
 
  95   my $contents = File::Slurp::read_file($path);
 
  99 sub sync_from_backend {
 
 100   my ($self, %params) = @_;
 
 101   return unless $params{file_type};
 
 103   $self->sync_all_locations(%params);
 
 108   return $::instance_conf->get_doc_webdav;
 
 116   sales_quotation             => 'angebote',
 
 117   sales_order                 => 'bestellungen',
 
 118   request_quotation           => 'anfragen',
 
 119   purchase_order              => 'lieferantenbestellungen',
 
 120   sales_delivery_order        => 'verkaufslieferscheine',
 
 121   purchase_delivery_order     => 'einkaufslieferscheine',
 
 122   credit_note                 => 'gutschriften',
 
 123   invoice                     => 'rechnungen',
 
 124   invoice_for_advance_payment => 'rechnungen',
 
 125   final_invoice               => 'rechnungen',
 
 126   purchase_invoice            => 'einkaufsrechnungen',
 
 128   service                     => 'dienstleistungen',
 
 129   assembly                    => 'erzeugnisse',
 
 131   general_ledger              => 'dialogbuchungen',
 
 132   gl_transaction              => 'dialogbuchungen',
 
 133   accounts_payable            => 'kreditorenbuchungen',
 
 134   shop_image                  => 'shopbilder',
 
 135   customer                    => 'kunden',
 
 136   vendor                      => 'lieferanten',
 
 139 my %type_to_model = (
 
 140   sales_quotation             => 'Order',
 
 141   sales_order                 => 'Order',
 
 142   request_quotation           => 'Order',
 
 143   purchase_order              => 'Order',
 
 144   sales_delivery_order        => 'DeliveryOrder',
 
 145   purchase_delivery_order     => 'DeliveryOrder',
 
 146   credit_note                 => 'Invoice',
 
 147   invoice                     => 'Invoice',
 
 148   invoice_for_advance_payment => 'Invoice',
 
 149   final_invoice               => 'Invoice',
 
 150   purchase_invoice            => 'PurchaseInvoice',
 
 155   general_ledger              => 'GLTransaction',
 
 156   gl_transaction              => 'GLTransaction',
 
 157   accounts_payable            => 'GLTransaction',
 
 158   shop_image                  => 'Part',
 
 159   customer                    => 'Customer',
 
 163 my %model_to_number = (
 
 164   Order           => 'ordnumber',
 
 165   DeliveryOrder   => 'ordnumber',
 
 166   Invoice         => 'invnumber',
 
 167   PurchaseInvoice => 'invnumber',
 
 168   Part            => 'partnumber',
 
 169   Letter          => 'letternumber',
 
 170   GLTransaction   => 'reference',
 
 171   ShopImage       => 'partnumber',
 
 172   Customer        => 'customernumber',
 
 173   Vendor          => 'vendornumber',
 
 177   my ($self, $dbfile) = @_;
 
 179   #die "No webdav backend enabled" unless $::instance_conf->get_webdav;
 
 181   my $type = $type_to_path{ $dbfile->object_type };
 
 183   die "Unknown type" unless $type;
 
 185   my $number = $dbfile->backend_data;
 
 187     $number = $self->_get_number_from_model($dbfile);
 
 188     $dbfile->backend_data($number);
 
 191   $main::lxdebug->message(LXDebug->DEBUG2(), "file_name=" . $dbfile->file_name ." number=".$number);
 
 193   my @fileparts = split(/_/, $dbfile->file_name);
 
 194   my $number_ext = pop @fileparts;
 
 195   my ($maynumber, $ext) = split(/\./, $number_ext, 2);
 
 196   push @fileparts, $maynumber if $maynumber ne $number;
 
 198   my $basename = join('_', @fileparts);
 
 200   my $path = File::Spec->catdir($self->get_rootdir, "webdav", $::auth->client->{id}, $type, $number);
 
 202     File::Path::make_path($path, { chmod => 0770 });
 
 204   my $fname = $basename . '_' . $number . '_' . $dbfile->itime->strftime('%Y%m%d_%H%M%S');
 
 205   $fname .= '.' . $ext if $ext;
 
 207   $main::lxdebug->message(LXDebug->DEBUG2(), "webdav path=" . $path . " filename=" . $fname);
 
 209   return (File::Spec->catfile($path, $fname), $path, $fname);
 
 212 sub get_rootdir { SL::System::Process::exe_dir() }
 
 214 sub _get_number_from_model {
 
 215   my ($self, $dbfile) = @_;
 
 217   my $class = 'SL::DB::' . $type_to_model{ $dbfile->object_type };
 
 218   eval "require $class";
 
 219   my $obj = $class->new(id => $dbfile->object_id)->load;
 
 220   die 'no object found' unless $obj;
 
 221   my $numberattr = $model_to_number{ $type_to_model{ $dbfile->object_type } };
 
 222   return $obj->$numberattr;
 
 226 # TODO not fully imlemented and tested
 
 228 sub sync_all_locations {
 
 229   my ($self, %params) = @_;
 
 231   my %dateparms = (dateformat => 'yyyymmdd');
 
 233   foreach my $type (keys %type_to_path) {
 
 236       file_type => $params{file_type},
 
 239     my @oldfiles = @{ SL::DB::Manager::File->get_all(
 
 241           file_type => $params{file_type},
 
 247     my $path = File::Spec->catdir($self->get_rootdir, "webdav", $::auth->client->{id},$type_to_path{$type});
 
 249     if (opendir my $dir, $path) {
 
 250       foreach my $file (sort { lc $a cmp lc $b }
 
 251         map { decode("UTF-8", $_) } readdir $dir)
 
 253         next if (($file eq '.') || ($file eq '..'));
 
 258         my ($filename, $number, $date, $time_ext) = split(/_/, $fname);
 
 259         my ($time, $ext) = split(/\./, $time_ext, 2);
 
 261         $time = substr($time, 0, 2) . ':' . substr($time, 2, 2) . ':' . substr($time, 4, 2);
 
 263         #my @found = grep { $_->backend_data eq $fname } @oldfiles;
 
 264         #if (scalar(@found) > 0) {
 
 265         #  @oldfiles = grep { $_ != @found[0] } @oldfiles;
 
 268           my $dbfile = SL::DB::File->new();
 
 269           my $class  = 'SL::DB::Manager::' . $type_to_model{$type};
 
 272             $model_to_number{ $type_to_model{$type} } => $number);
 
 275             my $mime_type = File::MimeInfo::Magic::magic(File::Spec->catfile($path, $fname));
 
 277               # if filename has the suffix "pdf", but is really no pdf set mimetype for no suffix
 
 278               $mime_type = File::MimeInfo::Magic::mimetype($fname);
 
 279               $mime_type = 'application/octet-stream' if $mime_type eq 'application/pdf' || !$mime_type;
 
 282             $dbfile->assign_attributes(
 
 283               object_id   => $obj->id,
 
 284               object_type => $type,
 
 285               source      => $params{file_type} eq 'document' ? 'created' : 'uploaded',
 
 286               file_type   => $params{file_type},
 
 287               file_name   => $filename . '_' . $number . '_' . $ext,
 
 288               mime_type   => $mime_type,
 
 289               itime       => $::locale->parse_date_to_object($date . ' ' . $time, %dateparms),
 
 311 SL::File::Backend::Filesystem  - Filesystem class for file storage backend
 
 315 See the synopsis of L<SL::File::Backend>.
 
 319 This specific storage backend use a Filesystem which is only accessed by this interface.
 
 320 This is the big difference to the Webdav backend where the files can be accessed without the control of that backend.
 
 321 This backend use the database id of the SL::DB::File object as filename. The filesystem has up to 1000 subdirectories
 
 322 to store the files not to flat in the filesystem.
 
 327 See methods of L<SL::File::Backend>.
 
 335 The synchronization must be tested and a periodical task is needed to synchronize in some time periods.
 
 339 Martin Helmling E<lt>martin.helmling@opendynamic.deE<gt>