File Coverage

blib/lib/WebService/Slack/WebApi/Files.pm
Criterion Covered Total %
statement 77 107 71.9
branch 12 38 31.5
condition 3 15 20.0
subroutine 14 15 93.3
pod 0 7 0.0
total 106 182 58.2


line stmt bran cond sub pod time code
1             package WebService::Slack::WebApi::Files;
2 3     3   3965 use strict;
  3         10  
  3         182  
3 3     3   21 use warnings;
  3         7  
  3         256  
4 3     3   22 use utf8;
  3         17  
  3         23  
5 3     3   153 use feature qw/state/;
  3         6  
  3         461  
6 3     3   26 use Data::Dumper qw/Dumper/;
  3         8  
  3         333  
7              
8 3     3   25 use parent 'WebService::Slack::WebApi::Base';
  3         6  
  3         22  
9              
10             use WebService::Slack::WebApi::Generator (
11 3         80 delete => {
12             file => 'Str',
13             },
14             info => {
15             file => 'Str',
16             count => { isa => 'Int', optional => 1 },
17             page => { isa => 'Int', optional => 1 },
18             },
19             list => {
20             channel => { isa => 'Str', optional => 1 },
21             count => { isa => 'Int', optional => 1 },
22             page => { isa => 'Int', optional => 1 },
23             ts_from => { isa => 'Str', optional => 1 },
24             ts_to => { isa => 'Str', optional => 1 },
25             types => { isa => 'Str', optional => 1 },
26             user => { isa => 'Str', optional => 1 },
27             },
28 3     3   980 );
  3         25  
