File Coverage

blib/lib/Net/API/Gett.pm
Criterion Covered Total %
statement 74 143 51.7
branch 10 64 15.6
condition 4 18 22.2
subroutine 17 21 80.9
pod 7 8 87.5
total 112 254 44.0


line stmt bran cond sub pod time code
1             package Net::API::Gett;
2              
3 5     5   224747 use strict;
  5         14  
  5         387  
4 5     5   28 use warnings;
  5         12  
  5         147  
5              
6 5     5   8688 use 5.010;
  5         23  
  5         205  
7              
8 5     5   6580 use Moo;
  5         107613  
  5         41  
9 5     5   10791 use Carp qw(croak);
  5         14  
  5         384  
10 5     5   29 use Scalar::Util qw(looks_like_number);
  5         11  
  5         412  
11              
12 5     5   3497 use Net::API::Gett::User;
  5         18  
  5         161  
13 5     5   3684 use Net::API::Gett::Share;
  5         16  
  5         185  
14 5     5   3757 use Net::API::Gett::File;
  5         18  
  5         338  
15 5     5   129 use Net::API::Gett::Request;
  5         13  
  5         399  
16              
17             BEGIN {
18 5 50   5   13548 require LWP::Protocol::https or die "This module requires HTTPS, please install LWP::Protocol::https\n";
19             }
20              
21             =head1 NAME
22              
23             Net::API::Gett - Perl bindings for Ge.tt API
24              
25             =head1 VERSION
26              
27             Version 1.06
28              
29             =cut
30              
31             our $VERSION = '1.06';
32              
33             =head1 SYNOPSIS
34              
35             use 5.010;
36             use Net::API::Gett;
37              
38             # Get API Key from http://ge.tt/developers
39              
40             my $gett = Net::API::Gett->new(
41             api_key => 'GettAPIKey',
42             email => 'me@example.com',
43             password => 'mysecret',
44             );
45              
46             my $file_obj = $gett->upload_file(
47             filename => "ossm.txt",
48             contents => "/some/path/example.txt",
49             title => "My Awesome File",
50             encoding => ":encoding(UTF-8)"
51             );
52              
53             say "File has been shared at " . $file_obj->getturl;
54              
55             # Download contents
56             my $file_contents = $file_obj->contents();
57              
58             open my $fh, ">:encoding(UTF-8)", "/some/path/example-copy.txt"
59             or die $!;
60             print $fh $file_contents;
61             close $fh;
62              
63             # clean up share and file(s)
64             my $share = $gett->get_share($file->sharename);
65             $share->destroy();
66              
67             =head1 ABOUT
68              
69             L is a clutter-free file sharing service that allows its users to
70             share up to 2 GB of files for free. They recently implemented a REST API; this is a
71             binding for the API. See L for full details and how to get an
72             API key.
73              
74             =head1 CHANGES FROM PREVIOUS VERSION
75              
76             This library is more encapsulated. Share functions which act on shares are in the L
77             object namespace, and likewise with Ge.tt L. Future versions of this library
78             will modify the L and L objects to be
79             L rather than objects.
80              
81             =cut
82              
83             sub BUILD {
84 2     2 0 21825 my $self = shift;
85 2         12 my $args = shift;
86              
87 2 50       21 unless ( $self->has_user ) {
88 2 0 33     100 if ( $args->{refresh_token} ||
      33        
      33        
      33        
89             $args->{access_token} ||
90             ( $args->{api_key} && $args->{email} && $args->{password} ) ) {
91 0         0 $self->user( Net::API::Gett::User->new(%{$args}) );
  0         0  
92             }
93             }
94             }
95              
96             =head1 ATTRIBUTES
97              
98             =over
99              
100             =item user
101              
102             L object. C predicate.
103              
104             =back
105              
106             =cut
107              
108             has 'user' => (
109             is => 'rw',
110             lazy => 1,
111             predicate => 'has_user',
112             isa => sub { die "$_[0] is not Net::API::Gett::User" unless ref($_[0]) =~ /User/ },
113             );
114              
115             =over
116              
117             =item request
118              
119             L object.
120              
121             =back
122              
123             =cut
124              
125             has 'request' => (
126             is => 'rw',
127             isa => sub { die "$_[0] is not Net::API::Gett::Request" unless ref($_[0]) =~ /Request/ },
128             default => sub { Net::API::Gett::Request->new() },
129             lazy => 1,
130             );
131              
132             =head1 METHODS
133              
134             Unless otherwise noted, these methods die if an error occurs or if they get a response from the API
135             which is not successful. If you need to handle errors more gracefully, use L to catch fatal
136             errors.
137              
138             =over
139              
140             =item new()
141              
142             Constructs a new object. Optionally accepts:
143              
144             =over
145              
146             =item * A Ge.tt API key, email, and password, or,
147              
148             =item * A Ge.tt refresh token, or,
149              
150             =item * A Ge.tt access token
151              
152             =back
153              
154             If any of these parameters are passed, they will be proxied into the L object which
155             will then permit you to make authenticated API calls. Without an access token (or the means to acquire one)
156             only non-authenticated calls are allowed; they are: C, C,
157             C<$file-Ethumbnail()> and C<$file-Econtents()>.
158              
159             =back
160              
161             =head2 Share functions
162              
163             All of these functions cache L objects. Retrieve objects from the
164             cache using the C method. Use the C method to update a cache entry if it
165             is stale.
166              
167             =over
168              
169             =item get_shares()
170              
171             Retrieves B share information for the given user. Takes optional scalar integers
172             C and C parameters, respectively.
173              
174             Returns an unordered list of L objects.
175              
176             =back
177              
178             =cut
179              
180             sub get_shares {
181 0     0 1 0 my $self = shift;
182 0 0       0 croak "Can't call get_shares() without Net::API::Gett::User object" unless $self->has_user;
183              
184 0         0 my $offset = shift;
185 0         0 my $limit = shift;
186              
187 0 0       0 $self->user->login unless $self->user->has_access_token;
188              
189 0         0 my $endpoint = "/shares?accesstoken=" . $self->user->access_token;
190              
191 0 0 0     0 if ( defined $offset && looks_like_number $offset ) {
192 0         0 $endpoint .= "&skip=$offset";
193             }
194              
195 0 0 0     0 if ( defined $limit && looks_like_number $limit ) {
196 0         0 $endpoint .= "&limit=$limit";
197             }
198              
199 0         0 my $response = $self->request->get($endpoint);
200              
201 0 0       0 if ( $response ) {
202 0         0 foreach my $share_href ( @{ $response } ) {
  0         0  
203 0 0       0 next unless $share_href;
204 0         0 $self->add_share(
205             $self->_build_share($share_href)
206             );
207             }
208 0         0 return $self->shares;
209             }
210             else {
211 0         0 return undef;
212             }
213             }
214              
215             =over
216              
217             =item get_share()
218              
219             Retrieves (and/or refreshes cached) information about a specific single share.
220             Requires a C parameter. Does not require an access token to call.
221              
222             Returns a L object.
223              
224             =back
225              
226             =cut
227              
228             sub get_share {
229 2     2 1 1945 my $self = shift;
230 2         6 my $sharename = shift;
231              
232 2 50       17 return undef unless $sharename =~ /\w+/;
233              
234 2         40 my $response = $self->request->get("/shares/$sharename");
235              
236 2 50       16 if ( $response ) {
237 2         18 my $share = $self->_build_share($response);
238 2         11 $self->add_share($share);
239 2         48 return $share;
240             }
241             else {
242 0         0 return undef;
243             }
244             }
245              
246             =over
247              
248             =item create_share()
249              
250             This method creates a new share instance to hold files. Takes an optional string scalar
251             parameter which sets the share's title attribute.
252              
253             Returns the new share as a L object.
254              
255             =back
256              
257             =cut
258              
259             sub create_share {
260 0     0 1 0 my $self = shift;
261 0 0       0 croak "Can't call create_share() without Net::API::Gett::User object" unless $self->has_user;
262              
263 0         0 my $title = shift;
264              
265 0 0       0 $self->user->login unless $self->user->has_access_token;
266              
267 0         0 my @args = ("/shares/create?accesstoken=".$self->user->access_token);
268 0 0       0 if ( $title ) {
269 0         0 push @args, { title => $title };
270             }
271 0         0 my $response = $self->request->post(@args);
272              
273 0 0       0 if ( $response ) {
274 0         0 my $share = $self->_build_share($response);
275 0         0 $self->add_share($share);
276 0         0 return $share;
277             }
278             else {
279 0         0 return undef;
280             }
281             }
282              
283             =head2 File functions
284              
285             =over
286              
287             =item get_file()
288              
289             Returns a L object given a C and a C.
290             Does not require an access token to call.
291              
292             =back
293              
294             =cut
295              
296             sub get_file {
297 1     1 1 485 my $self = shift;
298 1         2 my $sharename = shift;
299 1         2 my $fileid = shift;
300              
301 1         33 my $response = $self->request->get("/files/$sharename/$fileid");
302              
303 1 50       7 if ( $response ) {
304 1         8 return $self->_build_file($response);
305             }
306             else {
307 0         0 return undef;
308             }
309             }
310              
311             =over
312              
313             =item upload_file()
314              
315             This method uploads a file to Gett. The following key/value pairs are valid:
316              
317             =over
318              
319             =item * filename (B)
320            
321             What to call the uploaded file when it's inside of the Gett service.
322              
323             =item * sharename (optional)
324            
325             Where to store the uploaded file. If not specified, a new share will be automatically created.
326              
327             =item * title (optional)
328            
329             If specified, this value is used when creating a new share to hold the file. It will not change
330             the title of an existing share. See the C method on the share object to do that.
331              
332             =item * content (optional)
333              
334             A synonym for C. (Yes, I've typo'd this too many times.) Anything in C has
335             precedent, if they're both specified.
336              
337             =item * contents (optional)
338              
339             A representation of the file's contents. This can be one of:
340              
341             =over
342              
343             =item * A buffer (See note below)
344              
345             =item * An L object
346              
347             =item * A FILEGLOB
348              
349             =item * A pathname to a file to be read
350              
351             =back
352              
353             If not specified, the C parameter is treated as a pathname. This attempts to be DWIM,
354             in the sense that if C contains a value which is not a valid filename, it treats
355             C as a buffer and uploads that data.
356              
357             =item * encoding
358              
359             An encoding scheme for the file content. By default it uses C<:raw>. See C
360             for more information about encodings.
361              
362             =item * chunk_size
363              
364             The chunk_size in bytes to use when uploading a file. Defaults to 1 MB.
365              
366             =back
367              
368             Returns a L object representing the uploaded file.
369              
370             =back
371              
372             =cut
373              
374             sub upload_file {
375 0     0 1 0 my $self = shift;
376 0         0 my $opts = { @_ };
377              
378 0 0       0 return undef unless ref($opts) eq "HASH";
379              
380 0         0 my $sharename = $opts->{'sharename'};
381              
382 0 0       0 if ( not $sharename ) {
383 0         0 my $share = $self->create_share($opts->{'title'});
384 0         0 $sharename = $share->sharename;
385             }
386              
387 0 0       0 $self->user->login unless $self->user->has_access_token;
388              
389 0         0 my $endpoint = "/files/$sharename/create?accesstoken=".$self->user->access_token;
390            
391 0         0 my $filename = $opts->{'filename'};
392              
393 0         0 my $response = $self->request->post($endpoint, { filename => $filename });
394              
395             # typo proof this - yeah I've been bitten by this!
396 0 0       0 unless ( exists $opts->{'contents'} ) {
397 0 0       0 if ( exists $opts->{'content'} ) {
398 0         0 $opts->{'contents'} = delete $opts->{'content'};
399             }
400             else {
401 0         0 $opts->{'contents'} = $filename
402             }
403             }
404              
405 0 0       0 if ( $response ) {
406 0         0 my $file = $self->_build_file($response);
407 0 0       0 if ( $file->readystate eq "remote" ) {
408 0         0 my $put_upload_url = $file->put_upload_url;
409 0 0       0 croak "Didn't get put upload URL from $endpoint" unless $put_upload_url;
410 0 0       0 if ( $file->send_file($put_upload_url, $opts->{'contents'},
411             $opts->{'encoding'}, $opts->{'chunk_size'}) ) {
412 0         0 return $file;
413             }
414             else {
415 0         0 croak "There was an error reading data from " . $opts->{'contents'};
416             }
417             }
418             else {
419 0         0 croak "$endpoint doesn't have right readystate";
420             }
421             }
422             else {
423 0         0 return undef;
424             }
425             }
426              
427             sub _build_share {
428 2     2   7 my $self = shift;
429 2         5 my $share_href = shift;
430              
431 2         37 my $share = Net::API::Gett::Share->new(
432             sharename => $share_href->{'sharename'},
433             created => $share_href->{'created'},
434             title => $share_href->{'title'},
435             getturl => $share_href->{'getturl'},
436             );
437 2         6058 foreach my $file_href ( @{ $share_href->{'files'} } ) {
  2         9  
438 16 50       54 next unless $file_href;
439 16         43 my $file = $self->_build_file($file_href);
440 16         263 $share->add_file($file);
441             }
442 2 50       15 $share->user($self->user) if $self->has_user;
443              
444 2         9 return $share;
445             }
446              
447             sub _build_file {
448 17     17   28 my $self = shift;
449 17         31 my $file_href = shift;
450              
451             # filter out undefined attributes
452 17         37 my @attrs = grep { defined $file_href->{$_} }
  153         485  
453             qw(filename size created fileid downloads readystate getturl download sharename);
454 17         36 my @params = map { $_ => $file_href->{$_} } @attrs;
  120         500  
455              
456 17 50       65 if ( exists $file_href->{'upload'} ) {
457 0         0 push @params, 'put_upload_url' => $file_href->{'upload'}->{'puturl'};
458 0         0 push @params, 'post_upload_url' => $file_href->{'upload'}->{'posturl'};
459             }
460              
461 17         1029 my $file = Net::API::Gett::File->new( @params );
462 17 50       8216 $file->user($self->user) if $self->has_user;
463            
464 17         106 return $file;
465             }
466              
467             =over
468              
469             =item add_share()
470              
471             This method populates/updates the L object local cache.
472              
473             It returns undef if the passed value isn't a L object.
474              
475             =back
476              
477             =cut
478              
479             sub add_share {
480 2     2 1 6 my $self = shift;
481 2         5 my $share = shift;
482              
483 2 50       15 return undef unless ref($share) =~ /Share/;
484              
485 2         9 my $sharename = $share->sharename();
486              
487 2         10 $self->{'shares'}->{$sharename} = $share;
488             }
489              
490             =over
491              
492             =item shares()
493              
494             This method retrieves one or more cached L objects. Objects are
495             requested by sharename. If no parameter list is specified, B cached objects are
496             returned in an unordered list. (The list will B be in the order shares were added
497             to the cache.)
498              
499             If no objects are cached, this method returns an empty list.
500              
501             =back
502              
503             =cut
504              
505             sub shares {
506 0     0 1   my $self = shift;
507              
508 0 0         if ( @_ ) {
509 0           return map { $self->{'shares'}->{$_} } @_;
  0            
510             }
511              
512 0 0         return () unless exists $self->{'shares'};
513              
514 0           return values %{ $self->{'shares'} };
  0            
515             }
516              
517             =head1 AUTHOR
518              
519             Mark Allen, C<< >>
520              
521             =head1 BUGS
522              
523             Please report any bugs or feature requests to C, or through
524             the web interface at L. I will
525             be notified, and then you'll automatically be notified of progress on your bug as I make changes.
526              
527             =head1 SUPPORT
528              
529             You can find documentation for this module with the perldoc command.
530              
531             perldoc Net::API::Gett
532              
533             You can also look for information at:
534              
535             =over 4
536              
537             =item * RT: CPAN's request tracker (report bugs here)
538              
539             L
540              
541             =item * AnnoCPAN: Annotated CPAN documentation
542              
543             L
544              
545             =item * CPAN Ratings
546              
547             L
548              
549             =item * MetaCPAN
550              
551             L
552              
553             =item * GitHub
554              
555             L
556              
557             =back
558              
559             =head1 SEE ALSO
560              
561             L
562              
563             =head1 CONTRIBUTORS
564              
565             Thanks to the following for patches:
566              
567             =over
568              
569             =item
570              
571             Keedi Kim (L)
572              
573             =item
574              
575             Alexander Ost
576              
577             =back
578              
579             =head1 LICENSE AND COPYRIGHT
580              
581             Copyright 2011 Mark Allen.
582              
583             This program is free software; you can redistribute it and/or modify it
584             under the terms of either: the GNU General Public License as published
585             by the Free Software Foundation; or the Artistic License.
586              
587             See http://dev.perl.org/licenses/ for more information.
588              
589             =cut
590              
591             1; # End of Net::API::Gett