File Coverage

blib/lib/Net/Google/Drive/Simple/V3.pm
Criterion Covered Total %
statement 106 553 19.1
branch 49 354 13.8
condition 11 258 4.2
subroutine 23 86 26.7
pod 54 54 100.0
total 243 1305 18.6


line stmt bran cond sub pod time code
1             ###########################################
2             ###########################################
3              
4             use strict;
5 10     10   1439609 use warnings;
  10         64  
  10         266  
6 10     10   43 use parent qw< Net::Google::Drive::Simple::Core >;
  10         19  
  10         249  
7 10     10   49  
  10         20  
  10         54  
8             use URI ();
9 10     10   561 use URI::QueryParam ();
  10         21  
  10         157  
10 10     10   4414 use File::Basename ();
  10         7055  
  10         195  
11 10     10   56 use JSON qw< from_json >;
  10         19  
  10         159  
12 10     10   40 use Log::Log4perl qw(:easy);
  10         21  
  10         68  
13 10     10   1082  
  10         23  
  10         74  
14             use constant {
15             'HTTP_METHOD_GET' => 'GET',
16 10         3150 'HTTP_METHOD_POST' => 'POST',
17             'HTTP_METHOD_PUT' => 'PUT',
18             'HTTP_METHOD_PATCH' => 'PATCH',
19             'HTTP_METHOD_DELETE' => 'DELETE',
20              
21             'TYPE_STRING' => 'string',
22             'TYPE_INTEGER' => 'integer',
23             'TYPE_LONG' => 'long',
24             'TYPE_BOOLEAN' => 'boolean',
25             'TYPE_OBJECT' => 'object',
26             'TYPE_BYTES' => 'bytes',
27              
28             'SIZE_256K' => 262_144, # default chunk size
29             'SIZE_5MB' => 5_242_880, # low limit
30             'SIZE_5120GB' => 5_497_558_138_880 # high limit
31             };
32 10     10   7456  
  10         38  
33             use constant { 'DEF_CHUNK_SIZE' => SIZE_5MB() * 2 }; # 10 MB
34 10     10   63  
  10         21  
  10         87140  
35             our $VERSION = '3.02';
36              
37             # TODO:
38             # * requestId are random UUIDs that we should probably generate (drive_create)
39             # * Support for Request Body values
40             # * Support fields format: https://developers.google.com/drive/api/guides/fields-parameter
41             # * Add validation for path parameters
42             # * Specific types (like ISO 639-1)
43             # * Extended upload support: https://developers.google.com/drive/api/guides/manage-uploads
44              
45             # These are only the defaults
46             my %default_deprecated_param_names = (
47             'corpus' => 'corpora',
48             'includeTeamDriveItems' => 'includeItemsFromAllDrives',
49             'supportsTeamDrives' => 'supportsAllDrives',
50             'teamDriveId' => 'driveId',
51             );
52              
53             ###########################################
54             ###########################################
55             my ( $class, %options ) = @_;
56             return $class->SUPER::new(
57 8     8 1 731 %options,
58 8         94 'api_base_url' => 'https://www.googleapis.com/drive/v3/',
59             'api_upload_url' => 'https://www.googleapis.com/upload/drive/v3/files',
60              
61             # to make sure api_test() works:
62             'api_file_url' => 'https://www.googleapis.com/drive/v3/files',
63             );
64             }
65              
66             ###########################################
67             ###########################################
68             my ( $self, $method, $param_data, $param_values ) = @_;
69              
70             my %validation_types = (
71 37     37   23152 TYPE_STRING() => sub { defined and length },
72             TYPE_INTEGER() => sub { defined and m{^[0-9]+$}xms },
73             TYPE_LONG() => sub { defined and m{^[0-9]+$}xms },
74 5 100   5   27 TYPE_BOOLEAN() => sub { defined and m{^[01]$}xms },
75 8 100   8   93 TYPE_OBJECT() => sub { ref eq 'HASH' },
76 4 100   4   35 TYPE_BYTES() => sub { defined and length },
77 6 100   6   81 );
78 7     7   33  
79 3 100   3   19 foreach my $param_name ( sort keys %{$param_values} ) {
80 37         285 if ( !exists $param_data->{$param_name} ) {
81             LOGDIE("[$method] Parameter name '$param_name' does not exist");
82 37         55 }
  37         110  
83 35 100       88 }
84 1         7  
85             foreach my $param_name ( sort keys %{$param_data} ) {
86             my ( $param_type, $is_required ) = @{ $param_data->{$param_name} };
87             my $param_value = $param_values->{$param_name};
88 36         58  
  36         93  
89 36         55 # You did not provide a parameter that is needed
  36         64  
90 36         62 if ( !exists $param_values->{$param_name} ) {
91             $is_required
92             and LOGDIE("[$method] Parameter '$param_name' is required");
93 36 100       67  
94 2 100       9 next;
95             }
96              
97 1         2 my $validation_cb = $validation_types{$param_type};
98             if ( !$validation_cb ) {
99             LOGDIE("[$method] Parameter type '$param_type' does not exist");
100 34         52 }
101 34 100       66  
102 1         9 local $_ = $param_value;
103             my $success = $validation_cb->()
104             or LOGDIE("[$method] Parameter type '$param_name' does not validate as '$param_type'");
105 33         52 }
106 33 100       56  
107             return 1;
108             }
109              
110 14         85 ###########################################
111             ###########################################
112             my ( $self, $method, $options ) = @_;
113              
114             if ( my $perm_for_view = $options->{'includePermissionsForView'} ) {
115             $perm_for_view eq 'published'
116 21     21   14189 or LOGDIE("[$method] Parameter 'includePermissionsForView' must be: published");
117             }
118 21 100       50  
119 2 100       9 my $page_size = $options->{'pageSize'};
120             if ( defined $page_size ) {
121             $page_size >= 1 && $page_size <= 1_000
122             or LOGDIE("[$method] Parameter 'pageSize' must be: 1 to 1000");
123 20         30 }
124 20 100       41  
125 8 100 100     34 if ( my $upload_type = $options->{'uploadType'} ) {
126             $upload_type =~ /^( media | multipart | resumable )$/xms
127             or LOGDIE("[$method] Parameter 'uploadType' must be: media|multipart|resumable");
128             }
129 16 100       35  
130 6 100       32 return 1;
131             }
132              
133             ###########################################
134 13         27 ###########################################
135             my ( $self, $path, $options ) = @_;
136             my $uri = URI->new( $path =~ /^http/xms ? $path : $self->{'api_base_url'} . $path );
137              
138             $options && %{$options}
139             and $uri->query_form($options);
140 7     7   7296  
141 7 100       75 return $uri;
142             }
143 7 100 100     13794  
  5         33  
144             ###########################################
145             ###########################################
146 7         398 my ( $self, $method, $info, $options ) = @_;
147              
148             foreach my $dep_name ( sort keys %{$options} ) {
149             my $alt = $info->{'deprecated_param_names'}{$dep_name}
150             || $default_deprecated_param_names{$dep_name};
151              
152 27     27   16999 if ($alt) {
153             WARN("[$method] Parameter name '$dep_name' is deprecated, use '$alt' instead");
154 27         38 }
  27         69  
155             }
156 26   100     81  
157             return;
158 26 100       53 }
159 13         43  
160             ###########################################
161             ###########################################
162             my ( $self, $options, $body_param_names ) = @_;
163 27         205  
164             my $body_options = {
165             map +( exists $options->{$_} ? ( $_ => delete $options->{$_} ) : () ),
166             @{$body_param_names},
167             };
168              
169 6     6   6420 keys %{$body_options} == 0
170             and return;
171              
172             return $body_options;
173 6 50       11 }
  6         27  
174              
175             ###########################################
176 6 100       13 ###########################################
  6         27  
