File Coverage

blib/lib/WWW/Spotify/Client.pm
Criterion Covered Total %
statement 17 89 19.1
branch 0 28 0.0
condition 0 2 0.0
subroutine 6 9 66.6
pod 0 3 0.0
total 23 131 17.5


line stmt bran cond sub pod time code
1             package WWW::Spotify::Client;
2             our $VERSION = '0.014';
3 4     4   54222 use 5.012;
  4         15  
4 4     4   21 use strict;
  4         9  
  4         113  
5 4     4   16 use warnings;
  4         7  
  4         237  
6              
7 4     4   27 use Moo::Role;
  4         8  
  4         52  
8              
9 4     4   2304 use MIME::Base64 qw( encode_base64 );
  4         9  
  4         385  
10 4     4   27 use JSON::MaybeXS qw( decode_json );
  4         8  
  4         5469  
11              
12             #--------------------------------------------------------------------------
13             # Requirements – attributes/methods that must be supplied by the consuming
14             # class (WWW::Spotify).
15             #--------------------------------------------------------------------------
16              
17             requires qw(
18             oauth_client_id
19             oauth_client_secret
20             oauth_authorize_url
21             oauth_token_url
22             oauth_redirect_uri
23             current_oauth_code
24             current_access_token
25             ua
26             _mech
27             debug
28             );
29              
30             #--------------------------------------------------------------------------
31             # Authentication helpers migrated from the original monolithic module.
32             #--------------------------------------------------------------------------
33              
34             sub get_oauth_authorize {
35 0     0 0   my $self = shift;
36              
37 0 0         if ( $self->current_oauth_code() ) {
38 0           return $self->current_oauth_code();
39             }
40              
41 0           my $grant_type = 'authorization_code';
42 0           my $client_and_secret
43             = $self->oauth_client_id() . ':' . $self->oauth_client_secret();
44 0           my $encoded = encode_base64($client_and_secret);
45 0           chomp($encoded);
46 0           $encoded =~ s/\n//g;
47 0           my $url = $self->oauth_authorize_url();
48              
49 0           my @parts;
50              
51 0           $parts[0] = 'response_type=code';
52 0           $parts[1] = 'redirect_uri=' . $self->oauth_redirect_uri;
53              
54 0           my $params = join( '&', @parts );
55 0           $url = $url . '?client_id=' . $self->oauth_client_id() . "&$params";
56              
57 0           $self->ua->get($url);
58              
59 0           return $self->ua->content;
60             }
61              
62             sub get_client_credentials {
63 0     0 0   my $self = shift;
64 0           my $scope = shift;
65              
66 0 0         if ( $self->current_access_token() ne q{} ) {
67 0           return $self->current_access_token();
68             }
69 0 0         if ( $self->oauth_client_id() eq q{} ) {
70 0           die "need to set the client oauth parameters\n";
71             }
72              
73 0           my $grant_type = 'client_credentials';
74 0           my $mech = $self->_mech;
75 0           my $client_and_secret
76             = $self->oauth_client_id() . ':' . $self->oauth_client_secret();
77 0           my $encoded = encode_base64($client_and_secret);
78 0           my $url = $self->oauth_token_url();
79              
80 0           my $extra = { grant_type => $grant_type };
81 0 0         if ($scope) {
82 0           $extra->{scope} = $scope;
83             }
84              
85 0           chomp($encoded);
86 0           $encoded =~ s/\n//g;
87 0           $mech->add_header( 'Authorization' => 'Basic ' . $encoded );
88              
89 0           $mech->post( $url, [$extra] );
90 0           my $content = $mech->content();
91              
92 0 0         if ( $content =~ /access_token/ ) {
93 0 0         warn "setting access token\n" if $self->debug();
94              
95 0           my $result = decode_json $content;
96              
97 0 0         if ( $result->{'access_token'} ) {
98 0           $self->current_access_token( $result->{'access_token'} );
99             }
100             }
101             }
102              
103             sub get_access_token {
104 0     0 0   my $self = shift;
105 0           my $grant_type = 'authorization_code';
106 0           my $scope = shift;
107              
108 0           my @scopes = (
109             'playlist-modify', 'playlist-modify-private',
110             'playlist-read-private', 'streaming',
111             'user-read-private', 'user-read-email'
112             );
113              
114 0 0         if ($scope) {
115 0           my $good_scope = 0;
116 0           foreach my $s (@scopes) {
117 0 0         if ( $scope eq $s ) {
118 0           $good_scope = 1;
119 0           last;
120             }
121             }
122 0 0         if ( $good_scope == 0 ) {
123 0           $scope = q{};
124             }
125             }
126              
127 0   0       $grant_type ||= 'authorization_code';
128              
129 0           my $client_and_secret
130             = $self->oauth_client_id() . ':' . $self->oauth_client_secret();
131              
132 0           my $encoded = encode_base64($client_and_secret);
133 0           chomp($encoded);
134 0           $encoded =~ s/\n//g;
135              
136 0           my $url = $self->oauth_token_url;
137              
138 0           my $extra = {
139             grant_type => $grant_type,
140             code => $self->current_oauth_code(),
141             redirect_uri => $self->oauth_redirect_uri
142             };
143 0 0         if ($scope) {
144 0           $extra->{scope} = $scope;
145             }
146              
147 0           my $mech = $self->_mech;
148 0           $mech->add_header( 'Authorization' => 'Basic ' . $encoded );
149              
150 0           $mech->post( $url, [$extra] );
151              
152 0           my $content = $mech->content();
153 0 0         warn "get_access_token response: $content\n" if $self->debug();
154              
155 0 0         if ( $content =~ /access_token/ ) {
156 0           my $result = decode_json($content);
157 0 0         if ( $result->{'access_token'} ) {
158 0           $self->current_access_token( $result->{'access_token'} );
159             }
160 0           return $result;
161             }
162              
163 0           return;
164             }
165              
166             1;
167              
168             # ABSTRACT: Spotify authentication logic (extracted into a role)
169              
170             # vim: ts=4 sts=4 sw=4 et
171              
172             __END__