Kunden-/Lieferantenstamm: Anzeige WebDAV-Reiter
[kivitendo-erp.git] / SL / Webdav.pm
1 package SL::Webdav;
2
3 use strict;
4 use parent qw(Rose::Object);
5
6 use Encode qw(decode);
7 use File::Spec;
8 use SL::Common;
9 use SL::Webdav::File;
10 use SL::Webdav::Object;
11 use SL::Webdav::VersionScheme::Serial;
12 use SL::Webdav::VersionScheme::Timestamp;
13
14 use Rose::Object::MakeMethods::Generic (
15   scalar => [ qw(type number) ],
16   'scalar --get_set_init' => [ qw(version_scheme) ],
17 );
18
19 my %type_to_path = (
20   sales_quotation         => 'angebote',
21   sales_order             => 'bestellungen',
22   request_quotation       => 'anfragen',
23   purchase_order          => 'lieferantenbestellungen',
24   sales_delivery_order    => 'verkaufslieferscheine',
25   purchase_delivery_order => 'einkaufslieferscheine',
26   credit_note             => 'gutschriften',
27   invoice                 => 'rechnungen',
28   purchase_invoice        => 'einkaufsrechnungen',
29   part                    => 'waren',
30   service                 => 'dienstleistungen',
31   assembly                => 'erzeugnisse',
32   letter                  => 'briefe',
33   general_ledger          => 'dialogbuchungen',
34   accounts_payable        => 'kreditorenbuchungen',
35   customer                => 'kunden',
36   vendor                  => 'lieferanten',
37 );
38
39 sub get_all_files {
40   my ($self) = @_;
41
42   my @objects = $self->get_all_objects;
43   my %files_by_name;
44
45   for my $obj (@objects) {
46     my $filename = join '.', grep $_, $obj->basename, $obj->extension;
47
48     my $file = $files_by_name{$filename} ||= SL::Webdav::File->new(filename => $filename, webdav => $self, loaded => 1);
49     $file->add_objects($obj);
50   }
51
52   return values %files_by_name;
53 }
54
55 sub get_all_objects {
56   my ($self) = @_;
57
58   my $path = $self->webdav_path;
59   my @objects;
60
61   my $base_path = $ENV{'SCRIPT_NAME'};
62   $base_path =~ s|[^/]+$||;
63   if (opendir my $dir, $path) {
64     foreach my $file (sort { lc $a cmp lc $b } map { decode("UTF-8", $_) } readdir $dir) {
65       next if (($file eq '.') || ($file eq '..'));
66
67       my $fname = $file;
68       $fname  =~ s|.*/||;
69
70       push @objects, SL::Webdav::Object->new(filename => $fname, webdav => $self);
71     }
72
73     closedir $dir;
74
75     return @objects;
76   }
77 }
78
79 sub get_all_latest {
80   my ($self) = @_;
81
82   my @files = $self->get_all_files;
83   map { ($_->versions)[-1] } @files;
84 }
85
86 sub _sanitized_number {
87   my $number = $_[0]->number;
88   $number =~ s|[/\\]|_|g;
89   $number;
90 }
91
92 sub webdav_path {
93   my ($self) = @_;
94
95   die "No client set in \$::auth" unless $::auth->client;
96   die "Need number"               unless $self->number;
97
98   my $type = $type_to_path{$self->type};
99
100   die "Unknown type"              unless $type;
101
102   my $path = File::Spec->catdir("webdav", $::auth->client->{id}, $type, $self->_sanitized_number);
103
104   if (!-d $path) {
105     Common::mkdir_with_parents($path);
106   }
107
108   return $path;
109 }
110
111 sub init_version_scheme {
112   SL::Webdav::VersionScheme::Timestamp->new;
113 }
114
115 1;
116
117 __END__
118
119 =encoding utf-8
120
121 =head1 NAME
122
123 SL::Webdav - Webdav manipulation
124
125 =head1 SYNOPSIS
126
127   # get list of all documents for this record
128   use SL::Webdav;
129
130   my $webdav = SL::Webdav->new(
131     type     => 'part',
132     number   => $number,
133   );
134
135   # gives you SL::Webdav::File instances
136   my $webdav_files = $webdav->get_all_files;
137
138   # gives you the objects instead
139   my $webdav_objects = $webdav->get_all_objects;
140
141   # gives you only the latest objects
142   my $webdav_objects = $webdav->get_all_latest;
143
144   # physical path to this dir
145   my $path = $webdav->webdav_path;
146
147 =head1 DESCRIPTION
148
149 This module is a wrapper around the webdav storage mechanism with some simple
150 document management functionality.
151
152 This is not a replacement for real document management, mostly because the
153 underlying webdav storage is not fully under our control. It's common practice
154 to allow people direct samba access to the webdav, so all versioning
155 information needs to be encoded into the filename of a file, and nonsensical
156 filenames must not break assumptions.
157
158 This module is intended to be used if you need to scan the folder for
159 previously saved files and need to build a list in order to display it.
160
161 If you need to manipulate the versions of a file, see L<SL::Webdav::File>
162
163 If you need to access a file directly for download or metadata, see L<SL::Webdav::Object>
164
165 =head1 FUNCTIONS
166
167 =over 4
168
169 =item C<get_all_objects>
170
171 Returns all L<SL::Webdav::Objects> found.
172
173 =item C<get_all_files>
174
175 Returns all objects sorted into L<SL::Webdav::File>s.
176
177 =item C<get_all_latest>
178
179 Returns only the latest object of each L<SL::Webdav::File> found.
180
181 =item C<webdav_path>
182
183 Returns the physical path to this webdav object.
184
185 =back
186
187 =head1 VERSIONING SCHEME
188
189 You may register a versioning scheme object to handle versioning. It is
190 expected to implement the following methods:
191
192 =over 4
193
194 =item C<separator>
195
196 Must return a string that will be used to separate the basename and version part of
197 filenames when generating and parsing.
198
199 =item C<extract_regexp>
200
201 Must return a regexp that will match a versioning string at the end of a
202 filename after the extension has been stripped off. It will be surrounded by
203 captures.
204
205 =item C<cmp>
206
207 Must return a comparison function that will be invoked with two
208 L<SL::Webdav::Object> instances.
209
210 =item C<first_version>
211
212 Must return a string representing the version of the first of a series of objects.
213
214 May return undef.
215
216 =item C<next_version>
217
218 Will be called with the latest L<SL::Webdav::Object> and must return a new version string.
219
220 =item C<keep_last_version>
221
222 Will be called with the latest L<SL::Webdav::Object>. Truish return value will
223 cause the latest object to be overwritten instead of creating a new version.
224
225 =back
226
227 =head1 BUGS AND CAVEATS
228
229 =over 4
230
231 =item *
232
233 File operations are inconsistently L<File::Spec>ed.
234
235 =back
236
237 =head1 SEE ALSO
238
239 L<SL::Webdav::File>, L<SL::Webdav::Object>
240
241 =head1 AUTHOR
242
243 Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
244
245 =cut