source: extensions/pLoader/trunk/src/Uploader/PWG/WebServices.pm @ 4610

Last change on this file since 4610 was 4610, checked in by ronosman, 14 years ago

Bug 1362 fixed : cannot connect to Piwigo when hosted by free.fr

  • Property svn:eol-style set to LF
File size: 16.8 KB
RevLine 
[2597]1# +-----------------------------------------------------------------------+
2# | pLoader - a Perl photo uploader for Piwigo                            |
3# +-----------------------------------------------------------------------+
4# | Copyright(C) 2008      Piwigo Team                  http://piwigo.org |
5# +-----------------------------------------------------------------------+
6# | This program is free software; you can redistribute it and/or modify  |
7# | it under the terms of the GNU General Public License as published by  |
8# | the Free Software Foundation                                          |
9# |                                                                       |
10# | This program is distributed in the hope that it will be useful, but   |
11# | WITHOUT ANY WARRANTY; without even the implied warranty of            |
12# | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
13# | General Public License for more details.                              |
14# |                                                                       |
15# | You should have received a copy of the GNU General Public License     |
16# | along with this program; if not, write to the Free Software           |
17# | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
18# | USA.                                                                  |
19# +-----------------------------------------------------------------------+
20package Uploader::PWG::WebServices;
21 
22use strict;
23use warnings;
[3194]24use MIME::Base64 qw(encode_base64); 
[2597]25use JSON;
26use LWP::UserAgent;
27use Data::Dumper;
28use Digest::MD5::File qw/file_md5_hex md5_hex/;
29use File::Slurp;
[4279]30use File::Spec;
[3194]31use POSIX qw(ceil floor);
[2597]32use base qw/
33           Uploader::Object
34           Class::Accessor::Fast
35           /;
36
37__PACKAGE__->mk_accessors( 
38    qw/
39           uagent
40           urlbase
41           username
42           password
43           qry_list_categories
[2661]44           qry_add_categories
[3472]45           qry_list_tags
[2597]46           items
47           tags
48           categories
[2696]49           site_high_file
50           site_resized_file
51           site_thumb_file
52           site_image_name
[3472]53           site_tags
[2597]54           rank
[2696]55           site_author
56           site_comment
57           site_img_date_creation
[2618]58           uagent_response
59           login_result
60           action_result
[2696]61           upload_high
[3194]62           chunk_size
[4467]63           sum
64           image_id
65           typecode
66                   reupload_action_files
67                   reupload_action_properties
68                   reupload_action_properties_m
69                   single_value_mode
70                   multiple_value_mode
[4476]71                   privacy_level
[2597]72      / 
73);
74
75$|=1;
76
77sub Init {
[4268]78    my ( $self, $version ) = @_ ;
[4467]79
80    # to transform a type_code into a typename
81    $self->typecode(
82        {
83             file => 'file',
84             thumbnail => 'thumb',
85             high => 'high',   
86        }
87    );
88       
89        $self->single_value_mode(
90            {
91                    1 => 'fill_if_empty',
92                        2 => 'replace',
93                }
94        );
95
96        $self->multiple_value_mode(
97            {
98                    1 => 'append',
99                        2 => 'replace',
100                }
101        );
102       
[2597]103    $self->uagent(
[4268]104        LWP::UserAgent->new(
105            agent => sprintf("Mozilla/pLoader %s", $version)       
106        )
[2597]107    );
108   
109    $self->uagent->cookie_jar({});     
110
111    $self->urlbase(
112        $self->{site_url}
113    );
114   
115    $self->username(
116        $self->{site_username}
117    );
118   
119    $self->password(
120        $self->{site_password}
121    );
[3467]122   
123    $self->chunk_size(
124        $self->{chunk_size}
125    );
[3285]126
[2597]127   
[3285]128    $self->uagent->default_headers->authorization_basic(
129        $self->{http_username}||$self->username, 
130        $self->{http_password}||$self->password
131    );
132   
[3194]133   
[2597]134    $self->qry_list_categories( sprintf
135        "%s/ws.php?format=json&method=%s&recursive=%s",
136        $self->urlbase,
[3176]137#        'pwg.categories.getAdminList',
138        'pwg.categories.getList',
[2597]139        'true',
140    );
141
[3472]142    $self->qry_list_tags( sprintf
143        "%s/ws.php?format=json&method=%s",
144        $self->urlbase,
145        'pwg.tags.getAdminList',
146    );
147
148
[2597]149    my $form = {
150        method => 'pwg.session.login',
151        username => $self->username,
152        password => $self->password,
153    };
154 
[4467]155    $self->_execute_post(
156        $form
157    );   
158
159    $self->login_result(
160        $self->_json_response_content
[2618]161    );
[4467]162
163}
164
165sub _json_response_content {
166    my ( $self ) = @_;
167
[2618]168    my $hresult = {} ;
169
170    if($self->uagent_response->is_success){
171        eval {
172            $hresult = from_json(
[4610]173                $self->uagent_response->content
[2618]174            );
175        };
[4610]176                if($@){
177            # when server response has warnings, the content response is not a valid json string
178                    # find the json response
179            $self->uagent_response->content =~ /(\{.+\})/;
180                    #printf("json response %s\n", $1);
181            eval {
182                $hresult = from_json(
183                    $1
184                );
185            };
186        }               
[2618]187    }
188    else{
[4476]189        $hresult = {
[2618]190            'message' => $self->uagent_response->message,
191            'stat'    => 'fail',
192        };
193    }
[4467]194       
195        $hresult;
[2597]196}
197
[4467]198sub _execute_get {
199    my ( $self, $query ) = @_;
[2597]200
201    eval {
[4467]202        $self->uagent_response(
203            $self->uagent->get(
204                $query
205                    )
[2597]206        );
207    };
208
209    if($@){
210        printf("An error occured in query execution %s\n%s",
[4467]211            $query,
[2597]212            $@,
213        );     
214    }
215}
216
[4467]217sub _execute_post {
218    my ( $self, $form ) = @_;
[3472]219
220    my $result;
221    eval {
[4467]222        $result = $self->uagent_response(
223            $self->uagent->post(
224                $self->urlbase.'/ws.php?format=json',
225                $form
226            )
[3472]227        );
[4467]228        };
[3472]229
230    if($@){
[4467]231        printf("An error occured in post execution %s\n%s",
232            $form->{method},
[3472]233            $@,
234        );     
235    }
[4467]236       
237        return ( $result->is_success, $result->status_line );
238}
239sub GetCategories {
240    my ( $self ) = @_;
[3472]241
[4467]242 
243    $self->_execute_get(
244            $self->qry_list_categories
245        );
246    $self->_json_response_content->{result}{categories};
[3472]247}
248
[4467]249sub GetTags {
250    my ( $self ) = @_;
251
252    $self->_execute_get(
253        $self->qry_list_tags   
254        );
255    $self->_json_response_content->{result}{tags};
256}
257
[3504]258sub AddTags {
259    my ( $self, $name ) = @_;
[3472]260
[3504]261    my $form = {
262        method            => 'pwg.tags.add',
263        name              => $name,
264       
265    };
266
[4467]267    return ( $self->_execute_post($form), $self->_json_response_content );
[3504]268} 
269
270
[2597]271sub UploadImage {
[4279]272    my ( $self, $progress ) = @_;
[2597]273
[4467]274    $self->image_id(
275        $self->_exists($progress->{original_sum})
[4291]276    );
[3230]277
[4467]278    my $status = 1;
279    my $status_line ="OK";
[3509]280    my $content = {};
[4291]281    my $doubleCheck;
282    my $form;
[4467]283    UPLOAD: while(1){
284        # first upload
285        if(!defined($self->image_id)){ 
286            $doubleCheck = 1;
287            $self->_checksum_files($progress);
288            my @types = ('file', 'thumb');
[4586]289            #printf("WS upload_high %s\n", $self->upload_high);
[4467]290            push @types, 'high' if $self->upload_high;
291            map{
292                my $rval = $self->_send_chunks($_, $progress);
293                $status_line = $rval->{message};
294                last UPLOAD if !$rval->{ok};
295            } @types;
[3451]296         
297       
298            $form = {
299                method            => 'pwg.images.add',
[4467]300                original_sum      => $self->sum->{original},
301                file_sum          => $self->sum->{file},
302                thumbnail_sum     => $self->sum->{thumb},
[3451]303                categories        => $self->categories,
[4467]304                name              => $self->site_image_name,
[3451]305                author            => $self->site_author,
306                comment           => $self->site_comment,
307                date_creation     => $self->site_img_date_creation,
[3472]308                tag_ids           => $self->site_tags,
[3451]309               
310            };
[4467]311
312           $form->{high_sum} = $self->sum->{high} if $self->upload_high;
313                   
314           $progress->{yield}->();
[4476]315           ( $status, $status_line ) = $self->_execute_post($form);
[4467]316                }
317        # re-upload
318        else{
319            # need to check if files have changed
320            # and update image info
321            if($self->reupload_action_files){
322                $self->_checksum_files($progress);
323                my $files = $self->_check_files();
324                if(defined($files)){
325                    $self->_add_files($files, $progress);       
326                }
[3451]327            }
[4467]328
[3451]329            $form = {
[4467]330                    method        => 'pwg.images.setInfo',
331                    image_id      => $self->image_id,
332                    };
333            # update metadata info
334            if($self->reupload_action_properties){     
[4476]335                        #printf("reupload_action_properties %s\n", $self->reupload_action_properties);
336                $form->{name}          = $self->site_image_name;
[4467]337                $form->{author}        = $self->site_author;
338                $form->{comment}       = $self->site_comment;
339                $form->{date_creation} = $self->site_img_date_creation;
340                                $form->{single_value_mode}  = $self->single_value_mode->{$self->reupload_action_properties};
[4476]341                $form->{level} = $self->privacy_level ? 2**($self->privacy_level - 1) : 0;
[4467]342                    }
343            if($self->reupload_action_properties_m){   
344                            #printf("reupload_action_properties_m %s\n", $self->reupload_action_properties_m);
345                $form->{tag_ids} = $self->site_tags if $self->site_tags;
346                $form->{categories} = $self->categories;
347                                $form->{multiple_value_mode} = $self->multiple_value_mode->{$self->reupload_action_properties_m};
[3451]348            };
[4291]349            $progress->{yield}->();
[4467]350            ( $status, $status_line ) = $self->_execute_post($form); 
[4097]351
[4476]352                }
353
[4097]354        delete $form->{tag_ids} unless defined $self->site_tags;
355        delete $form->{tag_ids} if '' eq $self->site_tags;
356
[4291]357        $progress->{yield}->();
[4476]358        # for first upload
359        if($doubleCheck){
360                    $self->image_id(
361                            $self->_exists($progress->{original_sum})
362                        );
363            $content->{stat} = !defined $self->image_id  ? 'fail' : 'ok'; 
364            if(defined $self->image_id and defined $self->privacy_level){
365                    ( $status, $status_line, $content ) = $self->_set_privacy_level;
366                }
367        }
[3509]368
[4467]369                last UPLOAD;
370    }# UPLOAD
[3451]371   
[4467]372    return ( $status,  $status_line, $content);
373}
[3509]374
[4476]375sub _set_privacy_level {
376    my ( $self ) = @_;
377               
378    my $form = {
379        method        => 'pwg.images.setPrivacyLevel',
380        image_id      => $self->image_id,
381        level         => $self->privacy_level ? 2**($self->privacy_level - 1) : 0,
382    };
383        print Dumper $form;
384        my ( $status, $status_line ) = $self->_execute_post($form); 
385    my $hresult = $self->_json_response_content;
386
387    ($status, $status_line, $hresult );
388}
389
[4467]390sub _checksum_files {
391    my ( $self, $progress ) = @_;
392
393    $self->sum(
394        {
395            file => $self->_checksum(
396                        $self->site_resized_file,
397                        $progress
398                    ),
399            thumb => $self->_checksum(
400                             $self->site_thumb_file,
401                             $progress
402                         ),
[4586]403            original => $progress->{original_sum}
404        }
405    ); 
406
[4467]407            high => $self->_checksum(
408                        $self->site_high_file,
409                        $progress
410                    ),
[4586]411
412    $self->sum->{high} = $self->_checksum(
413                        $self->site_high_file,
414                        $progress
415    ) if $self->upload_high ;
[4467]416}
[4291]417
[4467]418sub _check_files {
419    my ( $self ) = @_;
420
421    my $form = {
422        method   => 'pwg.images.checkFiles',
423        image_id => $self->image_id,
424    };
425   
426    @$form{'thumbnail_sum', 'file_sum' } = (
427        $self->sum->{thumb},
428        $self->sum->{file},
429    );
430
431    if($self->upload_high){
432        $form->{high_sum} = $self->sum->{high};
[2696]433    }
[4467]434
435    $self->_execute_post($form);   
436    my $hresult = $self->_json_response_content;
437
438    my $rval = 'ok' eq $hresult->{stat} ? $hresult->{result} : undef;
[3451]439   
[4467]440    $rval;
[2597]441}
[2661]442
[4467]443# $files is returned by _check_files
444# {
445#     thumbnail => 'equals', 'differs', 'missing'
446#     file => 'equals', 'differs', 'missing'
447#     high => 'equals', 'differs', 'missing'
448#}
449
450sub _add_files {
451    my ( $self, $files, $progress ) = @_;
452
453    map{
454        $self->_add_file($_, $progress);
455    }
456    map{
457        $self->typecode->{$_};
458    } grep { 'equals' ne $files->{$_} } keys %$files ;
459       
460}
461
462sub _add_file {
463    my ( $self, $type_code, $progress ) = @_;
464
465    $self->_send_chunks(
466        $type_code,
467        $progress,
468    );
469
470    my $form = {
471        method => 'pwg.images.addFile',
472        image_id => $self->image_id,
473        type     => $type_code,
474        sum      => $self->sum->{$type_code},           
475    }; 
476
477    $self->_execute_post($form);   
478    my $hresult = $self->_json_response_content;
[4476]479
[4467]480    my $rval = 'ok' eq $hresult->{stat} ? $hresult->{result} : undef;
481   
482    $rval;
483}
484
485sub IsAlreadyUploaded {
486    my ( $self, $md5_sums ) = @_;
487       
488        # md5_sums is an array ref
489        $self->_execute_post({
490        method      => 'pwg.images.exist',
491        md5sum_list => join(',', @$md5_sums)
492            }
493        );
494
495        my $sums = $self->_json_response_content->{result};
496
497    $sums;
498}
499
[4291]500sub _exists {
501    my ( $self, $md5_sum ) = @_;
502
503    my $form = {
504        method            => 'pwg.images.exist',
505        md5sum_list       => $md5_sum,
506    };
507
[4467]508    $self->_execute_post($form);   
509    my $hresult = $self->_json_response_content;
[4291]510
[4467]511        $hresult->{result} = {} if 'HASH' ne ref $hresult->{result};
512    my $id = 'ok' eq $hresult->{stat} ? $hresult->{result}{$md5_sum} : undef ;
513
[4291]514    $id;
515} 
516
517sub _checksum {
518    my ( $self, $file, $progress ) = @_;
519    my $file_sum;
520
521    my $yield = $progress->{yield};
522
523    $yield->();
524    $progress->{msg_details}->(
525        sprintf(
526            "%s : %s", 
527            $progress->{checksum_msg}, 
528            $file
529        )
530    );
531    eval {
532        $file_sum = file_md5_hex(
533            $file
534        );
535    };
536    $yield->();
537
538    $file_sum;
539}
540
541sub _send_chunks {
[4467]542    my ( $self, $type_code, $progress ) = @_;
[4291]543
544    my $msg = {
545        thumb=>'thumbnail_msg',
546        file=>'resized_msg',
547        high=>'highdef_msg',
548    };
549
550    my $filepath = {
551        thumb=>$self->site_thumb_file,
552        file=>$self->site_resized_file,
553        high=>$self->site_high_file,
554    };
555
[4467]556    $progress->{current_msg} = $progress->{$msg->{$type_code}};
[4291]557    $progress->{yield}->();
558
559    my $params = {
[4467]560         filepath      => $filepath->{$type_code},
561         type          => $type_code,
562         original_sum  => $self->sum->{original},
[4291]563    };
[4586]564    #print Dumper $params;
[4291]565    $self->send_chunks(
566       $params,
567       $progress,
568    );
569    $progress->{yield}->();
570
571    $params;
572}
573
[2661]574sub AddCategories{
575    my ( $self, $name, $parentid ) = @_;
576
577    my $form = {
578        method            => 'pwg.categories.add',
579        name              => $name,
580        parent            => $parentid,
581       
582    };
583       
[4467]584    return ( $self->_execute_post($form), $self->_json_response_content );
[3194]585}
586
[3466]587sub SetInfoCategories{
588    my ( $self, $name, $comment, $parentid ) = @_;
[3194]589
[3466]590    my $form = {
591        method            => 'pwg.categories.setInfo',
592        name              => $name,
593        comment           => $comment,
594        category_id       => $parentid,
595       
596    };
597
[4467]598    return ( $self->_execute_post($form), $self->_json_response_content );
[3466]599}
600
601
[3194]602sub send_chunks {
[4279]603    my ( $self, $params, $progress ) = @_;
[3194]604
[4279]605    my $yield = $progress->{yield};
606    my ( $vol, $dir, $filename ) = File::Spec->splitpath($params->{filepath});
607
608    $yield->();
609    $progress->{bar}->(0);
610    $yield->();
611    $progress->{msg_details}->(
612        sprintf(
613            "%s : %s", 
614            $progress->{current_msg}, 
615            $filename
616        )
617    );
618
619
620    $yield->();
[3268]621    my $content = read_file(
622        $params->{filepath},
623        binmode => ':raw',
[3194]624    );
[4279]625    $yield->();
[3194]626
627    my $content_length = length($content);
628    my $nb_chunks = ceil($content_length / $self->chunk_size);
629
630    my $chunk_pos = 0;
631    my $chunk_id = 1;
[4279]632
633
[3194]634    while ($chunk_pos < $content_length) {
[4279]635
[3194]636        my $chunk = substr(
637            $content,
638            $chunk_pos,
639            $self->chunk_size
640        );
641        $chunk_pos += $self->chunk_size;
642        my $response = $self->uagent->post(
643            $self->urlbase.'/ws.php?format=json',
644            {
645                method       => 'pwg.images.addChunk',
[3268]646                data         => encode_base64($chunk),
[3194]647                original_sum => $params->{original_sum},
648                position     => $chunk_id,
649                type         => $params->{type},
650            }
651        );
[4279]652        $yield->();
653        $progress->{bar}->(100*($chunk_pos/$content_length));
654        $progress->{msg_details}->(
655            sprintf(
656                "%s : %s", 
657                $progress->{current_msg}, 
658                $filename
659            )
660        );
[3451]661        $params->{ok} = 1;
[3194]662        if ($response->code != 200) {
663            printf("response code    : %u\n", $response->code);
664            printf("response message : %s\n", $response->message);
[3451]665            $params->{ok} = 0;
666            $params->{message} = $response->message;
667            $params->{code} = $response->code;
668            last;
[3194]669        }
670
671        $chunk_id++;
672    }
673}
674
675 
[2597]6761;
677   
Note: See TracBrowser for help on using the repository browser.