From: Martin Helmling martin.helmling@octosoft.eu Date: Wed, 25 Jan 2017 16:54:14 +0000 (+0100) Subject: Dateimanagement: Webdav Backend (NICHT FERTIG !!!) X-Git-Tag: release-3.5.4~1583 X-Git-Url: http://wagnertech.de/git?a=commitdiff_plain;h=0e9f27e4397f0d7f22b61873d1cb2846854effed;p=kivitendo-erp.git Dateimanagement: Webdav Backend (NICHT FERTIG !!!) Dieses Backend bedarf noch Entwicklung Die Synchronisierung ist noch nicht fertig implementiert und getestet --- diff --git a/SL/File/Backend/Webdav.pm b/SL/File/Backend/Webdav.pm new file mode 100644 index 000000000..1a2209f41 --- /dev/null +++ b/SL/File/Backend/Webdav.pm @@ -0,0 +1,339 @@ +package SL::File::Backend::Webdav; + +use strict; + +use parent qw(SL::File::Backend); +use SL::DB::File; + +#use SL::Webdav; +use File::Copy; +use File::Slurp; +use File::Basename; +use File::Path qw(make_path); +use File::MimeInfo::Magic; + +# +# public methods +# + +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); + return 0 unless $params{dbfile}; + my ($file_path, undef, undef) = $self->webdav_path($params{dbfile}); + unlink($file_path); + return 1; +} + +sub rename { + my ($self, %params) = @_; + return 0 unless $params{dbfile}; + my (undef, $oldwebdavname) = split(/:/, $params{dbfile}->location, 2); + my ($tofile, $basepath, $basename) = $self->webdav_path($params{dbfile}); + my $fromfile = File::Spec->catfile($basepath, $oldwebdavname); + $main::lxdebug->message(LXDebug->DEBUG2(), "renamefrom=" . $fromfile . " to=" . $tofile); + move($fromfile, $tofile); +} + +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); + my $dbfile = $params{dbfile}; + die 'no file contents' unless $params{file_path} || $params{file_contents}; + + if ($params{dbfile}->id * 1 == 0) { + + # new element: need id for file + $params{dbfile}->save; + } + my ($tofile, undef, $basename) = $self->webdav_path($params{dbfile}); + if ($params{file_path} && -f $params{file_path}) { + copy($params{file_path}, $tofile); + } + elsif ($params{file_contents}) { + open(OUT, "> " . $tofile); + print OUT $params{file_contents}; + close(OUT); + } + return 1; +} + +sub get_version_count { + my ($self, %params) = @_; + die "no dbfile" unless $params{dbfile}; + ## TODO + return 1; +} + +sub get_mtime { + my ($self, %params) = @_; + die "no dbfile" unless $params{dbfile}; + $main::lxdebug->message(LXDebug->DEBUG2(), "version=" .$params{version}); + my ($path, undef, undef) = $self->webdav_path($params{dbfile}); + 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); + return $dt; +} + +sub get_filepath { + my ($self, %params) = @_; + die "no dbfile" unless $params{dbfile}; + my ($path, undef, undef) = $self->webdav_path($params{dbfile}); + die "no file" if !-f $path; + return $path; +} + +sub get_content { + my ($self, %params) = @_; + my $path = $self->get_filepath(%params); + return "" unless $path; + my $contents = File::Slurp::read_file($path); + return \$contents; +} + +sub sync_from_backend { + my ($self, %params) = @_; + return unless $params{file_type}; + + $self->sync_all_locations(%params); + +} + +sub enabled { + return 0 unless $::instance_conf->get_doc_webdav; + return 1; +} + +# +# internals +# + +my %type_to_path = ( + sales_quotation => 'angebote', + sales_order => 'bestellungen', + request_quotation => 'anfragen', + purchase_order => 'lieferantenbestellungen', + sales_delivery_order => 'verkaufslieferscheine', + purchase_delivery_order => 'einkaufslieferscheine', + credit_note => 'gutschriften', + invoice => 'rechnungen', + purchase_invoice => 'einkaufsrechnungen', + part => 'waren', + service => 'dienstleistungen', + assembly => 'erzeugnisse', + letter => 'briefe', + general_ledger => 'dialogbuchungen', + accounts_payable => 'kreditorenbuchungen', +); + +my %type_to_model = ( + sales_quotation => 'Order', + sales_order => 'Order', + request_quotation => 'Order', + purchase_order => 'Order', + sales_delivery_order => 'DeliveryOrder', + purchase_delivery_order => 'DeliveryOrder', + credit_note => 'Invoice', + invoice => 'Invoice', + purchase_invoice => 'PurchaseInvoice', + part => 'Part', + service => 'Part', + assembly => 'Part', + letter => 'Letter', + general_ledger => 'GLTransaction', + accounts_payable => 'GLTransaction', +); + +my %model_to_number = ( + Order => 'ordnumber', + DeliveryOrder => 'ordnumber', + Invoice => 'invnumber', + PurchaseInvoice => 'invnumber', + Part => 'partnumber', + Letter => 'letternumber', + GLTransaction => 'reference' +); + +sub webdav_path { + my ($self, $dbfile) = @_; + + #die "No webdav backend enabled" unless $::instance_conf->get_webdav; + + my $type = $type_to_path{ $dbfile->object_type }; + + die "Unknown type" unless $type; + + my $number = $dbfile->backend_data; + if ($number eq '') { + $number = $self->_get_number_from_model($dbfile); + $dbfile->backend_data($number); + $dbfile->save; + } + $main::lxdebug->message(LXDebug->DEBUG2(), "file_name=" . $dbfile->file_name ." number=".$number); + + my @fileparts = split(/_/, $dbfile->file_name); + my $number_ext = pop @fileparts; + my ($maynumber, $ext) = split(/\./, $number_ext, 2); + push @fileparts, $maynumber if $maynumber ne $number; + + my $basename = join('_', @fileparts); + + my $path = File::Spec->catdir($self->get_rootdir, "webdav", $::auth->client->{id}, $type, $number); + if (!-d $path) { + File::Path::make_path($path, { chmod => 0770 }); + } + my $fname = $basename . '_' . $number . '_' . $dbfile->itime->strftime('%Y%m%d_%H%M%S'); + $fname .= '.' . $ext if $ext; + + $main::lxdebug->message(LXDebug->DEBUG2(), "webdav path=" . $path . " filename=" . $fname); + + return (File::Spec->catfile($path, $fname), $path, $fname); +} + +sub get_rootdir { + my ($self) = @_; + + #TODO immer noch das alte Problem: + #je nachdem von woher der Aufruf kommt ist man in ./users oder . + my $rootdir = POSIX::getcwd(); + my $basename = basename($rootdir); + my $dirname = dirname($rootdir); + $rootdir = $dirname if $basename eq 'users'; + return $rootdir; +} + +sub _get_number_from_model { + my ($self, $dbfile) = @_; + + my $class = 'SL::DB::' . $type_to_model{ $dbfile->object_type }; + eval "require $class"; + my $obj = $class->new(id => $dbfile->object_id)->load; + die 'no object found' unless $obj; + my $numberattr = $model_to_number{ $type_to_model{ $dbfile->object_type } }; + return $obj->$numberattr; +} + +# +# TODO not fully imlemented and tested +# +sub sync_all_locations { + my ($self, %params) = @_; + + my %dateparms = (dateformat => 'yyyymmdd'); + + foreach my $type (keys %type_to_path) { + + my @query = ( + file_type => $params{file_type}, + object_type => $type + ); + my @oldfiles = @{ SL::DB::Manager::File->get_all( + query => [ + file_type => $params{file_type}, + object_type => $type + ] + ) + }; + + my $path = File::Spec->catdir($self->get_rootdir, "webdav", $::auth->client->{id},$type_to_path{$type}); + + if (opendir my $dir, $path) { + foreach my $file (sort { lc $a cmp lc $b } + map { decode("UTF-8", $_) } readdir $dir) + { + next if (($file eq '.') || ($file eq '..')); + + my $fname = $file; + $fname =~ s|.*/||; + + my ($filename, $number, $date, $time_ext) = split(/_/, $fname); + my ($time, $ext) = split(/\./, $time_ext, 2); + + $time = substr($time, 0, 2) . ':' . substr($time, 2, 2) . ':' . substr($time, 4, 2); + + #my @found = grep { $_->backend_data eq $fname } @oldfiles; + #if (scalar(@found) > 0) { + # @oldfiles = grep { $_ != @found[0] } @oldfiles; + #} + #else { + my $dbfile = SL::DB::File->new(); + my $class = 'SL::DB::Manager::' . $type_to_model{$type}; + my $obj = + $class->find_by( + $model_to_number{ $type_to_model{$type} } => $number); + if ($obj) { + + my $mime_type = File::MimeInfo::Magic::magic(File::Spec->catfile($path, $fname)); + if (!$mime_type) { + # if filename has the suffix "pdf", but is really no pdf set mimetype for no suffix + $mime_type = File::MimeInfo::Magic::mimetype($fname); + $mime_type = 'application/octet-stream' if $mime_type eq 'application/pdf' || !$mime_type; + } + + $dbfile->assign_attributes( + object_id => $obj->id, + object_type => $type, + source => $params{file_type} eq 'document' ? 'created' : 'uploaded', + file_type => $params{file_type}, + file_name => $filename . '_' . $number . '_' . $ext, + mime_type => $mime_type, + itime => $::locale->parse_date_to_object($date . ' ' . $time, %dateparms), + ); + $dbfile->save; + } + #} + + closedir $dir; + } + } + } +} + +1; + +__END__ + +=pod + +=encoding utf8 + +=head1 NAME + +SL::File::Backend::Filesystem - Filesystem class for file storage backend + +=head1 SYNOPSIS + +See the synopsis of L. + +=head1 OVERVIEW + +This specific storage backend use a Filesystem which is only accessed by this interface. +This is the big difference to the Webdav backend where the files can be accessed without the control of that backend. +This backend use the database id of the SL::DB::File object as filename. The filesystem has up to 1000 subdirectories +to store the files not to flat in the filesystem. + + +=head1 METHODS + +See methods of L. + +=head1 SEE ALSO + +L + +=head1 TODO + +The synchronization must be tested and a periodical task is needed to synchronize in some time periods. + +=head1 AUTHOR + +Martin Helmling Emartin.helmling@opendynamic.deE + +=cut + +