File Coverage

blib/lib/Net/Zendesk.pm
Criterion Covered Total %
statement 50 76 65.7
branch 36 62 58.0
condition 6 29 20.6
subroutine 6 10 60.0
pod 3 4 75.0
total 101 181 55.8


line stmt bran cond sub pod time code
1             package Net::Zendesk;
2 2     2   133843 use strict;
  2         14  
  2         63  
3 2     2   10 use warnings;
  2         3  
  2         60  
4 2     2   1013 use MIME::Base64;
  2         1438  
  2         118  
5 2     2   953 use JSON::MaybeXS;
  2         15840  
  2         2525  
6              
7             our $VERSION = '0.02';
8              
9             sub new {
10 1     1 0 614 my ($class, %args) = @_;
11             die 'please provide a zendesk domain name (e.g. domain => "obscura.zendesk.com")'
12 1 50 33     18 unless $args{domain} && $args{domain} =~ /\.zendesk\.com\z/ && $args{domain} !~ m{/};
      33        
13              
14             die 'sorry! only API version 2 is supported at the moment'
15 1 50 33     6 if exists $args{api} && $args{api} != 2;
16              
17 1 50       3 die 'please provide the email of a valid zendesk account' unless $args{email};
18 1 50       4 if ($args{token}) {
    0          
19 1         5 $args{auth} = "$args{email}/token:$args{token}";
20             }
21             elsif ($args{password}) {
22 0         0 $args{auth} = "$args{email}:$args{password}";
23             }
24             else {
25 0         0 die 'please provide a password or a token for zendesk authentication. Oauth is not yet supported by this module';
26             }
27              
28             return bless {
29             _domain => $args{domain},
30             _api => $args{api},
31             _auth => MIME::Base64::encode($args{auth}),
32             _ua => $args{ua} || undef,
33 1   50     18 }, $class;
34             }
35              
36             sub create_ticket {
37 0     0 1 0 my ($self, $ticket, %extra) = @_;
38 0         0 my $path = 'tickets.json';
39 0 0       0 if (%extra) {
40 0         0 $path .= '?' . join('&', map("$_=$extra{$_}", keys %extra));
41             }
42 0         0 return $self->make_request('POST', $path, { ticket => $ticket });
43             }
44              
45             sub search {
46 0     0 1 0 my ($self, $search_args) = @_;
47 0         0 my $parsed_args = $self->_parse_search_args($search_args);
48              
49 0         0 require URI::Escape;
50 0         0 my $query = URI::Escape::uri_escape(join(' ' => @$parsed_args));
51              
52 0         0 return $self->make_request('GET', 'search.json?query=' . $query, {});
53             }
54              
55             sub make_request {
56 0     0 1 0 my ($self, $type, $path, $params) = @_;
57 0 0 0     0 die 'please provide a type' unless $type
      0        
58             && ($type eq 'GET' || $type eq 'POST' || $type eq 'PUT' || $type eq 'DELETE');
59 0 0 0     0 die 'please provide a relative path' unless $path && $path !~ m{\A/api};
60 0 0 0     0 die 'please provide a HASHREF with parameters' unless $params && ref $params eq 'HASH';
61 0         0 my $method = lc $type;
62             return $self->_ua->$method(
63 0 0 0     0 'https://' . $self->{_domain} . '/api/v2/' . $path,
64             [
65             ($method eq 'post' || $method eq 'put'
66             ? ('Content-Type' => 'application/json') : ()
67             ),
68             ],
69             encode_json($params),
70             );
71             }
72              
73             sub _parse_search_args {
74 20     20   10117 my ($self, $search_args) = @_;
75 20         32 my @query;
76 20         63 foreach my $keyword (keys %$search_args) {
77 20 50       74 die "Net::Zendesk: malformed search keyword '$keyword' contains spaces"
78             if $keyword =~ /\s/;
79 20         32 my $value = $search_args->{$keyword};
80 20 100       45 if (ref $value) {
81 15 100       39 if (ref $value eq 'HASH') {
    50          
82 13         27 foreach my $inner_key (keys %$value) {
83 15         60 my %tokens = (
84             '=' => ':',
85             '>' => '>',
86             '<' => '<',
87             '>=' => '>=',
88             '<=' => '<=',
89             '!=' => ':',
90             'or' => ':',
91             'and' => ':',
92             );
93 15 50       31 die "Net::Zendesk: invalid token '$inner_key' for keyword '$keyword'. Available tokens are " . join(', ', keys %tokens) unless exists $tokens{$inner_key};
94              
95 15         23 my $inner_value = $value->{$inner_key};
96 15 100       29 $inner_value = 'none' unless defined $inner_value;
97              
98 15 100       27 if (ref $inner_value) {
99 3 50       27 die 'Net::Zendesk: only scalar values or ARRAY references are supported. Got ' . ref($inner_value) . " for keyword '$keyword' under '$inner_key'." unless ref $inner_value eq 'ARRAY';
100 3 100 66     17 if ($inner_key eq 'and') {
    50          
101             push @query, $keyword . ':'
102             . join ' ', map {
103 1 50       4 defined $_ ? $_ =~ /\s/ ? qq("$_") : $_ : 'none'
  2 100       15  
104             } @$inner_value;
105             }
106             elsif ($inner_key eq '=' || $inner_key eq 'or') {
107 2         6 foreach my $or (@$inner_value) {
108 4 100       9 $or = 'none' unless defined $or;
109 4 50       8 $or = qq("$or") if $or =~ /\s/;
110 4         18 push @query, "$keyword$tokens{$inner_key}$or";
111             }
112             }
113             else {
114 0         0 die 'Net::Zendesk: only =,and,or tokens are allowed for references';
115             }
116             }
117             else {
118 12 100       31 $inner_value = qq("$inner_value") if $inner_value =~ /\s/;
119 12 100       65 push @query, ($inner_key eq '!=' ? '-' : '')
120             . "$keyword$tokens{$inner_key}$inner_value";
121             }
122             }
123             }
124             elsif (ref $value eq 'ARRAY') {
125 2         5 foreach my $or (@$value) {
126 4 100       10 $or = 'none' unless defined $or;
127 4 50       11 $or = qq("$or") if $or =~ /\s/;
128 4         11 push @query, "$keyword:$or";
129             }
130             }
131             else {
132 0         0 die 'Net::Zendesk: unsuported reference ' . ref($value) . '. Please use either a scalar or an ARRAY/HASH reference as a value for ' . $keyword;
133             }
134             }
135             else {
136 5 100       12 $value = 'none' unless defined $value;
137 5 100       15 $value = qq("$value") if $value =~ /\s/;
138 5         18 push @query, "$keyword:$value";
139             }
140             }
141 20         67 return \@query;
142             }
143              
144             sub _ua {
145 0     0     my ($self) = @_;
146 0 0         return $self->{_ua} if $self->{_ua};
147 0           require Furl;
148 0           require IO::Socket::SSL;
149 0           IO::Socket::SSL->import;
150             $self->{_ua} = Furl->new(
151             headers => [
152             'Accept' => 'application/json',
153             'Authorization' => 'Basic ' . $self->{_auth},
154 0           ],
155             ssl_opts => {
156             SSL_verify_mode => SSL_VERIFY_PEER(),
157             },
158             );
159             }
160              
161             1;
162             __END__