29              
30             sub revoke_public_url {
31 1     1 0 52 state $rule = Data::Validator->new(
32             file => 'Str',
33             )->with('Method', 'AllowExtra');
34 1         2299 my ($self, $args, %extra) = $rule->validate(@_);
35              
36 1         147 return $self->request('revokePublicURL', {%$args, %extra});
37             }
38              
39             sub shared_public_url {
40 1     1 0 727 state $rule = Data::Validator->new(
41             file => 'Str',
42             )->with('Method', 'AllowExtra');
43 1         2094 my ($self, $args, %extra) = $rule->validate(@_);
44              
45 1         106 return $self->request('sharedPublicURL', {%$args, %extra});
46             }
47              
48             sub get_upload_url_external {
49 2     2 0 815 state $rule = Data::Validator->new(
50             filename => 'Str',
51             length => 'Int',
52             )->with('Method', 'AllowExtra');
53 2         2217 my ($self, $args, %extra) = $rule->validate(@_);
54              
55 2         268 return $self->request('getUploadURLExternal', {%$args, %extra});
56             }
57              
58             sub send_file_to_external_url {
59 1     1 0 3 my ($self, $url, $params) = @_;
60              
61 1         3 my %headers;
62 1 50 33     4 if( $self->client->token && $params->{'http_auth'} ) {
63 0         0 my $msg = 'Illegal parameters. You have defined \'token\' but the '
64             . ' method you are using defines its own HTTP Authorization header.';
65 0         0 WebService::Slack::WebApi::Exception::IllegalParameters->throw(
66             message => $msg,
67             );
68             }
69 1 50       16 if (exists $params->{file_type}) {
70 1         5 $headers{'Content-type'} = $params->{file_type};
71             } else {
72 0         0 $headers{'Content-type'} = 'application/octet-stream';
73             }
74              
75 1 50       4 if( $self->client->token ) {
    0          
76 1         29 $headers{'Authorization'} = 'Bearer ' . $self->client->token;
77             } elsif( $params->{'http_auth'} ) {
78 0         0 $headers{'Authorization'} = $params->{'http_auth'};
79             }
80            
81             my %options = (
82             headers => \%headers,
83             content => $params->{file},
84 1         13 );
85            
86 1         3 my $response = $self->client->ua->request(
87             'POST',
88             $url,
89             \%options
90             );
91 1 50       61 return if $response->{success};
92              
93 0         0 WebService::Slack::WebApi::Exception::FailureResponse->throw(
94             message => 'file upload failed.',
95             response => $response,
96             );
97             }
98              
99             sub complete_upload_external {
100 2     2 0 806 state $rule = Data::Validator->new(
101             files => 'ArrayRef[HashRef]',
102             channels => { isa => 'ArrayRef[Str]', optional => 1 },
103             channel_id => { isa => 'Str', optional => 1 },
104             initial_comment => { isa => 'Str', optional => 1 },
105             thread_ts => { isa => 'Str', optional => 1 },
106             )->with('Method', 'AllowExtra');
107 2         2895 my ($self, $args, %extra) = $rule->validate(@_);
108              
109 2 50       290 $args->{channels} = join ',', @{$args->{channels}} if exists $args->{channels};
  0         0  
110              
111 2         21 return $self->request_json('completeUploadExternal', {%$args, %extra});
112             }
113              
114             # FIXME: maybe be broken... https://github.com/mihyaeru21/p5-WebService-Slack-WebApi/issues/15
115             # Will STOP Working by Slack on 2025-03-11
116             sub upload {
117 1     1 0 743 state $rule = Data::Validator->new(
118             channels => { isa => 'ArrayRef[Str]', optional => 1 },
119             content => { isa => 'Str', optional => 1 },
120             file => { isa => 'Str', optional => 1 },
121             filename => { isa => 'Str', optional => 1 },
122             filetype => { isa => 'Str', optional => 1 },
123             initial_comment => { isa => 'Str', optional => 1 },
124             title => { isa => 'Str', optional => 1 },
125             )->with('Method', 'AllowExtra');
126 1         2547 my ($self, $args, %extra) = $rule->validate(@_);
127              
128 1 50       237 $args->{file} = [$args->{file}] if exists $args->{file};
129 1 50       6 $args->{channels} = join ',', @{$args->{channels}} if exists $args->{channels};
  1         6  
130              
131 1         12 return $self->request('upload', {%$args, %extra});
132             }
133              
134             =item $ _check_response(response =>, to =>, from =>, text =>, channel_not_found =>)
135              
136             Internal method.
137              
138             Checks the response from slack for the ok value and looks for error and warning values.
139              
140             It will die if it's an error or ok not found.
141              
142             The to, from and optional text values are included in the output to help troubleshoot.
143              
144             If the error is 'channel_not_found' we call the 'channel_not_found' provided subroutine so the
145             caller can handle sending to their custom error slack channel, etc.
146            
147             Returns the following status code:
148             0 - okay
149             1 - warning found
150             2 - channel_not_found encountered and message was sent to the error channel successfully
151              
152             =cut
153             sub _check_response
154             {
155 0     0   0 my $self = shift;
156 0         0 my %args = ( @_ );
157 0         0 my $response = $args{response};
158 0         0 my $to = $args{to};
159 0         0 my $from = $args{from};
160 0         0 my $text = $args{text}; # can be undef.
161 0         0 my $channel_not_found = $args{channel_not_found};
162            
163 0 0 0     0 die "ERROR: channel_not_found must be a CODE ref!" if (!defined $channel_not_found || (defined $channel_not_found && ref($channel_not_found) ne "CODE"));
      0        
164            
165 0 0       0 if (! exists $response->{ok})
166             {
167 0         0 die "ERROR: _check_response(): ok field not found in slack response hash! to='$to', from='$from'\n" . Dumper($response);
168             }
169             else
170             {
171 0 0       0 if ($response->{ok})
172             {
173 0 0       0 if (exists $response->{warning})
174             {
175 0         0 return 1;
176             }
177             else
178             {
179 0         0 return 0;
180             }
181             }
182             else
183             {
184 0 0       0 if ($response->{error} eq 'channel_not_found')
185             {
186 0         0 my $code = $channel_not_found->(
187             $self,
188             response => $response,
189             to => $to,
190             from => $from,
191             text => $text
192             );
193            
194 0 0       0 return 2 if ($code == 0);
195 0         0 return $code; # default to pass through the error returned from $channel_not_found
196             }
197             else
198             {
199 0         0 die "ERROR: _check_response(): ok is false and error='$response->{error}'! to='$to', from='$from'\n" . Dumper($response);
200             }
201             }
202             }
203             }
204              
205             # This is a helper method that wraps get_upload_url_external(), post_file_to_external_url()
206             # and complete_upload_external() calls for the caller. They have to provide everything necessary
207             # though.
208             # Returns an array with $code and $response.
209             # $code = 0, 1 or 2 to indicate if it succeeded or 'channel_not_found' handler was called.
210             # $response = last response message returned in the process
211             sub upload_v2 {
212 1     1 0 754 my $self = shift;
213 1         10 my $args = { error_handler => \&_check_response, @_ };
214 1         3 my $channel = $args->{channel}; # slack channel name
215 1         2 my $channel_id = $args->{channel_id}; # internal slack channel id
216 1         3 my $file_contents = $args->{file_contents}; # contents of the file to upload
217 1         2 my $file_type = $args->{file_type}; # type of the file
218 1         2 my $file_length = $args->{file_length}; # length of the file in bytes
219 1         3 my $filename = $args->{filename}; # what you want the file to be named in Slack
220 1         2 my $from = $args->{from}; # who we say this message is from
221 1         2 my $message = $args->{message}; # the message you want associated with the file in slack.
222 1         3 my $callingObj = $args->{callingObj}; # instance of the caller that $error_handler and
223             # $channel_not_found need passed in as $self.
224 1         2 my $error_handler = $args->{error_handler}; # sub you should call to validate the returned info
225             #is valid. Takes the following parameters:
226             # response =>, to, from, message, channel_not_found
227             # and returns 0 if ok, 1 otherwise. Can die if a fatal error is encountered.
228 1         2 my $channel_not_found = $args->{channel_not_found};
229 1         2 my $code; # tracks the error_handler result.
230            
231 1 50       7 if (!defined $error_handler) {
232 0         0 die "upload_v2(): error_handler must be defined!";
233             }
234 1 50 33     8 if (defined $error_handler && ref($error_handler) ne 'CODE') {
235 0         0 die "upload_v2(): error_handler is not a CODE ref! You provided: " . ref($error_handler);
236             }
237            
238 1 50       4 if (!defined $channel_not_found) {
239 0         0 die "upload_v2(): channel_not_found must be defined!";
240             }
241 1 50 33     5 if (defined $channel_not_found && ref($channel_not_found) ne 'CODE') {
242 0         0 die "upload_v2(): channel_not_found is not a CODE ref! You provided: " . ref($channel_not_found);
243             }
244              
245 1         25 my $external_url_response = $self->get_upload_url_external(
246             filename => $filename,
247             length => $file_length
248             );
249 1         8 $code = $error_handler->(
250             $callingObj,
251             response => $external_url_response,
252             to => $channel,
253             from => $from,
254             text => $message,
255             channel_not_found => $channel_not_found,
256             );
257            
258 1 50       7 if ($code == 0) {
259             # we got a valid response and can proceed.
260 1         3 my $url = $external_url_response->{upload_url};
261 1         3 my $file_id = $external_url_response->{file_id};
262            
263 1         8 $self->send_file_to_external_url($url,
264             {
265             file => $file_contents,
266             file_type => $file_type
267             }
268             );
269            
270 1         8 my $complete_upload_response = $self->complete_upload_external(
271             files => [
272             {
273             id => $file_id,
274             title => $filename
275             },
276             ],
277             channel_id => $channel_id,
278             initial_comment => $message,
279             );
280 1         7 $code = $error_handler->(
281             $callingObj,
282             response => $complete_upload_response,
283             to => $channel,
284             from => $from,
285             text => $message,
286             channel_not_found => $channel_not_found,
287             );
288            
289 1         14 return ($code, $complete_upload_response);
290             }
291            
292 0           return ($code, $external_url_response);
293             }
294              
295             1;
296