177             my ( $self, $info, $options ) = @_;
178             my $method = $info->{'method_name'};
179 3         48  
180             # We yank out all the body parameters so we don't validate them
181             # We reuse the same key to store the key + value this time (instead of which keys to use in options)
182             # TODO: Support body parameter validation
183             my $body_parameters = delete $info->{'body_parameters'};
184             $info->{'body_parameters'} //= $self->_prepare_body_options( $options, $body_parameters );
185 5     5   22139  
186 5         10 # We validate the options left
187             $self->_validate_param_type( $method, $info->{'query_parameters'}, $options );
188              
189             # We might have a more complicated type checking specified
190             if ( my $param_check = $info->{'parameter_checks'} ) {
191 5         9 foreach my $name ( sort keys %{$param_check} ) {
192 5   66     33 defined $options->{$name}
193             or next;
194              
195 5         19 my $cb = $param_check->{$name};
196             ref $cb eq 'CODE'
197             or LOGDIE("[$method] Parameter '$name' missing validation callback");
198 5 100       16  
199 1         2 local $_ = $options->{$name};
  1         5  
200 3 100       8 my $error_str = $cb->();
201             $error_str
202             and LOGDIE("[$method] Parameter '$name' failed validation: $error_str");
203 2         14 }
204 2 50       8 }
205              
206             # We check for deprecated parameters (from a list of known deprecated parameters)
207 2         5 $self->_handle_deprecated_params( $method, $info, $options );
208 2         6  
209 2 100       935 # We handle some more specific validation rules (from a list of known parameters)
210             $self->_handle_complex_types( $method, $options );
211              
212             $self->init();
213              
214             # We generate the URI path
215 4         19 my $uri = $self->_generate_uri( $info->{'path'}, $options );
216             my $req = $self->_generate_request( $uri, $info );
217              
218 4         13 if ( $info->{'return_http_request'} ) {
219             return $req;
220 4         14 }
221              
222             return $self->_make_request( $req, $info->{'return_http_response'} );
223 4         40 }
224 4         20  
225             # --- about
226 4 50       11  
227 0         0 ###########################################
228             ###########################################
229             my ( $self, $options ) = @_;
230 4         15  
231             ref $options eq 'HASH'
232             or LOGDIE('about() missing parameters');
233              
234             my $info = {
235             'query_parameters' => {
236             'fields' => [ TYPE_STRING(), 1 ],
237             },
238 0     0 1   'path' => 'about',
239             'method_name' => 'about',
240 0 0         'http_method' => HTTP_METHOD_GET(),
241             };
242              
243 0           return $self->_handle_api_method( $info, $options );
244             }
245              
246             # --- changes
247              
248             ###########################################
249             ###########################################
250             my ( $self, $options ) = @_;
251              
252 0           $options //= {};
253              
254             my $info = {
255             'query_parameters' => {
256             'driveId' => [ TYPE_STRING(), 0 ],
257             'fields' => [ TYPE_STRING(), 0 ],
258             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
259             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ], # Deprecated
260 0     0 1   'teamDriveId' => [ TYPE_STRING(), 0 ], # Deprecated
261             },
262 0   0        
263             'path' => 'changes/startPageToken',
264 0           'http_method' => HTTP_METHOD_GET(),
265             'method_name' => 'getStartPageToken',
266             };
267              
268             return $self->_handle_api_method( $info, $options );
269             }
270              
271             ###########################################
272             ###########################################
273             my ( $self, $options ) = @_;
274              
275             ref $options eq 'HASH'
276             or LOGDIE('changes() missing parameters');
277              
278 0           my $info = {
279             'query_parameters' => {
280             'pageToken' => [ TYPE_STRING(), 1 ],
281             'driveId' => [ TYPE_STRING(), 0 ],
282             'fields' => [ TYPE_STRING(), 0 ],
283             'includeCorpusRemovals' => [ TYPE_BOOLEAN(), 0 ],
284 0     0 1   'includeItemsFromAllDrives' => [ TYPE_BOOLEAN(), 0 ],
285             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
286 0 0         'includeRemoved' => [ TYPE_BOOLEAN(), 0 ],
287             'includeTeamDriveItems' => [ TYPE_BOOLEAN(), 0 ],
288             'pageSize' => [ TYPE_INTEGER(), 0 ],
289             'restrictToMyDrive' => [ TYPE_BOOLEAN(), 0 ],
290             'spaces' => [ TYPE_STRING(), 0 ],
291             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
292             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
293             'teamDriveId' => [ TYPE_STRING(), 0 ],
294             },
295              
296             'parameter_checks' => {
297             'spaces' => sub {
298             /^( drive | appDataFolder | photos )$/xms
299             or return 'must be: drive|appDataFolder|photos';
300              
301             return 0;
302             },
303             },
304              
305             'path' => 'changes',
306             'http_method' => HTTP_METHOD_GET(),
307             'method_name' => 'changes',
308             };
309 0 0   0      
310             return $self->_handle_api_method( $info, $options );
311             }
312 0            
313             ###########################################
314             ###########################################
315             my ( $self, $options ) = @_;
316 0            
317             $options //= {};
318              
319             my $info = {
320             'query_parameters' => {
321 0           'fields' => [ TYPE_STRING(), 0 ],
322             },
323              
324             'body_parameters' => [
325             qw<
326             kind
327 0     0 1   id
328             resourceId
329 0   0       resourceUri
330             token
331 0           expiration
332             type
333             address
334             payload
335             params
336             >
337             ],
338              
339             'path' => 'changes/watch',
340             'http_method' => HTTP_METHOD_POST(),
341             'method_name' => 'watch_changes',
342             };
343              
344             $options->{'kind'} = 'api#channel';
345              
346             return $self->_handle_api_method( $info, $options );
347             }
348              
349             # --- channels
350              
351             ###########################################
352             ###########################################
353             my ( $self, $options ) = @_;
354              
355             ref $options eq 'HASH'
356 0           or LOGDIE('stop_channels() missing parameters');
357              
358 0           my $info = {
359             'body_parameters' => [
360             qw<
361             kind
362             id
363             resourceId
364             resourceUri
365             token
366 0     0 1   expiration
367             type
368 0 0         address
369             payload
370             params
371             >
372             ],
373              
374             'parameter_checks' => {
375             'type' => sub {
376             m{^web_?hook$}xms
377             or return 'must be: webhook|web_hook';
378              
379             return 0;
380             },
381             },
382              
383             'path' => 'channels/stop',
384             'http_method' => HTTP_METHOD_POST(),
385             'method_name' => 'stop_channels',
386             };
387              
388             $options->{'kind'} = 'api#channel';
389 0 0   0      
390             return $self->_handle_api_method( $info, $options );
391             }
392 0            
393             # --- comments
394              
395             ###########################################
396 0           ###########################################
397             my ( $self, $fileId, $options ) = @_;
398              
399             defined $fileId && length $fileId
400             or LOGDIE('create_comment() missing file ID');
401 0            
402             ref $options eq 'HASH'
403 0           or LOGDIE('create_comment() missing parameters');
404              
405             my $info = {
406             'query_parameters' => {
407             'fields' => [ TYPE_STRING(), 1 ],
408             },
409              
410             'body_parameters' => [
411 0     0 1   qw<
412             content
413 0 0 0       anchor
414             quotedFileContent
415             >
416 0 0         ],
417              
418             'path' => "files/$fileId/comments",
419 0           'method_name' => 'create_comment',
420             'http_method' => HTTP_METHOD_POST(),
421             };
422              
423             return $self->_handle_api_method( $info, $options );
424             }
425              
426             ###########################################
427             ###########################################
428             my ( $self, $fileId, $commentId ) = @_;
429              
430             defined $fileId && length $fileId
431             or LOGDIE('create_comment() missing file ID');
432              
433             defined $commentId && length $commentId
434             or LOGDIE('create_comment() missing comment ID');
435              
436             my $info = {
437 0           'path' => "files/$fileId/comments/$commentId",
438             'method_name' => 'delete_comment',
439             'http_method' => HTTP_METHOD_DELETE(),
440             };
441              
442             return $self->_handle_api_method( $info, {} );
443 0     0 1   }
444              
445 0 0 0       ###########################################
446             ###########################################
447             my ( $self, $fileId, $commentId, $options ) = @_;
448 0 0 0        
449             defined $fileId && length $fileId
450             or LOGDIE('get_comment() missing file ID');
451 0            
452             defined $commentId && length $commentId
453             or LOGDIE('get_comment() missing comment ID');
454              
455             ref $options eq 'HASH'
456             or LOGDIE('get_comment() missing parameters');
457 0            
458             my $info = {
459             'query_parameters' => {
460             'fields' => [ TYPE_STRING(), 1 ],
461             'includeDeleted' => [ TYPE_BOOLEAN(), 0 ],
462             },
463 0     0 1    
464             'path' => "files/$fileId/comments/$commentId",
465 0 0 0       'method_name' => 'get_comment',
466             'http_method' => HTTP_METHOD_GET(),
467             };
468 0 0 0        
469             return $self->_handle_api_method( $info, $options );
470             }
471 0 0          
472             ###########################################
473             ###########################################
474 0           my ( $self, $fileId, $options ) = @_;
475              
476             defined $fileId && length $fileId
477             or LOGDIE('comments() missing file ID');
478              
479             ref $options eq 'HASH'
480             or LOGDIE('comments() missing parameters');
481              
482             my $info = {
483             'query_parameters' => {
484             'fields' => [ TYPE_STRING(), 1 ],
485 0           'includeDeleted' => [ TYPE_BOOLEAN(), 0 ],
486             'pageSize' => [ TYPE_INTEGER(), 0 ],
487             'pageToken' => [ TYPE_STRING(), 0 ],
488             'startModifiedTime' => [ TYPE_STRING(), 0 ],
489             },
490              
491 0     0 1   'path' => "files/$fileId/comments",
492             'method_name' => 'comments',
493 0 0 0       'http_method' => HTTP_METHOD_GET(),
494             };
495              
496 0 0         return $self->_handle_api_method( $info, $options );
497             }
498              
499 0           ###########################################
500             ###########################################
501             my ( $self, $fileId, $commentId, $options ) = @_;
502              
503             defined $fileId && length $fileId
504             or LOGDIE('update_comment() missing file ID');
505              
506             defined $commentId && length $commentId
507             or LOGDIE('update_comment() missing comment ID');
508              
509             ref $options eq 'HASH'
510             or LOGDIE('update_comment() missing parameters');
511              
512             my $info = {
513 0           'query_parameters' => {
514             'fields' => [ TYPE_STRING(), 1 ],
515             },
516              
517             'body_parameters' => [
518             qw<
519 0     0 1   content
520             >
521 0 0 0       ],
522              
523             'path' => "files/$fileId/comments/$commentId",
524 0 0 0       'method_name' => 'update_comment',
525             'http_method' => HTTP_METHOD_PATCH(),
526             };
527 0 0          
528             return $self->_handle_api_method( $info, $options );
529             }
530 0            
531             # --- files
532              
533             ###########################################
534             ###########################################
535             my ( $self, $fileId, $options ) = @_;
536              
537             defined $fileId && length $fileId
538             or LOGDIE('copy_file() missing file ID');
539              
540             ref $options eq 'HASH'
541             or LOGDIE('copy_file() missing parameters');
542              
543             # TODO: ocrLanguage is ISO 639-1 code
544              
545             my $info = {
546 0           'query_parameters' => {
547             'fields' => [ TYPE_STRING(), 0 ],
548             'ignoreDefaultVisibility' => [ TYPE_BOOLEAN(), 0 ],
549             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
550             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
551             'ocrLanguage' => [ TYPE_STRING(), 0 ],
552             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
553             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
554 0     0 1   },
555              
556 0 0 0       'body_parameters' => [
557             qw<
558             appProperties
559 0 0         contentHints
560             contentRestrictions
561             copyRequiresWriterPermission
562             description
563             id
564 0           mimeType
565             modifiedTime
566             name
567             parents
568             properties
569             starred
570             viewedByMeTime
571             writersCanShare
572             >
573             ],
574              
575             'path' => "files/$fileId/copy",
576             'method_name' => 'copy_file',
577             'http_method' => HTTP_METHOD_POST(),
578             };
579              
580             return $self->_handle_api_method( $info, $options );
581             }
582              
583             # Helper
584             ###########################################
585             ###########################################
586             my ( $self, $name, $parent_id ) = @_;
587              
588             defined $name && length $name
589             or LOGDIE('create_folder() missing name');
590              
591             defined $parent_id && length $parent_id
592             or LOGDIE('create_folder() missing parent_id');
593              
594             return $self->create_file(
595             {
596             'name' => $name,
597             'mimeType' => "application/vnd.google-apps.folder",
598             'parents' => [$parent_id],
599 0           }
600             );
601             }
602              
603             # Metadata only
604             ###########################################
605             ###########################################
606 0     0 1   my ( $self, $options ) = @_;
607              
608 0 0 0       ref $options eq 'HASH'
609             or LOGDIE('create_file() missing parameters');
610              
611 0 0 0       my $info = {
612             'query_parameters' => {
613             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
614 0           'ignoreDefaultVisibility' => [ TYPE_BOOLEAN(), 0 ],
615             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
616             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
617             'ocrLanguage' => [ TYPE_STRING(), 0 ],
618             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
619             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
620             'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ]
621             },
622              
623             'body_parameters' => [
624             qw<
625             appProperties
626             contentHints
627 0     0 1   contentRestrictions
628             copyRequiresWriterPermission
629 0 0         createdTime
630             description
631             folderColorRgb
632 0           id
633             mimeType
634             modifiedTime
635             name
636             originalFilename
637             parents
638             properties
639             shortcutDetails.targetId
640             starred
641             viewedByMeTime
642             writersCanShare
643             >
644             ],
645              
646             'path' => 'files',
647             'method_name' => 'create_file',
648             'http_method' => HTTP_METHOD_POST(),
649             };
650              
651             if ( defined $options->{'enforceSingleParent'} ) {
652             LOGDIE("[$info->{'method_name'}] Creating files in multiple folders is no longer supported");
653             }
654              
655             return $self->_handle_api_method( $info, $options );
656             }
657              
658             # Uploading file (uploadType=media)
659             ###########################################
660             ###########################################
661             my ( $self, $file, $options ) = @_;
662              
663             defined $file && length $file
664             or LOGDIE('upload_media_file() missing file');
665              
666             -r $file
667             or LOGDIE("upload_media_file() received non-existent/unreadable file: $file");
668              
669             my $size = -s $file;
670             $size <= SIZE_5MB()
671             or LOGDIE("upload_media_file() has a limit of 5M, '$file' is bigger");
672 0 0          
673 0           $options //= {};
674             $options->{'uploadType'} = 'media';
675              
676 0           my $mimeType = delete $options->{'mimeType'} // $self->file_mime_type($file);
677              
678             my $info = {
679             'query_parameters' => {
680             'uploadType' => [ TYPE_STRING(), 1 ],
681             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
682             'ignoreDefaultVisibility' => [ TYPE_BOOLEAN(), 0 ],
683 0     0 1   'includePermissionsForView' => [ TYPE_STRING(), 0 ],
684             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
685 0 0 0       'ocrLanguage' => [ TYPE_STRING(), 0 ],
686             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
687             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
688 0 0         'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ]
689             },
690              
691 0           'path' => $self->{'api_upload_url'},
692 0 0         'method_name' => 'upload_media_file',
693             'http_method' => HTTP_METHOD_POST(),
694             'body_content' => $self->_content_sub($file),
695 0   0       'extra_headers' => [
696 0           'Content-Type' => $mimeType,
697             'Content-Length' => $size,
698 0   0       ],
699             };
700              
701             if ( defined $options->{'enforceSingleParent'} ) {
702             LOGDIE("[$info->{'method_name'}] Creating files in multiple folders is no longer supported");
703             }
704              
705             # Since a file upload can take a long time, refresh the token
706             # just in case.
707             $self->{'oauth'}->token_expire();
708              
709             return $self->_handle_api_method( $info, $options );
710             }
711              
712             ###########################################
713 0           ###########################################
714             my ( $self, $file, $options ) = @_;
715              
716             defined $file && length $file
717             or LOGDIE('upload_multipart_file() missing file');
718              
719             -r $file
720             or LOGDIE("upload_multipart_file() received non-existent/unreadable file: $file");
721              
722             my $size = -s $file;
723 0 0         $size <= SIZE_5MB()
724 0           or LOGDIE("upload_multipart_file() has a limit of 5M, '$file' is bigger");
725              
726             $options //= {};
727              
728             $options->{'name'} //= File::Basename::basename($file);
729 0           $options->{'mimeType'} //= $self->file_mime_type($file);
730             $options->{'uploadType'} = 'multipart';
731 0            
732             # TODO: Wouldn't it be great to support Chunking with a callback?
733             my $file_content;
734             {
735             open my $fh, '<', $file
736             or LOGDIE("File '$file' cannot be open for reading");
737 0     0 1    
738             undef $/;
739 0 0 0       $file_content = <$fh>;
740              
741             close $fh
742 0 0         or LOGDIE("File '$file' cannot be closed after reading");
743             }
744              
745 0           my $info = {
746 0 0         'query_parameters' => {
747             'uploadType' => [ TYPE_STRING(), 1 ],
748             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
749 0   0       'ignoreDefaultVisibility' => [ TYPE_BOOLEAN(), 0 ],
750             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
751 0   0       'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
752 0   0       'ocrLanguage' => [ TYPE_STRING(), 0 ],
753 0           'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
754             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
755             'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ]
756 0           },
757              
758 0 0         'body_parameters' => [
  0            
759             qw<
760             appProperties
761 0           contentHints
762 0           contentRestrictions
763             copyRequiresWriterPermission
764 0 0         createdTime
765             description
766             folderColorRgb
767             id
768             mimeType
769             modifiedTime
770             name
771             originalFilename
772             parents
773             properties
774             shortcutDetails.targetId
775             starred
776             viewedByMeTime
777             writersCanShare
778             >
779             ],
780              
781             'path' => $self->{'api_upload_url'},
782             'method_name' => 'upload_multipart_file',
783             'http_method' => HTTP_METHOD_POST(),
784             'multipart' => 1,
785             'body_content' => $file_content,
786             };
787              
788             if ( defined $options->{'enforceSingleParent'} ) {
789             LOGDIE("[$info->{'method_name'}] Creating files in multiple folders is no longer supported");
790             }
791              
792             # Since a file upload can take a long time, refresh the token
793             # just in case.
794             $self->{'oauth'}->token_expire();
795              
796             return $self->_handle_api_method( $info, $options );
797             }
798              
799             ###########################################
800             ###########################################
801             my ( $self, $file, $options ) = @_;
802              
803             defined $file && length $file
804 0           or LOGDIE('create_resumable_upload_for() missing file');
805              
806             -r $file
807             or LOGDIE("create_resumable_upload_for() received non-existent/unreadable file: $file");
808              
809             my $size = -s $file;
810             $size <= SIZE_5120GB()
811 0 0         or LOGDIE("create_resumavble_upload_for() has a limit of 5120G, '$file' is bigger");
812 0            
813             $options //= {};
814              
815             $options->{'name'} //= File::Basename::basename($file);
816             $options->{'mimeType'} //= $self->file_mime_type($file);
817 0           $options->{'uploadType'} = 'resumable';
818              
819 0           my @extra_headers = (
820             'X-Upload-Content-Type' => $options->{'mimeType'},
821             'X-Upload-Content-Length' => $size,
822             );
823              
824             # Do we have metadata other than uploadType?
825 0     0 1   if ( keys %{$options} > 1 ) {
826             push @extra_headers, 'Content-Type' => 'application/json; charset=UTF-8';
827 0 0 0       }
828              
829             my $info = {
830 0 0         'query_parameters' => {
831             'uploadType' => [ TYPE_STRING(), 1 ],
832             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
833 0           'ignoreDefaultVisibility' => [ TYPE_BOOLEAN(), 0 ],
834 0 0         'includePermissionsForView' => [ TYPE_STRING(), 0 ],
835             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
836             'ocrLanguage' => [ TYPE_STRING(), 0 ],
837 0   0       'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
838             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
839 0   0       'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ]
840 0   0       },
841 0            
842             'body_parameters' => [
843             qw<
844 0           appProperties
845             contentHints
846             contentRestrictions
847             copyRequiresWriterPermission
848             createdTime
849 0 0         description
  0            
850 0           folderColorRgb
851             id
852             mimeType
853             modifiedTime
854             name
855             originalFilename
856             parents
857             properties
858             shortcutDetails.targetId
859             starred
860             viewedByMeTime
861             writersCanShare
862             >
863             ],
864              
865             'path' => $self->{'api_upload_url'},
866             'method_name' => 'create_resumable_upload',
867             'http_method' => HTTP_METHOD_POST(),
868             'extra_headers' => \@extra_headers,
869             'resumable' => 1,
870             'return_http_response' => 1,
871             };
872              
873             if ( defined $options->{'enforceSingleParent'} ) {
874             LOGDIE("[$info->{'method_name'}] Creating files in multiple folders is no longer supported");
875             }
876              
877             # Since a file upload can take a long time, refresh the token
878             # just in case.
879             $self->{'oauth'}->token_expire();
880              
881             my $response = $self->_handle_api_method( $info, $options );
882             $response->is_success()
883             or return;
884              
885             my $location = $response->header('Location');
886             return $location || '';
887             }
888              
889 0           ###########################################
890             ###########################################
891             my ( $self, $options ) = @_;
892              
893             $options //= {};
894             $options->{'uploadType'} = 'resumable';
895              
896             my @extra_headers;
897 0 0         if ( my $mimeType = delete $options->{'mediaType'} ) {
898 0           push @extra_headers, 'X-Upload-Content-Type' => $mimeType;
899             }
900              
901             # Do we have metadata other than uploadType?
902             if ( keys %{$options} > 1 ) {
903 0           push @extra_headers, 'Content-Type' => 'application/json; charset=UTF-8';
904             }
905 0            
906 0 0         my $info = {
907             'query_parameters' => {
908             'uploadType' => [ TYPE_STRING(), 1 ],
909 0           'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
910 0   0       'ignoreDefaultVisibility' => [ TYPE_BOOLEAN(), 0 ],
911             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
912             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
913             'ocrLanguage' => [ TYPE_STRING(), 0 ],
914             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
915             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
916 0     0 1   'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ]
917             },
918 0   0        
919 0           'body_parameters' => [
920             qw<
921 0           appProperties
922 0 0         contentHints
923 0           contentRestrictions
924             copyRequiresWriterPermission
925             createdTime
926             description
927 0 0         folderColorRgb
  0            
928 0           id
929             mimeType
930             modifiedTime
931             name
932             originalFilename
933             parents
934             properties
935             shortcutDetails.targetId
936             starred
937             viewedByMeTime
938             writersCanShare
939             >
940             ],
941              
942             'path' => $self->{'api_upload_url'},
943             'method_name' => 'create_resumable_upload',
944             'http_method' => HTTP_METHOD_POST(),
945             'extra_headers' => \@extra_headers,
946             'resumable' => 1,
947             'return_http_response' => 1,
948             };
949              
950             if ( defined $options->{'enforceSingleParent'} ) {
951             LOGDIE("[$info->{'method_name'}] Creating files in multiple folders is no longer supported");
952             }
953              
954             # Since a file upload can take a long time, refresh the token
955             # just in case.
956             $self->{'oauth'}->token_expire();
957              
958             my $response = $self->_handle_api_method( $info, $options );
959             $response->is_success()
960             or return;
961              
962             my $location = $response->header('Location');
963             return $location || '';
964             }
965              
966             ###########################################
967 0           ###########################################
968             my ( $self, $upload_uri, $file ) = @_;
969              
970             defined $upload_uri && length $upload_uri
971             or LOGDIE('upload_file_content_single() missing upload_uri');
972              
973             $upload_uri =~ m{^https://.*\bupload_id=.+}xmsi
974             or LOGDIE('upload_file_content_single() upload_uri seems malformed');
975 0 0          
976 0           defined $file && length $file
977             or LOGDIE('upload_file_content_single() missing file');
978              
979             -r $file
980             or LOGDIE("upload_file_content_single() received non-existent/unreadable file: $file");
981 0            
982             my $size = -s $file;
983 0           $size <= SIZE_5120GB()
984 0 0         or LOGDIE("upload_file_content_single() has a limit of 5120G, '$file' is bigger");
985              
986             my $info = {
987 0           'path' => $upload_uri,
988 0   0       'method_name' => 'upload_file_content_single',
989             'http_method' => HTTP_METHOD_PUT(),
990             'body_content' => $self->_content_sub($file),
991             };
992              
993             # Since a file upload can take a long time, refresh the token
994 0     0 1   # just in case.
995             $self->{'oauth'}->token_expire();
996 0 0 0        
997             return $self->_handle_api_method( $info, {} );
998             }
999 0 0          
1000             ###########################################
1001             ###########################################
1002 0 0 0       my ( $self, $upload_uri, $file, $chunk_size ) = @_;
1003              
1004             defined $upload_uri && length $upload_uri
1005 0 0         or LOGDIE('upload_file_content_multiple() missing upload_uri');
1006              
1007             $upload_uri =~ m{^https://.*upload_id=.+}xms
1008 0           or LOGDIE('upload_file_content_multiple() upload_uri seems malformed');
1009 0 0          
1010             defined $file && length $file
1011             or LOGDIE('upload_file_content_multiple() missing file');
1012 0            
1013             -r $file
1014             or LOGDIE("upload_file_content_multiple() received non-existent/unreadable file: $file");
1015              
1016             my $size = -s $file;
1017             $size <= SIZE_5120GB()
1018             or LOGDIE("upload_file_content_multiple() has a limit of 5120G, '$file' is bigger");
1019              
1020             # By upload in 10 MB chunks
1021 0           # But you can provide the amount of bytes instead
1022             $chunk_size //= DEF_CHUNK_SIZE();
1023 0            
1024             $chunk_size > 0
1025             or LOGDIE('upload_file_content_multiple() must have a chunk size above 0');
1026              
1027             $chunk_size % SIZE_256K() == 0
1028             or LOGDIE('upload_file_content_multiple() chunk size must divide by 256K');
1029 0     0 1    
1030             my $iter = $self->upload_file_content_iterator( $upload_uri, $file, $chunk_size );
1031 0 0 0       while ( my $request = $iter->() ) {
1032             my $response = $self->_make_request( $request, 1 );
1033              
1034 0 0         # 200 - means we're done
1035             # 308 - means continue
1036             # anything else - we're confused, so it's an error no matter what
1037 0 0 0        
1038             if ( $response->code() == Net::Google::Drive::Simple::Core::HTTP_CODE_OK() ) {
1039             return from_json( $response->decoded_content() );
1040 0 0         }
1041              
1042             if ( $response->code() != Net::Google::Drive::Simple::Core::HTTP_CODE_RESUME() ) {
1043 0           LOGDIE( "Triggered error: " . $response->code() );
1044 0 0         }
1045             }
1046              
1047             return;
1048             }
1049 0   0        
1050             ###########################################
1051 0 0         ###########################################
1052             my ( $self, $upload_uri, $file, $chunk_size ) = @_;
1053              
1054 0 0         defined $upload_uri && length $upload_uri
1055             or LOGDIE('upload_file_content_multiple() missing upload_uri');
1056              
1057 0           $upload_uri =~ m{^https://.*upload_id=.+}xms
1058 0           or LOGDIE('upload_file_content_multiple() upload_uri seems malformed');
1059 0            
1060             defined $file && length $file
1061             or LOGDIE('upload_file_content_multiple() missing file');
1062              
1063             -r $file
1064             or LOGDIE("upload_file_content_multiple() received non-existent/unreadable file: $file");
1065 0 0          
1066 0           my $size = -s $file;
1067             $size <= SIZE_5120GB()
1068             or LOGDIE("upload_file_content_multiple() has a limit of 5120G, '$file' is bigger");
1069 0 0          
1070 0           # By upload in 10 MB chunks
1071             # But you can provide the amount of bytes instead
1072             $chunk_size //= DEF_CHUNK_SIZE();
1073              
1074 0           $chunk_size > 0
1075             or LOGDIE('upload_file_content_multiple() must have a chunk size above 0');
1076              
1077             $chunk_size % SIZE_256K() == 0
1078             or LOGDIE('upload_file_content_multiple() chunk size must divide by 256K');
1079              
1080 0     0 1   # How many chunks are we going to iterate over
1081             # size in bytes divided by 256K (chunk size)
1082 0 0 0       my $chunks = ( $size / $chunk_size );
1083              
1084             # One more if there's a tail
1085 0 0         $size % $chunk_size
1086             and $chunks++;
1087              
1088 0 0 0       my $position = 0;
1089             my $iter = sub {
1090             $chunks-- == 0
1091 0 0         and return;
1092              
1093             my $start_position = $position;
1094 0            
1095 0 0         # TODO: Should we take the approach of _content_sub with opening usnig IO::File?
1096             open my $fh, '<', $file
1097             or LOGDIE("File '$file' cannot be open for reading");
1098              
1099             my $content;
1100 0   0       sysseek $fh, $start_position, 0;
1101             my $bytes_read = sysread $fh, $content, $chunk_size;
1102 0 0         $position += $bytes_read;
1103              
1104             close $fh
1105 0 0         or LOGDIE("File '$file' cannot be closed after reading");
1106              
1107             my $info = {
1108             'path' => $upload_uri,
1109             'method_name' => 'upload_file_content_multiple',
1110 0           'http_method' => HTTP_METHOD_PUT(),
1111             'return_http_request' => 1,
1112             'body_content' => $content,
1113 0 0         'extra_headers' => [
1114             'Content-Length' => $bytes_read,
1115             'Content-Range' => "bytes $start_position-" . ( $position - 1 ) . "/$size" #. ( $position + $bytes_read ),
1116 0           ],
1117             };
1118 0 0   0      
1119             # Since a file upload can take a long time, refresh the token
1120             # just in case.
1121 0           $self->{'oauth'}->token_expire();
1122              
1123             my $request = $self->_handle_api_method( $info, {} );
1124 0 0         return $request;
1125             };
1126              
1127 0           return $iter;
1128 0           }
1129 0            
1130 0           ###########################################
1131             ###########################################
1132 0 0         my ( $self, $file, $options ) = @_;
1133             my $upload_uri = $self->create_resumable_upload_for( $file, $options );
1134             return $self->upload_file_content_single( $upload_uri, $file );
1135 0           }
1136              
1137             ###########################################
1138             ###########################################
1139             my ( $self, $fileId, $options ) = @_;
1140              
1141             defined $fileId && length $fileId
1142             or LOGDIE('delete_file() missing file ID');
1143              
1144             $options //= {};
1145              
1146             my $info = {
1147             'query_parameters' => {
1148             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
1149 0           'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1150             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1151 0           },
1152 0            
1153 0           'path' => "files/$fileId",
1154             'method_name' => 'delete_file',
1155 0           'http_method' => HTTP_METHOD_DELETE(),
1156             };
1157              
1158             if ( defined $options->{'enforceSingleParent'} ) {
1159             LOGDIE("[$info->{'method_name'}] If an item is not in a shared drive and its last parent is deleted but the item itself is not, the item will be placed under its owner's root");
1160             }
1161 0     0 1    
1162 0           return $self->_handle_api_method( $info, $options );
1163 0           }
1164              
1165             ###########################################
1166             ###########################################
1167             my ( $self, $fileId, $options ) = @_;
1168              
1169 0     0 1   defined $fileId && length $fileId
1170             or LOGDIE('export_file() missing file ID');
1171 0 0 0        
1172             ref $options eq 'HASH'
1173             or LOGDIE('export_file() missing parameters');
1174 0   0        
1175             my $info = {
1176 0           'query_parameters' => {
1177             'mimeType' => [ TYPE_STRING(), 1 ],
1178             'fields' => [ TYPE_STRING(), 0 ],
1179             },
1180              
1181             'path' => "files/$fileId/export",
1182             'method_name' => 'export_file',
1183             'http_method' => HTTP_METHOD_GET(),
1184             };
1185              
1186             return $self->_handle_api_method( $info, $options );
1187             }
1188 0 0          
1189 0           ###########################################
1190             ###########################################
1191             my ( $self, $options ) = @_;
1192 0            
1193             $options //= {};
1194              
1195             my $info = {
1196             'query_parameters' => {
1197             'count' => [ TYPE_INTEGER(), 0 ],
1198 0     0 1   'fields' => [ TYPE_STRING(), 0 ],
1199             'space' => [ TYPE_STRING(), 0 ],
1200 0 0 0       'type' => [ TYPE_STRING(), 0 ],
1201             },
1202              
1203 0 0         'parameter_checks' => {
1204             'spaces' => sub {
1205             /^( files | shortcuts )$/xms
1206 0           or return 'must be: files|shortcuts';
1207              
1208             return 0;
1209             }
1210             },
1211              
1212             'path' => 'files/generateIds',
1213             'method_name' => 'generateIds',
1214             'http_method' => HTTP_METHOD_GET(),
1215             };
1216              
1217 0           return $self->_handle_api_method( $info, $options );
1218             }
1219              
1220             ###########################################
1221             ###########################################
1222             my ( $self, $fileId, $options ) = @_;
1223 0     0 1    
1224             defined $fileId && length $fileId
1225 0   0       or LOGDIE('get_file() missing file ID');
1226              
1227             $options //= {};
1228              
1229             my $info = {
1230             'query_parameters' => {
1231             'alt' => [ TYPE_STRING(), 0 ],
1232             'acknowledgeAbuse' => [ TYPE_BOOLEAN(), 0 ],
1233             'fields' => [ TYPE_STRING(), 0 ],
1234             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
1235             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1236             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1237 0 0   0     },
1238              
1239             'parameter_checks' => {
1240 0           'alt' => sub {
1241             $_ eq 'media'
1242             or return 'must be: media';
1243              
1244 0           return 0;
1245             },
1246             },
1247              
1248             'path' => "files/$fileId",
1249 0           'method_name' => 'get_file',
1250             'http_method' => HTTP_METHOD_GET(),
1251             };
1252              
1253             if ( $options->{'alt'} eq 'media' ) {
1254             $info->{'return_http_response'} = 1;
1255 0     0 1   }
1256              
1257 0 0 0       my $response = $self->_handle_api_method( $info, $options );
1258             return $response->decoded_content();
1259             }
1260 0   0        
1261             ###########################################
1262             ###########################################
1263             my ( $self, $options ) = @_;
1264              
1265             $options //= {};
1266              
1267             # TODO: orderBy
1268             # 'createdTime', 'folder', 'modifiedByMeTime', 'modifiedTime', 'name', 'name_natural', 'quotaBytesUsed', 'recency', 'sharedWithMeTime', 'starred', and 'viewedByMeTime'.
1269             # ?orderBy=folder,modifiedTime desc,name
1270              
1271             # TODO: Steal the struct to query syntax from MetaCPAN::Client
1272             # https://developers.google.com/drive/api/guides/search-files
1273             #if ( my $query_str = $options->{'q'} ) {...}
1274 0 0   0      
1275             my $info = {
1276             'query_parameters' => {
1277 0           'corpora' => [ TYPE_STRING(), 0 ],
1278             'corpus' => [ TYPE_STRING(), 0 ], # deprecated
1279             'driveId' => [ TYPE_STRING(), 0 ],
1280             'fields' => [ TYPE_STRING(), 0 ],
1281 0           'includeItemsFromAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1282             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
1283             'includeTeamDriveItems' => [ TYPE_BOOLEAN(), 0 ], # deprecated
1284             'orderBy' => [ TYPE_STRING(), 0 ],
1285             'pageSize' => [ TYPE_INTEGER(), 0 ],
1286 0 0         'pageToken' => [ TYPE_STRING(), 0 ],
1287 0           'q' => [ TYPE_STRING(), 0 ],
1288             'spaces' => [ TYPE_STRING(), 0 ],
1289             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1290 0           'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ], # deprecated
1291 0           'teamDriveId' => [ TYPE_STRING(), 0 ], # deprecated
1292             'trashed' => [ TYPE_BOOLEAN(), 0 ], # not documented
1293             },
1294              
1295             'parameter_checks' => {
1296             'corpora' => sub {
1297 0     0 1   /^( user | drive | domain | allDrives )$/xms
1298             or return 'must be: user|drive|domain|allDrives';
1299 0   0        
1300             if ( $_ eq 'drive' ) {
1301             defined $options->{'driveId'}
1302             or return 'if corpora is drive, parameter driveId must be set';
1303             }
1304              
1305             return 0;
1306             },
1307              
1308             'corpus' => sub {
1309             /^( domain | user )$/xms
1310             or return 'must be: domain|user';
1311              
1312             return 0;
1313             },
1314              
1315             'spaces' => sub {
1316             /^( drive | appDataFolder )$/xms
1317             or return 'must be: drive|appDataFolder';
1318              
1319             return 0;
1320             },
1321             },
1322              
1323             'path' => 'files',
1324             'method_name' => 'files',
1325             'http_method' => HTTP_METHOD_GET(),
1326             };
1327              
1328             return $self->_handle_api_method( $info, $options );
1329             }
1330              
1331 0 0   0     # Update with upload
1332             ###########################################
1333             ###########################################
1334 0 0         my ( $self, $fileId, $options ) = @_;
1335 0 0          
1336             defined $fileId && length $fileId
1337             or LOGDIE('update_file() missing file ID');
1338              
1339 0           ref $options eq 'HASH'
1340             or LOGDIE('update_file() missing parameters');
1341              
1342             my $info = {
1343 0 0   0     'query_parameters' => {
1344             'uploadType' => [ TYPE_STRING(), 1 ],
1345             'addParents' => [ TYPE_STRING(), 0 ],
1346 0           'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
1347             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
1348             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
1349             'ocrLanguage' => [ TYPE_STRING(), 0 ],
1350 0 0   0     'removeParents' => [ TYPE_STRING(), 0 ],
1351             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1352             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1353 0           'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ],
1354             },
1355              
1356             'body_parameters' => [
1357 0           qw<
1358             appProperties
1359             contentHints
1360             contentRestrictions
1361             copyRequiresWriterPermission
1362 0           description
1363             folderColorRgb
1364             mimeType
1365             modifiedTime
1366             name
1367             originalFilename
1368             properties
1369 0     0 1   starred
1370             trashed
1371 0 0 0       viewedByMeTime
1372             writersCanShare
1373             >
1374 0 0         ],
1375              
1376             'path' => $self->{'api_upload_file'} . "/$fileId",
1377             'method_name' => 'update_file',
1378             'http_method' => HTTP_METHOD_PATCH(),
1379             };
1380              
1381             if ( defined $options->{'enforceSingleParent'} ) {
1382             LOGDIE("[$info->{'method_name'}] Adding files to multiple folders is no longer supported. Use shortcuts instead");
1383             }
1384              
1385             return $self->_handle_api_method( $info, $options );
1386             }
1387              
1388             # Metadata
1389             ###########################################
1390             ###########################################
1391             my ( $self, $fileId, $options ) = @_;
1392              
1393             defined $fileId && length $fileId
1394             or LOGDIE('update_file_metadata() missing file ID');
1395              
1396             ref $options eq 'HASH'
1397             or LOGDIE('update_file_metadata() missing parameters');
1398              
1399             my $info = {
1400             'query_parameters' => {
1401             'addParents' => [ TYPE_STRING(), 0 ],
1402             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
1403             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
1404             'keepRevisionForever' => [ TYPE_BOOLEAN(), 0 ],
1405             'ocrLanguage' => [ TYPE_STRING(), 0 ],
1406             'removeParents' => [ TYPE_STRING(), 0 ],
1407             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1408             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1409             'useContentAsIndexableText' => [ TYPE_BOOLEAN(), 0 ],
1410             },
1411 0            
1412             'body_parameters' => [
1413             qw<
1414             appProperties
1415             contentHints
1416 0 0         contentRestrictions
1417 0           copyRequiresWriterPermission
1418             description
1419             folderColorRgb
1420 0           mimeType
1421             modifiedTime
1422             name
1423             originalFilename
1424             properties
1425             starred
1426             trashed
1427 0     0 1   viewedByMeTime
1428             writersCanShare
1429 0 0 0       >
1430             ],
1431              
1432 0 0         'path' => "files/$fileId",
1433             'method_name' => 'update_file_metadata',
1434             'http_method' => HTTP_METHOD_PATCH(),
1435 0           };
1436              
1437             if ( defined $options->{'enforceSingleParent'} ) {
1438             LOGDIE("[$info->{'method_name'}] Adding files to multiple folders is no longer supported. Use shortcuts instead");
1439             }
1440              
1441             return $self->_handle_api_method( $info, $options );
1442             }
1443              
1444             ###########################################
1445             ###########################################
1446             my ( $self, $fileId, $options ) = @_;
1447              
1448             defined $fileId && length $fileId
1449             or LOGDIE('watch_file() missing file ID');
1450              
1451             ref $options eq 'HASH'
1452             or LOGDIE('watch_file() missing parameters');
1453              
1454             my $info = {
1455             'query_parameters' => {
1456             'acknowledgeAbuse' => [ TYPE_BOOLEAN(), 0 ],
1457             'fields' => [ TYPE_STRING(), 0 ],
1458             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1459             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1460             },
1461              
1462             'body_parameters' => [
1463             qw<
1464             kind
1465             id
1466             resourceId
1467             resourceUri
1468             token
1469             expiration
1470             type
1471             address
1472             payload
1473 0 0         params
1474 0           >
1475             ],
1476              
1477 0           'path' => "files/$fileId/watch",
1478             'method_name' => 'watch_file',
1479             'http_method' => HTTP_METHOD_POST(),
1480             };
1481              
1482             $options->{'kind'} = 'api#channel';
1483 0     0 1    
1484             return $self->_handle_api_method( $info, $options );
1485 0 0 0       }
1486              
1487             ###########################################
1488 0 0         ###########################################
1489             my ( $self, $options ) = @_;
1490              
1491 0           $options //= {};
1492              
1493             my $info = {
1494             'query_parameters' => {
1495             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
1496             },
1497              
1498             'path' => 'files/trash',
1499             'method' => 'empty_trash',
1500             'http_method' => HTTP_METHOD_DELETE(),
1501             };
1502              
1503             if ( defined $options->{'enforceSingleParent'} ) {
1504             LOGDIE("[$info->{'method_name'}] If an item is not in a shared drive and its last parent is deleted but the item itself is not, the item will be placed under its owner's root");
1505             }
1506              
1507             return $self->_handle_api_method( $info, {} );
1508             }
1509              
1510             # --- permissions
1511              
1512             ###########################################
1513             ###########################################
1514             my ( $self, $fileId, $options ) = @_;
1515              
1516             defined $fileId && length $fileId
1517             or LOGDIE('create_permission() missing file ID');
1518              
1519 0           ref $options eq 'HASH'
1520             or LOGDIE('create_permission() missing parameters');
1521 0            
1522             my $info = {
1523             'query_parameters' => {
1524             'emailMessage' => [ TYPE_STRING(), 0 ],
1525             'enforceSingleParent' => [ TYPE_BOOLEAN(), 0 ],
1526             'fields' => [ TYPE_STRING(), 0 ],
1527 0     0 1   'moveToNewOwnersRoot' => [ TYPE_BOOLEAN(), 0 ],
1528             'sendNotificationEmail' => [ TYPE_BOOLEAN(), 0 ],
1529 0   0       'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1530             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1531 0           'transferOwnership' => [ TYPE_BOOLEAN(), 0 ],
1532             'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
1533             },
1534              
1535             'body_parameters' => [
1536             qw<
1537             role
1538             type
1539             allowFileDiscovery
1540             domain
1541 0 0         emailAddress
1542 0           pendingOwner
1543             view
1544             >
1545 0           ],
1546              
1547             'deprecated_param_names' => {
1548             'enforceSingleParent' => 'moveToNewOwnersRoot',
1549             },
1550              
1551             'path' => "files/$fileId/permissions",
1552             'method_name' => 'create_permission',
1553 0     0 1   'http_method' => HTTP_METHOD_POST(),
1554             };
1555 0 0 0        
1556             return $self->_handle_api_method( $info, $options );
1557             }
1558 0 0          
1559             ###########################################
1560             ###########################################
1561 0           my ( $self, $fileId, $permissionId, $options ) = @_;
1562              
1563             defined $fileId && length $fileId
1564             or LOGDIE('delete_permission() missing file ID');
1565              
1566             defined $permissionId && length $permissionId
1567             or LOGDIE('delete_permission() missing permission ID');
1568              
1569             $options //= {};
1570              
1571             my $info = {
1572             'query_parameters' => {
1573             'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1574             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1575             'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
1576             },
1577              
1578             'path' => "files/$fileId/permissions/$permissionId",
1579             'method_name' => 'delete_permission',
1580             'http_method' => HTTP_METHOD_DELETE(),
1581             };
1582              
1583             return $self->_handle_api_method( $info, $options );
1584             }
1585              
1586             ###########################################
1587             ###########################################
1588             my ( $self, $fileId, $permissionId, $options ) = @_;
1589              
1590             defined $fileId && length $fileId
1591             or LOGDIE('get_permission() missing file ID');
1592              
1593             defined $permissionId && length $permissionId
1594             or LOGDIE('get_permission() missing permission ID');
1595 0            
1596             $options //= {};
1597              
1598             my $info = {
1599             'query_parameters' => {
1600             'fields' => [ TYPE_STRING(), 0 ],
1601 0     0 1   'supportsAllDrivee' => [ TYPE_BOOLEAN(), 0 ],
1602             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1603 0 0 0       'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
1604             },
1605              
1606 0 0 0       'path' => "files/$fileId/permissions/$permissionId",
1607             'method_name' => 'get_permission',
1608             'http_method' => HTTP_METHOD_GET(),
1609 0   0       };
1610              
1611 0           return $self->_handle_api_method( $info, $options );
1612             }
1613              
1614             ###########################################
1615             ###########################################
1616             my ( $self, $fileId, $options ) = @_;
1617              
1618             defined $fileId && length $fileId
1619             or LOGDIE('permissions() missing file ID');
1620              
1621             $options //= {};
1622              
1623 0           my $info = {
1624             'query_parameters' => {
1625             'fields' => [ TYPE_STRING(), 0 ],
1626             'includePermissionsForView' => [ TYPE_STRING(), 0 ],
1627             'pageSize' => [ TYPE_INTEGER(), 0 ],
1628             'pageToken' => [ TYPE_STRING(), 0 ],
1629 0     0 1   'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1630             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1631 0 0 0       'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
1632             },
1633              
1634 0 0 0       'path' => "files/$fileId/permissions",
1635             'method_name' => 'permissions',
1636             'http_method' => HTTP_METHOD_GET(),
1637 0   0       };
1638              
1639 0           return $self->_handle_api_method( $info, $options );
1640             }
1641              
1642             ###########################################
1643             ###########################################
1644             my ( $self, $fileId, $permissionId, $options ) = @_;
1645              
1646             defined $fileId && length $fileId
1647             or LOGDIE('update_permission() missing file ID');
1648              
1649             defined $permissionId && length $permissionId
1650             or LOGDIE('update_permission() missing permission ID');
1651              
1652 0           $options //= {};
1653              
1654             my $info = {
1655             'query_parameters' => {
1656             'fields' => [ TYPE_STRING(), 0 ],
1657             'removeExpiration' => [ TYPE_BOOLEAN(), 0 ],
1658 0     0 1   'supportsAllDrives' => [ TYPE_BOOLEAN(), 0 ],
1659             'supportsTeamDrives' => [ TYPE_BOOLEAN(), 0 ],
1660 0 0 0       'transferOwnership' => [ TYPE_BOOLEAN(), 0 ],
1661             'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
1662             },
1663 0   0        
1664             'path' => "files/$fileId/permissions/$permissionId",
1665 0           'method_name' => 'update_permission',
1666             'http_method' => HTTP_METHOD_PATCH(),
1667             };
1668              
1669             return $self->_handle_api_method( $info, $options );
1670             }
1671              
1672             # --- replies
1673              
1674             ###########################################
1675             ###########################################
1676             my ( $self, $fileId, $commentId, $options ) = @_;
1677              
1678             defined $fileId && length $fileId
1679             or LOGDIE('create_reply() missing file ID');
1680              
1681 0           defined $commentId && length $commentId
1682             or LOGDIE('create_reply() missing comment ID');
1683              
1684             ref $options eq 'HASH'
1685             or LOGDIE('create_reply() missing parameters');
1686              
1687 0     0 1   my $info = {
1688             'query_parameters' => {
1689 0 0 0       'fields' => [ TYPE_STRING(), 1 ],
1690             },
1691              
1692 0 0 0       'body_parameters' => [
1693             qw<
1694             action
1695 0   0       content
1696             >
1697 0           ],
1698              
1699             'parameter_checks' => {
1700             'action' => sub {
1701             m{^( resolve | reopen )$}xms
1702             or return 'must be: resolve|reopen';
1703              
1704             return 0;
1705             },
1706             },
1707              
1708             'path' => "files/$fileId/comments/$commentId/replies",
1709             'method_name' => 'create_reply',
1710             'http_method' => HTTP_METHOD_POST(),
1711             };
1712 0            
1713             return $self->_handle_api_method( $info, $options );
1714             }
1715              
1716             ###########################################
1717             ###########################################
1718             my ( $self, $fileId, $commentId, $replyId ) = @_;
1719              
1720 0     0 1   defined $fileId && length $fileId
1721             or LOGDIE('delete_reply() missing file ID');
1722 0 0 0        
1723             defined $commentId && length $commentId
1724             or LOGDIE('delete_reply() missing comment ID');
1725 0 0 0        
1726             my $info = {
1727             'path' => "files/$fileId/comments/$commentId/replies/$replyId",
1728 0 0         'method_name' => 'delete_reply',
1729             'http_method' => HTTP_METHOD_DELETE(),
1730             };
1731              
1732             return $self->_handle_api_method( $info, {} );
1733             }
1734              
1735             ###########################################
1736             ###########################################
1737             my ( $self, $fileId, $commentId, $replyId, $options ) = @_;
1738              
1739             defined $fileId && length $fileId
1740             or LOGDIE('get_reply() missing file ID');
1741              
1742             defined $commentId && length $commentId
1743             or LOGDIE('get_reply() missing comment ID');
1744              
1745 0 0   0     defined $replyId && length $replyId
1746             or LOGDIE('get_reply() missing reply ID');
1747              
1748 0           ref $options eq 'HASH'
1749             or LOGDIE('get_reply() missing parameters');
1750              
1751             my $info = {
1752 0           'query_parameters' => {
1753             'fields' => [ TYPE_STRING(), 1 ],
1754             'includeDeleted' => [ TYPE_BOOLEAN(), 0 ],
1755             },
1756              
1757 0           'path' => "files/$fileId/comments/$commentId/replies/$replyId",
1758             'method_name' => 'get_reply',
1759             'http_method' => HTTP_METHOD_GET(),
1760             };
1761              
1762             return $self->_handle_api_method( $info, $options );
1763 0     0 1   }
1764              
1765 0 0 0       ###########################################
1766             ###########################################
1767             my ( $self, $fileId, $commentId, $options ) = @_;
1768 0 0 0        
1769             defined $fileId && length $fileId
1770             or LOGDIE('replies() missing file ID');
1771 0            
1772             defined $commentId && length $commentId
1773             or LOGDIE('replies() missing comment ID');
1774              
1775             ref $options eq 'HASH'
1776             or LOGDIE('replies() missing parameters');
1777 0            
1778             my $info = {
1779             'query_parameters' => {
1780             'fields' => [ TYPE_STRING(), 1 ],
1781             'includeDeleted' => [ TYPE_BOOLEAN(), 0 ],
1782             'pageSize' => [ TYPE_INTEGER(), 0 ],
1783 0     0 1   'pageToken' => [ TYPE_STRING(), 0 ],
1784             },
1785 0 0 0        
1786             'path' => "files/$fileId/comments/$commentId/replies",
1787             'method_name' => 'replies',
1788 0 0 0       'http_method' => HTTP_METHOD_GET(),
1789             };
1790              
1791 0 0 0       return $self->_handle_api_method( $info, $options );
1792             }
1793              
1794 0 0         ###########################################
1795             ###########################################
1796             my ( $self, $fileId, $commentId, $replyId, $options ) = @_;
1797 0            
1798             defined $fileId && length $fileId
1799             or LOGDIE('update_reply() missing file ID');
1800              
1801             defined $commentId && length $commentId
1802             or LOGDIE('update_reply() missing comment ID');
1803              
1804             defined $replyId && length $replyId
1805             or LOGDIE('update_reply() missing reply ID');
1806              
1807             ref $options eq 'HASH'
1808 0           or LOGDIE('update_reply() missing parameters');
1809              
1810             my $info = {
1811             'query_parameters' => {
1812             'fields' => [ TYPE_STRING(), 1 ],
1813             },
1814 0     0 1    
1815             'body_parameters' => {
1816 0 0 0       'content' => [ TYPE_STRING(), 1 ],
1817             },
1818              
1819 0 0 0       'path' => "files/$fileId/comments/$commentId/replies/$replyId",
1820             'method_name' => 'update_reply',
1821             'http_method' => HTTP_METHOD_PATCH(),
1822 0 0         };
1823              
1824             return $self->_handle_api_method( $info, $options );
1825 0           }
1826              
1827             # --- revisions
1828              
1829             ###########################################
1830             ###########################################
1831             my ( $self, $fileId, $revisionId ) = @_;
1832              
1833             defined $fileId && length $fileId
1834             or LOGDIE('delete_revision() missing file ID');
1835              
1836             my $info = {
1837             'path' => "files/$fileId/revisions/$revisionId",
1838 0           'method_name' => 'delete_revision',
1839             'http_method' => HTTP_METHOD_DELETE(),
1840             };
1841              
1842             return $self->_handle_api_method( $info, {} );
1843             }
1844 0     0 1    
1845             ###########################################
1846 0 0 0       ###########################################
1847             my ( $self, $fileId, $revisionId, $options ) = @_;
1848              
1849 0 0 0       defined $fileId && length $fileId
1850             or LOGDIE('get_revision() missing file ID');
1851              
1852 0 0 0       defined $revisionId && length $revisionId
1853             or LOGDIE('get_revision() missing revision ID');
1854              
1855 0 0         $options //= {};
1856              
1857             my $info = {
1858 0           'query_parameters' => {
1859             'acknowledgeAbuse' => [ TYPE_BOOLEAN(), 0 ],
1860             'fields' => [ TYPE_STRING(), 0 ],
1861             },
1862              
1863             'path' => "files/$fileId/revisions/$revisionId",
1864             'method_name' => 'get_revision',
1865             'http_method' => HTTP_METHOD_GET(),
1866             };
1867              
1868             return $self->_handle_api_method( $info, $options );
1869             }
1870              
1871             ###########################################
1872 0           ###########################################
1873             my ( $self, $fileId, $options ) = @_;
1874              
1875             defined $fileId && length $fileId
1876             or LOGDIE('revisions() missing file ID');
1877              
1878             $options //= {};
1879              
1880 0     0 1   my $info = {
1881             'query_parameters' => {
1882 0 0 0       'fields' => [ TYPE_STRING(), 0 ],
1883             'pageSize' => [ TYPE_INTEGER(), 0 ],
1884             'pageToken' => [ TYPE_STRING(), 0 ],
1885 0           },
1886              
1887             'path' => "files/$fileId/revisions",
1888             'method_name' => 'revisions',
1889             'http_method' => HTTP_METHOD_GET(),
1890             };
1891 0            
1892             return $self->_handle_api_method( $info, $options );
1893             }
1894              
1895             ###########################################
1896             ###########################################
1897 0     0 1   my ( $self, $fileId, $revisionId, $options ) = @_;
1898              
1899 0 0 0       defined $fileId && length $fileId
1900             or LOGDIE('update_revision() missing file ID');
1901              
1902 0 0 0       defined $revisionId && length $revisionId
1903             or LOGDIE('update_revision() missing revision ID');
1904              
1905 0   0       ref $options eq 'HASH'
1906             or LOGDIE('update_revision() missing parameters');
1907 0            
1908             my $info = {
1909             'query_parameters' => {
1910             'fields' => [ TYPE_STRING(), 0 ],
1911             },
1912              
1913             'body_parameter' => [
1914             qw<
1915             keepForever
1916             publishAuto
1917             published
1918 0           publishedOutsideDomain
1919             >
1920             ],
1921              
1922             'path' => "files/$fileId/revisions/$revisionId",
1923             'method_name' => 'update_revision',
1924 0     0 1   'http_method' => HTTP_METHOD_PATCH(),
1925             };
1926 0 0 0        
1927             return $self->_handle_api_method( $info, $options );
1928             }
1929 0   0        
1930             # --- drives
1931 0            
1932             ###########################################
1933             ###########################################
1934             my ( $self, $options ) = @_;
1935              
1936             ref $options eq 'HASH'
1937             or LOGDIE('create_drive() missing parameters');
1938              
1939             my $info = {
1940             'query_parameters' => {
1941             'requestId' => [ TYPE_STRING(), 1 ],
1942             },
1943 0            
1944             'body_parameters' => {
1945             'name' => [ TYPE_STRING(), 1 ],
1946             'themeId' => [ TYPE_STRING(), 0 ],
1947             },
1948              
1949 0     0 1   'path' => 'drives',
1950             'method_name' => 'create_drive',
1951 0 0 0       'http_method' => HTTP_METHOD_POST(),
1952             };
1953              
1954 0 0 0       return $self->_handle_api_method( $info, $options );
1955             }
1956              
1957 0 0         ###########################################
1958             ###########################################
1959             my ( $self, $driveId ) = @_;
1960 0            
1961             defined $driveId && length $driveId
1962             or LOGDIE('delete_drive() missing drive ID');
1963              
1964             my $info = {
1965             'path' => "drives/$driveId",
1966             'method_name' => 'delete_drive',
1967             'http_method' => HTTP_METHOD_DELETE(),
1968             };
1969              
1970             return $self->_handle_api_method( $info, {} );
1971             }
1972              
1973             ###########################################
1974             ###########################################
1975             my ( $self, $driveId, $options ) = @_;
1976              
1977             defined $driveId && length $driveId
1978             or LOGDIE('get_drive() missing drive ID');
1979 0            
1980             $options //= {};
1981              
1982             my $info = {
1983             'query_parameters' => {
1984             'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
1985             },
1986              
1987 0     0 1   'path' => "drives/$driveId",
1988             'method_name' => 'get_drive',
1989 0 0         'http_method' => HTTP_METHOD_GET(),
1990             };
1991              
1992 0           return $self->_handle_api_method( $info, $options );
1993             }
1994              
1995             ###########################################
1996             ###########################################
1997             my ( $self, $driveId ) = @_;
1998              
1999             defined $driveId && length $driveId
2000             or LOGDIE('hide_drive() missing drive ID');
2001              
2002             my $info = {
2003             'path' => "drives/$driveId/hide",
2004             'method_name' => 'hide_drive',
2005             'http_method' => HTTP_METHOD_POST(),
2006             };
2007 0            
2008             return $self->_handle_api_method( $info, {} );
2009             }
2010              
2011             ###########################################
2012             ###########################################
2013 0     0 1   my ( $self, $options ) = @_;
2014              
2015 0 0 0       $options //= {};
2016              
2017             my $info = {
2018 0           'query_parameters' => {
2019             'pageSize' => [ TYPE_INTEGER(), 0 ],
2020             'pageToken' => [ TYPE_STRING(), 0 ],
2021             'q' => [ TYPE_STRING(), 0 ],
2022             'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
2023             },
2024 0            
2025             'path' => 'drives',
2026             'method_name' => 'drives',
2027             'http_method' => HTTP_METHOD_GET(),
2028             };
2029              
2030 0     0 1   return $self->_handle_api_method( $info, $options );
2031             }
2032 0 0 0        
2033             ###########################################
2034             ###########################################
2035 0   0       my ( $self, $driveId ) = @_;
2036              
2037 0           defined $driveId && length $driveId
2038             or LOGDIE('unhide_drive() missing drive ID');
2039              
2040             my $info = {
2041             'path' => "drives/$driveId/unhide",
2042             'method_name' => 'unhide_drive',
2043             'http_method' => HTTP_METHOD_POST(),
2044             };
2045              
2046             return $self->_handle_api_method( $info, {} );
2047 0           }
2048              
2049             ###########################################
2050             ###########################################
2051             my ( $self, $driveId, $options ) = @_;
2052              
2053 0     0 1   defined $driveId && length $driveId
2054             or LOGDIE('update_drive() missing drive ID');
2055 0 0 0        
2056             ref $options eq 'HASH'
2057             or LOGDIE('update_drive() missing parameters');
2058 0            
2059             my $info = {
2060             'query_parameters' => {
2061             'useDomainAdminAccess' => [ TYPE_BOOLEAN(), 0 ],
2062             },
2063              
2064 0           'body_parameters' => [
2065             qw<
2066             backgroundImageFile
2067             colorRgb
2068             name
2069             restrictions
2070 0     0 1   themeId
2071             >
2072 0   0       ],
2073              
2074 0           'path' => "drives/$driveId",
2075             'method_name' => 'update_drive',
2076             'http_method' => HTTP_METHOD_PATCH(),
2077             };
2078              
2079             return $self->_handle_api_method( $info, $options );
2080             }
2081              
2082             # Helper methods
2083              
2084             ###########################################
2085             ###########################################
2086             my ( $self, $path, $opts, $search_opts ) = @_;
2087 0            
2088             DEBUG("Determine children of $path");
2089             LOGDIE("No $path given") unless defined $path;
2090              
2091             $opts //= {};
2092             $search_opts //= {};
2093 0     0 1    
2094             $opts->{'maxResults'}
2095 0 0 0       and LOGDIE("'maxResults' not supported, use 'pagesize' instead");
2096              
2097             my ( $folder_id, $parent ) = $self->_path_resolve( $path, $opts, $search_opts );
2098 0            
2099             return unless defined $folder_id;
2100              
2101             DEBUG("Getting content of folder $folder_id");
2102             my $children = $self->children_by_folder_id( $folder_id, $opts, $search_opts ) or return;
2103              
2104 0           return $children;
2105             }
2106              
2107             ###########################################
2108             ###########################################
2109             my ( $self, $folder_id, $opts, $search_opts ) = @_;
2110 0     0 1    
2111             $folder_id
2112 0 0 0       or LOGDIE('Must provide a folder id');
2113              
2114             $self->init();
2115 0 0          
2116             $opts = {} unless defined $opts;
2117             $search_opts = {} unless defined $search_opts;
2118 0            
2119             exists $search_opts->{'page'}
2120             and LOGDIE("Search option 'page' is deprecated, use 'auto_paging'");
2121              
2122             exists $search_opts->{'title'}
2123             and LOGDIE("Search option 'title' is deprecated, set 'q' parameter with 'name' accordingly");
2124              
2125             $search_opts->{'auto_paging'} //= 1;
2126              
2127             # Append or create a search in folder
2128             if ( defined $opts->{'q'} && length $opts->{'q'} ) {
2129             $opts->{'q'} .= ' AND ';
2130             }
2131             else {
2132             $opts->{'q'} = '';
2133             }
2134              
2135             $opts->{'q'} .= "'$folder_id' in parents";
2136              
2137             if ( my $name = $search_opts->{'name'} ) {
2138 0           $name =~ s{\'}{\\\'}xmsg;
2139             $opts->{'q'} .= " AND name = '$name'";
2140             }
2141              
2142             $opts->{'fields'} //= '';
2143             if ( $opts->{'fields'} ) {
2144             $opts->{'fields'} .= ',';
2145             }
2146 0     0 1   $opts->{'fields'} .= 'files(id,kind,name,mimeType,parents,originalFilename,trashed)';
2147              
2148 0           # Find only those not in the trash
2149 0 0         # possibly go through all paged results
2150             my @children;
2151 0   0       while (1) {
2152 0   0       my $data = $self->files($opts)
2153             or return;
2154 0 0          
2155             my @items = @{ $data->{'files'} || [] };
2156              
2157 0           while ( my $item = shift @items ) {
2158             if ( $item->{'trashed'} ) {
2159 0 0         DEBUG("Skipping $item->{'name'} (item in trash)");
2160             next;
2161 0           }
2162 0 0          
2163             # use the Item.pm object with AUTOLOAD, is_folder, and is_file
2164 0           # TODO: I dislke the AUTOLOAD format...
2165             push @children, $self->data_factory($item);
2166             }
2167              
2168             if ( $search_opts->{'auto_paging'} && $data->{'nextPageToken'} ) {
2169             $opts->{'pageToken'} = $data->{'nextPageToken'};
2170 0     0 1   }
2171             else {
2172 0 0         last;
2173             }
2174             }
2175 0            
2176             return \@children;
2177 0 0         }
2178 0 0          
2179             ###########################################
2180 0 0         ###########################################
2181             my ( $self, $path, $opts, $search_opts ) = @_;
2182              
2183 0 0         $opts = {} if !defined $opts;
2184             $search_opts = {} if !defined $search_opts;
2185              
2186 0   0       my @parts = grep length, split '/', $path;
2187              
2188             my @ids = qw(root);
2189 0 0 0       my $folder_id = my $parent = 'root';
2190 0           DEBUG("Parent: $parent");
2191              
2192             PART:
2193 0           foreach my $part (@parts) {
2194             DEBUG("Looking up part $part (folder_id=$folder_id)");
2195              
2196 0           # We append to 'q' parameter in case the user provided it
2197             my $name = $part =~ s{\'}{\\\'}xmsgr;
2198 0 0          
2199 0           my $children = $self->children_by_folder_id(
2200 0           $folder_id,
2201             {},
2202             { %{$search_opts}, 'name' => $name },
2203 0   0       ) or return;
2204 0 0          
2205 0           for my $child (@$children) {
2206             DEBUG( "Found child: " . $child->name() );
2207 0            
2208             if ( $child->name() eq $part ) {
2209             $folder_id = $child->id();
2210             unshift @ids, $folder_id;
2211 0           $parent = $folder_id;
2212 0           DEBUG("Parent: $parent");
2213 0 0         next PART;
2214             }
2215             }
2216 0 0          
  0            
2217             my $msg = "Child $part not found";
2218 0           $self->error($msg);
2219 0 0         ERROR($msg);
2220 0           return;
2221 0           }
2222              
2223             # parent of root is root
2224             if ( @ids == 1 ) {
2225             push @ids, $ids[0];
2226 0           }
2227              
2228             return @ids;
2229 0 0 0       }
2230 0            
2231             # TODO: Placed here until I have a use for it
2232             #my %IMPORT_FORMATS = (
2233 0           # 'application/x-vnd.oasis.opendocument.presentation' => 'application/vnd.google-apps.presentation',
2234             # 'text/tab-separated-values' => 'application/vnd.google-apps.spreadsheet',
2235             # 'image/jpeg' => 'application/vnd.google-apps.document',
2236             # 'image/bmp' => 'application/vnd.google-apps.document',
2237 0           # 'image/gif' => 'application/vnd.google-apps.document',
2238             # 'application/vnd.ms-excel.sheet.macroenabled.12' => 'application/vnd.google-apps.spreadsheet',
2239             # 'application/vnd.openxmlformats-officedocument.wordprocessingml.template' => 'application/vnd.google-apps.document',
2240             # 'application/vnd.ms-powerpoint.presentation.macroenabled.12' => 'application/vnd.google-apps.presentation',
2241             # 'application/vnd.ms-word.template.macroenabled.12' => 'application/vnd.google-apps.document',
2242             # 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'application/vnd.google-apps.document',
2243 0     0     # 'image/pjpeg' => 'application/vnd.google-apps.document',
2244             # 'application/vnd.google-apps.script+text/plain' => 'application/vnd.google-apps.script',
2245 0 0         # 'application/vnd.ms-excel' => 'application/vnd.google-apps.spreadsheet',
2246 0 0         # 'application/vnd.sun.xml.writer' => 'application/vnd.google-apps.document',
2247             # 'application/vnd.ms-word.document.macroenabled.12' => 'application/vnd.google-apps.document',
2248 0           # 'application/vnd.ms-powerpoint.slideshow.macroenabled.12' => 'application/vnd.google-apps.presentation',
2249             # 'text/rtf' => 'application/vnd.google-apps.document',
2250 0           # 'application/vnd.oasis.opendocument.spreadsheet' => 'application/vnd.google-apps.spreadsheet',
2251 0           # 'text/plain' => 'application/vnd.google-apps.document',
2252 0           # 'application/x-vnd.oasis.opendocument.spreadsheet' => 'application/vnd.google-apps.spreadsheet',
2253             # 'application/x-vnd.oasis.opendocument.text' => 'application/vnd.google-apps.document',
2254             # 'image/png' => 'application/vnd.google-apps.document',
2255 0           # 'application/msword' => 'application/vnd.google-apps.document',
2256 0           # 'application/pdf' => 'application/vnd.google-apps.document',
2257             # 'application/x-msmetafile' => 'application/vnd.google-apps.drawing',
2258             # 'application/vnd.openxmlformats-officedocument.spreadsheetml.template' => 'application/vnd.google-apps.spreadsheet',
2259 0           # 'application/vnd.ms-powerpoint' => 'application/vnd.google-apps.presentation',
2260             # 'application/vnd.ms-excel.template.macroenabled.12' => 'application/vnd.google-apps.spreadsheet',
2261             # 'image/x-bmp' => 'application/vnd.google-apps.document',
2262             # 'application/rtf' => 'application/vnd.google-apps.document',
2263             # 'application/vnd.openxmlformats-officedocument.presentationml.template' => 'application/vnd.google-apps.presentation',
2264 0 0         # 'image/x-png' => 'application/vnd.google-apps.document',
  0            
2265             # 'text/html' => 'application/vnd.google-apps.document',
2266             # 'application/vnd.oasis.opendocument.text' => 'application/vnd.google-apps.document',
2267 0           # 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'application/vnd.google-apps.presentation',
2268 0           # 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'application/vnd.google-apps.spreadsheet',
2269             # 'application/vnd.google-apps.script+json' => 'application/vnd.google-apps.script',
2270 0 0         # 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'application/vnd.google-apps.presentation',
2271 0           # 'application/vnd.ms-powerpoint.template.macroenabled.12' => 'application/vnd.google-apps.presentation',
2272 0           # 'text/csv' => 'application/vnd.google-apps.spreadsheet',
2273 0           # 'application/vnd.oasis.opendocument.presentation' => 'application/vnd.google-apps.presentation',
2274 0           # 'image/jpg' => 'application/vnd.google-apps.document',
2275 0           # 'text/richtext' => 'application/vnd.google-apps.document']
2276             #);
2277              
2278             1;
2279 0            
2280 0            
2281 0           =head1 SYNOPSIS
2282 0            
2283             my $gd_v3 = Net::Google::Drive::Simple->new( 'version' => 3 );
2284             # same as:
2285             my $gd_v3 = Net::Google::Drive::Simple::V3->new();
2286 0 0          
2287 0           $gd->changes(...);
2288             $gd->create_comment(...);
2289             $gd->delete_file(...);
2290 0            
2291             =head1 DESCRIPTION
2292              
2293             This is a complete implementation of the Google Drive API V3. You can
2294             use all the documented methods below.
2295              
2296             Uploading files over 5 MB require reading the B<UPLOADING> section below.
2297              
2298             =head1 METHODS
2299              
2300             =head2 C<new>
2301              
2302             my $gd = Net::Google::Drive::Simple::V3->new();
2303              
2304             Create a new instance.
2305              
2306             You can also create an instance using L<Net::Google::Drive::Simple>:
2307              
2308             my $gd = Net::Google::Drive::Simple->new( 'version' => 3 );
2309              
2310             =head2 C<about>
2311              
2312             my $about = $gd->about({%params});
2313              
2314             This serves the path to C</about>.
2315              
2316             It's also referred to as C<about.get>.
2317              
2318             You can read about the parameters on the Google Drive
2319             L<API page|https://developers.google.com/drive/api/v3/reference/about/get>.
2320              
2321             =head2 C<getStartPageToken>
2322              
2323             my $data = $gd->getStartPageToken({%params});
2324              
2325             Parameters are optional.
2326              
2327             This serves the path to C</changes/startPageToken>.
2328              
2329             This is also known as C<changes_getStartPageToken>.
2330              
2331             You can read about the parameters on the Google Drive
2332             L<API page|https://developers.google.com/drive/api/v3/reference/changes/getStartPageToken>.
2333              
2334             =head2 C<changes>
2335              
2336             my $changes_list = $gd->changes({%params});
2337              
2338             This serves the path to C</changes>.
2339              
2340             This is also known as C<changes.list>.
2341              
2342             You can read about the parameters on the Google Drive
2343             L<API page|https://developers.google.com/drive/api/v3/reference/changes/list>.
2344              
2345             =head2 C<watch_changes>
2346              
2347             my $data = $gd->watch_changes({%params});
2348              
2349             Parameters are optional.
2350              
2351             This serves the path to C</changes/watch>.
2352              
2353             This is also known as C<changes.watch>.
2354              
2355             You can read about the parameters on the Google Drive
2356             L<API page|https://developers.google.com/drive/api/v3/reference/changes/watch>.
2357              
2358             =head2 C<stop_channels>
2359              
2360             $gd->stop_channels({%params});
2361              
2362             This serves the path to C</channels/stop>.
2363              
2364             This is also known as C<channels.stop>.
2365              
2366             You can read about the parameters on the Google Drive
2367             L<API page|https://developers.google.com/drive/api/v3/reference/channels/stop>.
2368              
2369             =head2 C<create_comment>
2370              
2371             my $comment = $gd->create_comment( $fileId, {%params} );
2372              
2373             This serves the path to C</files/$fileId/comments>.
2374              
2375             This is also known as C<comments.create>.
2376              
2377             You can read about the parameters on the Google Drive
2378             L<API page|https://developers.google.com/drive/api/v3/reference/comments/create>.
2379              
2380             =head2 C<delete_comment( $fileId, $commentId )>
2381              
2382             $gd->delete_comment( $fileId, $commentId );
2383              
2384             This serves the path to C</files/$fileId/comments/$commentId>.
2385              
2386             This is also known as C<comments.delete>.
2387              
2388             You can read about the parameters on the Google Drive
2389             L<API page|https://developers.google.com/drive/api/v3/reference/comments/delete>.
2390              
2391             =head2 C<get_comment( $fileId, $commentId, $params )>
2392              
2393             my $comment = $gd->get_comment( $fileId, $commentId, {%params} );
2394              
2395             This serves the path to C</files/$fileId/comments/$commentId>.
2396              
2397             This is also known as C<comments.get>.
2398              
2399             You can read about the parameters on the Google Drive
2400             L<API page|https://developers.google.com/drive/api/v3/reference/comments/get>.
2401              
2402             =head2 C<comments>
2403              
2404             my $comments = $gd->comments( $fileId, {%params} );
2405              
2406             This serves the path to C</files/$fileId/comments>.
2407              
2408             This is also known as C<comments.list>.
2409              
2410             You can read about the parameters on the Google Drive
2411             L<API page|https://developers.google.com/drive/api/v3/reference/comments/list>.
2412              
2413             =head2 C<update_comment>
2414              
2415             my $comment = $gd->update_comment( $fileId, $commentId, {%params} );
2416              
2417             This serves the path to C</files/$fileId/comments/$commentId>.
2418              
2419             This is also known as C<comments.update>.
2420              
2421             You can read about the parameters on the Google Drive
2422             L<API page|https://developers.google.com/drive/api/v3/reference/comments/update>.
2423              
2424             =head2 C<copy_file>
2425              
2426             my $file = $gd->copy_file( $fileId, {%params} );
2427              
2428             This serves the path to C</files/$fileId/copy>.
2429              
2430             This is also known as C<files.copy>.
2431              
2432             You can read about the parameters on the Google Drive
2433             L<API page|https://developers.google.com/drive/api/v3/reference/files/copy>.
2434              
2435             =head2 C<create_folder>
2436              
2437             my $folder_data = $gd->create_folder( $name, $parent_id );
2438             print $folder_data->{'id'};
2439              
2440             This method is just for convenience. It's effectively:
2441              
2442             $self->create_file({
2443             'name' => $name,
2444             'mimeType' => "application/vnd.google-apps.folder",
2445             'parents' => [$parent_id],
2446             });
2447              
2448             =head2 C<create_file>
2449              
2450             my $file = $gd->create_file({%params});
2451              
2452             This serves the path to C</files>.
2453              
2454             This is also known as C<files.create>.
2455              
2456             You can read about the parameters on the Google Drive
2457             L<API page|https://developers.google.com/drive/api/v3/reference/files/create>.
2458              
2459             This one is B<ONLY for creating metadata for a file>. It will not upload
2460             any content. If you want to set content, use the following methods below:
2461             C<upload_media_file()>, C<upload_multipart_file>,
2462             C<create_resumable_upload()>, C<upload_file_content_single()>,
2463             C<upload_file_content_multiple()>, and C<upload_file_content_iterator>.
2464              
2465             Read more about uploading under B<UPLOADING> below. If you want a simple way
2466             to upload files, check C<upload_file()>.
2467              
2468             =head2 C<upload_file>
2469              
2470             my $result = $gd->upload_file( $filename, {%params} );
2471              
2472             Parameters are optional.
2473              
2474             This method combines the different mechanisms for uploading a file and makes
2475             it easy to upload large files. There are disadvantages, but for most cases,
2476             this method should serve you well.
2477              
2478             Read more about uploading under B<UPLOADING> below.
2479              
2480             =head2 C<upload_media_file>
2481              
2482             my $file = $gd->upload_media_file( $filename, {%params} );
2483              
2484             Parameters are optional.
2485              
2486             This serves the path to C</files>.
2487              
2488             This is also known as C<files.create>.
2489              
2490             You can read about the parameters on the Google Drive
2491             L<API page|https://developers.google.com/drive/api/v3/reference/files/create>.
2492              
2493             This one is for uploading a file B<without metadata>. File size limitation
2494             is 5 MB and we read it 4K at a time.
2495              
2496             Read more about uploading under B<UPLOADING> below.
2497              
2498             =head2 C<upload_multipart_file>
2499              
2500             my $file = $gd->upload_multipart_file( $filename, {%params} );
2501              
2502             Parameters are optional.
2503              
2504             This serves the path to C</files>.
2505              
2506             This is also known as C<files.create>.
2507              
2508             You can read about the parameters on the Google Drive
2509             L<API page|https://developers.google.com/drive/api/v3/reference/files/create>.
2510              
2511             This one is for uploading B<both a file and its metadata>. File size limitation
2512             is 5 MB and we read the entire file into memory at once before uploading.
2513              
2514             Read more about uploading under B<UPLOADING> below.
2515              
2516             =head2 C<create_resumable_upload_for>
2517              
2518             my $upload_id = $gd->upload_multimedia_file( $filename, {%params} );
2519              
2520             Parameters are optional.
2521              
2522             This serves the path to C</files>.
2523              
2524             This is also known as C<files.create>.
2525              
2526             You can read about the parameters on the Google Drive
2527             L<API page|https://developers.google.com/drive/api/v3/reference/files/create>.
2528              
2529             This method starts a resumable upload for a specific file on disk. It provides
2530             you with an ID that you can then feed to the following methods:
2531             C<upload_file_content_single()>, C<upload_file_content_multiple()>, and
2532             C<upload_file_content_iterator()>.
2533              
2534             File size limitation for any resumable upload is 5120 GB and
2535             C<create_resumable_upload_for()> checks for this limit.
2536              
2537             Read more about uploading under B<UPLOADING> below.
2538              
2539             =head2 C<create_resumable_upload>
2540              
2541             my $upload_id = $gd->create_resumable_upload( {%params} );
2542              
2543             Parameters are optional.
2544              
2545             This serves the path to C</files>.
2546              
2547             This is also known as C<files.create>.
2548              
2549             You can read about the parameters on the Google Drive
2550             L<API page|https://developers.google.com/drive/api/v3/reference/files/create>.
2551              
2552             This method starts a resumable upload. It provides you with an ID that you can
2553             then feed to the following methods: C<upload_file_content_single()>,
2554             C<upload_file_content_multiple()>, and C<upload_file_content_iterator()>.
2555              
2556             File size limitation for any resumable upload is 5120 GB and
2557             C<create_resumable_upload_for()> checks for this limit.
2558              
2559             Read more about uploading under B<UPLOADING> below.
2560              
2561             =head2 C<upload_file_content_single>
2562              
2563             my $result = $gd->upload_file_content_single( $upload_uri, $filename );
2564              
2565             This serves the path to the upload URI you provide it.
2566              
2567             There is a limitation of 5120 GB for the file. With this method, we feed the
2568             file 4K at a time.
2569              
2570             Read more about uploading under B<UPLOADING>.
2571              
2572             =head2 C<upload_file_content_multiple>
2573              
2574             my $result = $gd->upload_file_content_multiple( $upload_uri, $file, $chunk_size );
2575              
2576             Chunk size is optional, defaults to 10 MB.
2577              
2578             This serves the path to the upload URI you provide it.
2579              
2580             There is a limitation of 5120 GB for the file. With this method, we feed the
2581             file in chunks defined by the chunk size you provide or the default 10 MB.
2582              
2583             Read more about uploading under B<UPLOADING>.
2584              
2585             The difference between C<upload_file_content_single()> and
2586             C<upload_file_content_multiple()> is that this variation will work better
2587             for long files, in theory. More importantly, it uses
2588             C<upload_file_content_iterator()> which really allows you to control matters.
2589              
2590             =head2 C<upload_file_content_iterator>
2591              
2592             use JSON qw< from_json >;
2593              
2594             my $iter_cb = $gd->upload_file_content_iterator( $filename, $file, $chunk_size );
2595              
2596             while ( my $request = $iter->() ) {
2597             my $response = handle_http_request($request);
2598             # anything else - we're confused, so it's an error no matter what
2599              
2600             # 200 - Done!
2601             if ( $response->code() == 200 ) {
2602             return from_json( $response->decoded_content() );
2603             }
2604              
2605             # 308 - Continue uploading!
2606             # anything else - not what we're expecting
2607             if ( $response->code() != 308 ) {
2608             die "Error: " . $response->code();
2609             }
2610             }
2611              
2612             Chunk size is optional, defaults to 10 MB.
2613              
2614             This returns a callback that allows you to control how to handle the
2615             uploading. It's especially valuable when you want to connect the uploading
2616             to an event loop like L<IO::Async>, L<POE>, L<AnyEvent>, or others.
2617              
2618             The callback returns an object of L<HTTP::Request> which represent the
2619             request that needs to be done. Once requested, if you receive a 308, it
2620             means you can continue, and if you receive a 200, it means you are done
2621             uploading.
2622              
2623             There is a limitation of 5120 GB for the file. With this method, we feed the
2624             file in chunks defined by the chunk size you provide or the default 10 MB.
2625              
2626             Read more about uploading under B<UPLOADING>.
2627              
2628             =head2 C<delete_file>
2629              
2630             $gd->delete_file( $fileId, {%params} );
2631              
2632             Parameters are optional.
2633              
2634             This serves the path to C</files/$fileId>.
2635              
2636             This is also known as C<files.delete>.
2637              
2638             You can read about the parameters on the Google Drive
2639             L<API page|https://developers.google.com/drive/api/v3/reference/files/delete>.
2640              
2641             =head2 C<export_file>
2642              
2643             my $file_content_in_bytes = $gd->export_file( $fileId, {%params} );
2644              
2645             This serves the path to C</files/$fileId/export>.
2646              
2647             This is also known as C<files.export>.
2648              
2649             You can read about the parameters on the Google Drive
2650             L<API page|https://developers.google.com/drive/api/v3/reference/files/export>.
2651              
2652             =head2 C<generateIds>
2653              
2654             my $data = $gd->generateIds({%params});
2655              
2656             Parameters are optional.
2657              
2658             This serves the path to C</files/generateIds>.
2659              
2660             This is also known as C<files.generateIds>.
2661              
2662             You can read about the parameters on the Google Drive
2663             L<API page|https://developers.google.com/drive/api/v3/reference/files/generateIds>.
2664              
2665             =head2 C<get_file>
2666              
2667             my $file_metadata = $gd->get_file( $fileId, {%params} );
2668              
2669             my $file_content = $gd->get_file(
2670             $fileId,
2671             {
2672             'alt' => 'media', # get the content
2673             'acknowledgeAbuse' => JSON::true(), # (optional) when there's risk
2674             },
2675             );
2676              
2677             Parameters are optional.
2678              
2679             This serves the path to C</files/$fileId>.
2680              
2681             This is also known as C<files.get>.
2682              
2683             You can read about the parameters on the Google Drive
2684             L<API page|https://developers.google.com/drive/api/v3/reference/files/get>.
2685              
2686             =head2 C<files>
2687              
2688             my $files = $gd->files({%params});
2689              
2690             Parameters are optional.
2691              
2692             This serves the path to C</files>.
2693              
2694             This is also known as C<files.list>.
2695              
2696             You can read about the parameters on the Google Drive
2697             L<API page|https://developers.google.com/drive/api/v3/reference/files/list>.
2698              
2699             =head2 C<update_file>
2700              
2701             my $file = $gd->update_file( $fileId, {%params} );
2702              
2703             This serves the path to C</files/$fileId>.
2704              
2705             This is also known as C<files.update>.
2706              
2707             This is for updating a file's metadata and content.
2708              
2709             You can read about the parameters on the Google Drive
2710             L<API page|https://developers.google.com/drive/api/v3/reference/files/update>.
2711              
2712             =head2 C<update_file_metadata>
2713              
2714             my $file = $gd->update_file_metadata( $fileId, {%params} );
2715              
2716             This serves the path to C</files/$fileId>.
2717              
2718             This is also known as C<files.update>.
2719              
2720             This one is only for updating a file's metadata, even though it shares
2721             a moniker with the C<update_file()> method in the Google Drive API.
2722              
2723             You can read about the parameters on the Google Drive
2724             L<API page|https://developers.google.com/drive/api/v3/reference/files/update>.
2725              
2726             =head2 C<watch_file>
2727              
2728             my $data = $gd->watch_file( $fileId, {%params} );
2729              
2730             This serves the path to C</files/$fileId/watch>.
2731              
2732             This is also known as C<files.watch>.
2733              
2734             You can read about the parameters on the Google Drive
2735             L<API page|https://developers.google.com/drive/api/v3/reference/files/watch>.
2736              
2737             =head2 C<empty_trash>
2738              
2739             $gd->empty_trash({%params})
2740              
2741             Parameters are optional.
2742              
2743             This serves the path to C</files/trash>.
2744              
2745             This is also known as C<files.emptyTrash>.
2746              
2747             You can read about the parameters on the Google Drive
2748             L<API page|https://developers.google.com/drive/api/v3/reference/files/emptyTrash>.
2749              
2750             =head2 C<create_permission>
2751              
2752             my $permission = $gd-><create_permission( $fileId, {%params} );
2753              
2754             This serves the path to C</files/$fileId/permissions>.
2755              
2756             This is also known as C<permissions.create>.
2757              
2758             You can read about the parameters on the Google Drive
2759             L<API page|https://developers.google.com/drive/api/v3/reference/permissions/create>.
2760              
2761             =head2 C<delete_permission>
2762              
2763             $gd->delete_permission( $fileId, $permissionId, {%params} );
2764              
2765             Parameters are optional.
2766              
2767             This serves the path to C</files/$fileId/permissions/$permissionId>.
2768              
2769             This is also known as C<permissions.delete>.
2770              
2771             You can read about the parameters on the Google Drive
2772             L<API page|https://developers.google.com/drive/api/v3/reference/permissions/delete>.
2773              
2774             =head2 C<get_permission>
2775              
2776             my $permission = $gd->get_permission( $fileId, $permissionId, {%params} );
2777              
2778             Parameters are optional.
2779              
2780             This serves the path to C</files/$fileId/permissions/$permissionId>.
2781              
2782             This is also known as C<permissions.get>.
2783              
2784             You can read about the parameters on the Google Drive
2785             L<API page|https://developers.google.com/drive/api/v3/reference/permissions/get>.
2786              
2787             =head2 C<permissions>
2788              
2789             my $permissions = $gd->permissions( $fileId, {%params} );
2790              
2791             Parameters are optional.
2792              
2793             This serves the path to C</files/$fileId/permissions>.
2794              
2795             This is also known as C<permissions.list>.
2796              
2797             You can read about the parameters on the Google Drive
2798             L<API page|https://developers.google.com/drive/api/v3/reference/permissions/list>.
2799              
2800             =head2 C<update_permission>
2801              
2802             my $permission = $gd->update_permission( $fileId, $permissionId, {%params} );
2803              
2804             Parameters are optional.
2805              
2806             This serves the path to C</files/$fileId/permissions/$permissionId>.
2807              
2808             This is also known as C<permissions.update>.
2809              
2810             You can read about the parameters on the Google Drive
2811             L<API page|https://developers.google.com/drive/api/v3/reference/permissions/update>.
2812              
2813             =head2 C<create_reply>
2814              
2815             my $reply = $gd->create_reply( $fileId, $commentId, {%params} );
2816              
2817             This serves the path to C</files/$fileId/comments/$commentId/replies>.
2818              
2819             This is also known as C<replies.create>.
2820              
2821             You can read about the parameters on the Google Drive
2822             L<API page|https://developers.google.com/drive/api/v3/reference/replies/create>.
2823              
2824             =head2 C<delete_reply( $fileId, $commentId, $replyId )>
2825              
2826             $gd->delete_reply( $fileId, $commentId, $replyId );
2827              
2828             This serves the path to C</files/$fileId/comments/$commentId/replies/$replyId>.
2829              
2830             This is also known as C<replies.delete>.
2831              
2832             You can read about the parameters on the Google Drive
2833             L<API page|https://developers.google.com/drive/api/v3/reference/replies/delete>.
2834              
2835             =head2 C<get_reply>
2836              
2837             my $reply = %gd->get_reply( $fileId, $commentId, $replyId, {%params} );
2838              
2839             This serves the path to C</files/$fileId/comments/$commentId/replies/$replyId>.
2840              
2841             This is also known as C<replies.get>.
2842              
2843             You can read about the parameters on the Google Drive
2844             L<API page|https://developers.google.com/drive/api/v3/reference/replies/get>.
2845              
2846             =head2 C<replies>
2847              
2848             my $replies = $gd->replies( $fileId, $commentId, {%params} );
2849              
2850             This serves the path to C</files/$fileId/comments/$commentId/replies>.
2851              
2852             This is also known as C<replies.list>.
2853              
2854             You can read about the parameters on the Google Drive
2855             L<API page|https://developers.google.com/drive/api/v3/reference/replies/list>.
2856              
2857             =head2 C<update_reply>
2858              
2859             my $reply = $gd->update_reply( $fileId, $commentId, $replyId, {%params} );
2860              
2861             This serves the path to C</files/$fileId/comments/$commentId/replies/$replyId>.
2862              
2863             This is also known as C<replies.update>.
2864              
2865             You can read about the parameters on the Google Drive
2866             L<API page|https://developers.google.com/drive/api/v3/reference/replies/update>.
2867              
2868             =head2 C<delete_revision>
2869              
2870             $gd->delete_revision( $fileId, {%params} );
2871              
2872             This serves the path to C</files/$fileId/revisions/$revisionId>.
2873              
2874             This is also known as C<revisions.delete>.
2875              
2876             You can read about the parameters on the Google Drive
2877             L<API page|https://developers.google.com/drive/api/v3/reference/revisions/delete>.
2878              
2879             =head2 C<get_revision( $fileId, $revisionId, $params )>
2880              
2881             my $revision = $gd->get_revision( $fileId, $revisionId, {%params} );
2882              
2883             Parameters are optional.
2884              
2885             This serves the path to C</files/$fileId/revisions/$revisionId>.
2886              
2887             This is also known as C<revisions.get>.
2888              
2889             You can read about the parameters on the Google Drive
2890             L<API page|https://developers.google.com/drive/api/v3/reference/revisions/get>.
2891              
2892             =head2 C<revisions>
2893              
2894             my $revisions = $gd->revisions( $fileId, {%params} );
2895              
2896             Parameters are optional.
2897              
2898             This serves the path to C</files/$fileId/revisions>.
2899              
2900             This is also known as C<revisions.list>.
2901              
2902             You can read about the parameters on the Google Drive
2903             L<API page|https://developers.google.com/drive/api/v3/reference/revisions/list>.
2904              
2905             =head2 C<update_revision>
2906              
2907             my $revision = $gd->update_revision( $fileId, $revisionId, {%params} );
2908              
2909             This serves the path to C</files/$fileId/revisions/$revisionId>.
2910              
2911             This is also known as C<revisions.update>.
2912              
2913             You can read about the parameters on the Google Drive
2914             L<API page|https://developers.google.com/drive/api/v3/reference/revisions/update>.
2915              
2916             =head2 C<create_drive>
2917              
2918             my $drive = $gd->create_drive({%params});
2919              
2920             This serves the path to C</drives>.
2921              
2922             This is also known as C<drives.create>.
2923              
2924             You can read about the parameters on the Google Drive
2925             L<API page|https://developers.google.com/drive/api/v3/reference/drives/create>.
2926              
2927             =head2 C<delete_drive>
2928              
2929             $gd->delete_drive($driveId);
2930              
2931             This serves the path to C</drives/$driveId>.
2932              
2933             This is also known as C<drives.delete>.
2934              
2935             You can read about the parameters on the Google Drive
2936             L<API page|https://developers.google.com/drive/api/v3/reference/drives/delete>.
2937              
2938             =head2 C<get_drive>
2939              
2940             my $drive = $gd->get_drive( $driveId, {%params} );
2941              
2942             Parameters are optional.
2943              
2944             This serves the path to C</drives/$driveId>.
2945              
2946             This is also known as C<drives.get>.
2947              
2948             You can read about the parameters on the Google Drive
2949             L<API page|https://developers.google.com/drive/api/v3/reference/drives/get>.
2950              
2951             =head2 C<hide_drive>
2952              
2953             my $drive = $gd->hide_drive($driveId);
2954              
2955             This serves the path to C</drives/$driveId/hide>.
2956              
2957             This is also known as C<drives.hide>.
2958              
2959             You can read about the parameters on the Google Drive
2960             L<API page|https://developers.google.com/drive/api/v3/reference/drives/hide>.
2961              
2962             =head2 C<drives>
2963              
2964             my $drives = $gd->drives({%params});
2965              
2966             Parameters are optional.
2967              
2968             This serves the path to C</drives>.
2969              
2970             This is also known as C<drives.list>.
2971              
2972             You can read about the parameters on the Google Drive
2973             L<API page|https://developers.google.com/drive/api/v3/reference/drives/list>.
2974              
2975             =head2 C<unhide_drive>
2976              
2977             my $drive = $gd->unhide_drive($driveId);
2978              
2979             This serves the path to C</drives/$driveId/unhide>.
2980              
2981             This is also known as C<drives.unhide>.
2982              
2983             You can read about the parameters on the Google Drive
2984             L<API page|https://developers.google.com/drive/api/v3/reference/drives/unhide>.
2985              
2986             =head2 C<update_drive>
2987              
2988             my $drive = $gd->update_drive( $driveId, {%params} );
2989              
2990             This serves the path to C</drives/$driveId>.
2991              
2992             This is also known as C<drives.update>.
2993              
2994             You can read about the parameters on the Google Drive
2995             L<API page|https://developers.google.com/drive/api/v3/reference/drives/update>.
2996              
2997             =head2 C<children>
2998              
2999             my $children = $gd->children( '/path/to', {%params}, {%extra_params} )>
3000              
3001             The parameters and extra parameters are both optional.
3002              
3003             Return the entries under a given path on the Google Drive as a reference
3004             to an array. Each entry
3005             is an object composed of the JSON data returned by the Google Drive API.
3006             Each object offers methods named like the fields in the JSON data, e.g.
3007             C<originalFilename()>, C<downloadUrl>, etc.
3008              
3009             Will return all entries found unless C<pageSize> is set:
3010              
3011             my $children = $gd->children( "/path/to", { pageSize => 3 } )
3012              
3013             Due to the somewhat capricious ways Google Drive handles its directory
3014             structures, the method needs to traverse the path component by component
3015             and determine the ID of each directory to get to the next level. To speed
3016             up subsequent lookups, it also returns the ID of the last component to the
3017             caller:
3018              
3019             my( $children, $parent ) = $gd->children( "/path/to" );
3020              
3021             If the caller now wants to e.g. insert a file into the directory, its
3022             ID is available in $parent.
3023              
3024             Each child comes back as a files#resource type and gets mapped into
3025             an object that offers access to the various fields via methods:
3026              
3027             for my $child ( @$children ) {
3028             print $child->kind(), " ", $child->name(), "\n";
3029             }
3030              
3031             Please refer to
3032              
3033             https://developers.google.com/drive/v3/reference/files#resource
3034              
3035             for details on which fields are available.
3036              
3037             =head2 C<children_by_folder_id>
3038              
3039             my $children = $gd->children_by_folder_id($folderId);
3040              
3041             # Search with a particular query and stop at the first page
3042             my $children = $gd->children_by_folder_id(
3043             $folderId,
3044             { 'q' => q{name contains 'hello'} },
3045             { 'auto_paging' => 0 },
3046             );
3047              
3048             Similar to C<children()> but uses a folder ID.
3049              
3050             The second parameter is the parameters the C<files()> method receives.
3051              
3052             The third parameter is for additional options on how to conduct this
3053             search. Only one option is supported: C<auto_paging>.
3054              
3055             When C<auto_paging> is turned on (which is the default), the search
3056             will be done on every page of the results instead of stopping at the
3057             first page.
3058              
3059             =head1 UPLOADING
3060              
3061             Uploading of a 5 MB file or lower is simple, but uploading a larger
3062             file is more difficult. This module supports every possible option,
3063             including connecting uploads to a different systems.
3064              
3065             =head2 SIMPLE AND EASY UPLOADING
3066              
3067             If you are not interested in all the details and finer controls of
3068             uploading files, you can just use C<upload_file>.
3069              
3070             my $data = $gd->upload_file( $filename, {%params} );
3071              
3072             The parameters are optional and you can read more about them in
3073             the appropriate
3074             L<API page|https://developers.google.com/drive/api/v3/reference/files/create>.
3075              
3076             The disadvantages are that you cannot control how much is uploaded
3077             at a time, it's not resumable, nor coudl you connect it with an
3078             event loop.
3079              
3080             However, this has no size limitations other than 5120 GB.
3081              
3082             =head2 UPLOADING FILES 5 MB OR SMALLER
3083              
3084             When uploading 5 MB and under, you can either use C<create_file()>
3085             for metadata or C<upload_media_file()> for both metadata and content.
3086              
3087             Despite the name, you may upload any form of file, not just media
3088             files. (This is the name Google provides this form of upload.)
3089              
3090             # Create only the metadata
3091             my $data = $gd->create_file({
3092             'name' => 'foo.txt',
3093             'mediaType' => 'text/plain',
3094             })
3095              
3096             Once you call C<create_file()>, you can use the ID of the response
3097             in subsequent calls to C<upload_media_file()> or
3098             C<upload_multipart_file()>. (This might work for resumable uploads
3099             too, but it's not tested.)
3100              
3101             # Upload just the file
3102             $data = $gd->upload_media_file('foo.txt');
3103             $data = $gd->upload_media_file( 'foo.txt', { 'name' => 'bar.txt' } );
3104              
3105             The only supported parameters are the query parameters.
3106              
3107             # Upload the file and all the metadata
3108             $data = $gd->upload_multipart_file( 'foo.txt', {...} );
3109              
3110             The difference between C<upload_media_file()> and
3111             C<upload_multipart_file()> is that the former method allows the query
3112             parameters, but the latter method allows all options.
3113              
3114             You can read more about the available options for either of these
3115             file uploads
3116             L<here|https://developers.google.com/drive/api/v3/reference/files/create>.
3117              
3118             =head2 UPLOADING FILES ABOVE 5 MB
3119              
3120             When uploading files above 5 MB, you must first create a URI for the
3121             file upload and then upload to that URI with another method.
3122              
3123             There are two ways to create it, depending on whether you have a file
3124             available on disk or not.
3125              
3126             # Creating the URI using a file
3127             my $upload_uri = $gd->create_resumable_upload_for( $file, {...} );
3128              
3129             # Creating the URI without a file
3130             my $upload_uri = $gd->create_resumable_upload({
3131             'name' => 'foo.txt',
3132             'mimeType' => 'text/plain',
3133             });
3134              
3135             The benefit of using C<create_resumable_upload_for()> is that it allows
3136             you to use an existing file's mime type and filename. Otherwise, if you
3137             use the low-level C<create_resumable_upload()>, you will need to provide
3138             the C<name> and C<mediaType> parameters yourself.
3139              
3140             There are three different methods for uploading - choose the one that
3141             suits you best.
3142              
3143             # Just upload the entire file
3144             my $data = upload_file_content_single( $upload_uri, $file );
3145              
3146             This upload will still try to chunk it by 4K so it doesn't load the
3147             entire file into memory. The biggest downside of this method is that
3148             if the file fails, it fully fails and you have to start from scratch.
3149              
3150             # Upload the file in resumable chunks
3151             my $data = upload_file_content_multiple(
3152             $upload_uri, $file, $optional_chunk_size,
3153             );
3154              
3155             This method will attempt to upload the file in chunks of 10 MB (or a
3156             whatever chunk size you ask for - in bytes) until it successfully
3157             finishes. If it fails, you might be able to resume. However, resuming
3158             is not yet supported within the API, sorry.
3159              
3160             =head2 UPLOADING FILES WITH EVENT LOOPS
3161              
3162             If you want to connect file uploading to an event loop, you can use
3163             C<upload_file_content_iterator()> to receive an iterator which will
3164             generate a proper L<HTTP::Request> object you can then use in the
3165             event loop request.
3166              
3167             my $iterator = upload_file_content_iterator(
3168             $upload_uir, $file, $optional_chunk_size,
3169             );
3170              
3171             while ( my $request = $iter->() ) {
3172             my $response = do_something_with_request($request);
3173              
3174             # $response->code() == 200 - Done
3175             # $response->code() == 308 - Keep going
3176             # anything else - Probably some form of error
3177             }
3178              
3179             There is currently no sample code for any particular event loop.
3180              
3181             =head1 LEGALESE
3182              
3183             Copyright 2012-2019 by Mike Schilli, all rights reserved.
3184             This program is free software, you can redistribute it and/or
3185             modify it under the same terms as Perl itself.
3186              
3187             =head1 AUTHOR
3188              
3189             Sawyer X <xsawyerx@cpan.org>