File Coverage

blib/lib/WebService/Xential.pm
Criterion Covered Total %
statement 71 95 74.7
branch 10 30 33.3
condition n/a
subroutine 16 21 76.1
pod 9 10 90.0
total 106 156 67.9


line stmt bran cond sub pod time code
1             package WebService::Xential;
2             our $VERSION = '0.004';
3 2     2   1007625 use v5.26;
  2         5  
4 2     2   1683 use Object::Pad;
  2         25264  
  2         33  
5              
6             # ABSTRACT: A Xential REST API module
7              
8             class WebService::Xential;
9 2     2   958 use Carp qw(croak);
  2         5  
  2         105  
10 2     2   794 use OpenAPI::Client;
  2         687435  
  2         29  
11 2     2   1331 use Try::Tiny;
  2         3405  
  2         199  
12 2     2   17 use Mojo::Content::Single;
  2         4  
  2         23  
13 2     2   70 use Mojo::Asset::Memory;
  2         4  
  2         20  
14 2     2   1563 use JSON::XS qw(encode_json);
  2         5081  
  2         153  
15 2     2   13 use Types::Serialiser qw();
  2         4  
  2         4996  
16              
17             field $api_key :param;
18             field $api_user :param;
19 0 0   0 1 0 field $api_host :param :accessor;
  0         0  
20             field $api_port :param = undef;
21             field $api_path :param = '/xential/modpages/next.oas/api';
22 1 50   1 1 4958 field $client :accessor;
  1         8  
23              
24              
25             ADJUST {
26              
27             my $definition = sprintf('data://%s/xential.json', ref $self);
28              
29             $client = OpenAPI::Client->new($definition);
30              
31             my $host = Mojo::URL->new();
32             $host->scheme('https');
33             $host->host($api_host);
34             $host->path($api_path);
35              
36             $client->base_url($host);
37              
38             $client->ua->on(
39             start => sub ($ua, $tx) {
40              
41             $tx->req->headers->add("Accept" => "application/json");
42              
43             unless ($tx->req->headers->header('XSessionID')) {
44             $tx->req->url->userinfo("$api_user:$api_key");
45             }
46             }
47             );
48              
49             $client->ua->transactor->add_generator(
50             'createData' => \&create_ticket_data);
51             }
52              
53             sub create_ticket_data {
54 1     1 0 41 my $t = shift;
55 1         4 my $tx = shift;
56              
57 1         12 $tx->req->headers->content_type('multipart/form-data');
58 1         157 my $headers = $tx->req->headers;
59              
60 1         15 my $data = shift;
61              
62 1         36 my $xml = Mojo::Content::Single->new();
63 1         35 my $options = Mojo::Content::Single->new();
64              
65             $options->asset(
66             Mojo::Asset::Memory->new->add_chunk(
67             encode_json($data->{options})
68 1         33 )
69             );
70              
71 1         101 $xml->asset(Mojo::Asset::Memory->new->add_chunk($data->{xml}));
72              
73 1         29 $options->headers->content_disposition('form-data; name="options"');
74 1         24 $xml->headers->content_disposition(
75             'form-data; name="ticketData"; filename="ticketData.xml"');
76 1         18 $xml->headers->content_type("text/xml");
77              
78 1         13 my @parts = ($options, $xml);
79              
80 1         4 $tx->req->content(
81             Mojo::Content::MultiPart->new(
82             headers => $headers,
83             parts => \@parts
84             )
85             );
86             }
87              
88              
89             method has_api_host {
90             return $api_host ? 1 : 0;
91             }
92              
93              
94              
95 2     2 1 18088 method whoami($session_id = undef) {
  2         17  
  2         6  
  2         4  
96 2 100       19 return $self->api_call('op_auth_whoami',
97             { $session_id ? (XSessionID => $session_id) : () });
98             }
99              
100              
101 0     0 1 0 method logout($session_id = undef) {
  0         0  
  0         0  
  0         0  
102 0 0       0 return $self->api_call('op_auth_logout',
103             { $session_id ? (XSessionID => $session_id) : () });
104             }
105              
106              
107 0     0 1 0 method impersonate($username = undef, $uuid = undef, $session_id = undef) {
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
108 0 0       0 return $self->api_call(
    0          
    0          
109             'op_auth_impersonate',
110             {
111             $username ? (userName => $username) : (),
112             $uuid ? (userUuid => $uuid) : (),
113             $session_id ? (XSessionID => $session_id) : (),
114             }
115             );
116             }
117              
118              
119 0     0 1 0 method create_ticket($xml, $options, $session_id = undef) {
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
120              
121 0 0       0 return $self->api_call(
122             'op_createTicket',
123             {
124             $session_id ? (XSessionID => $session_id) : (),
125             },
126             {
127             createData => {
128             options => $options,
129             xml => $xml,
130             }
131             }
132             );
133             }
134              
135              
136 1     1 1 7366 method start_document($url = undef, $uuid = undef, $session_id = undef) {
  1         6  
  1         3  
  1         2  
  1         4  
  1         2  
137 1 50       14 return $self->api_call(
    50          
    50          
138             'op_document_startDocument',
139             {
140             $session_id ? (XSessionID => $session_id) : (),
141             $uuid ? (ticketUuid => $uuid) : (),
142             $url ? (xmldataurl => $url) : (),
143             }
144             );
145             }
146              
147              
148 2     2 1 5999 method build_document($close, $uuid, $session_id = undef) {
  2         10  
  2         6  
  2         3  
  2         5  
  2         4  
149 2 100       22 return $self->api_call(
    50          
150             'op_document_buildDocument',
151             {
152             close => $close ? $Types::Serialiser::true : $Types::Serialiser::false,
153             documentUuid => $uuid,
154             $session_id ? (XSessionID => $session_id) : (),
155             }
156             );
157             }
158              
159              
160 1     1 1 3 method api_call($operation, $query, $content = {}) {
  1         4  
  1         3  
  1         2  
  1         3  
  1         2  
161              
162             my $tx = try {
163 1     1   80 $client->call($operation => $query, %$content);
164             }
165             catch {
166 0     0   0 die("Died calling Xential API with operation '$operation': $_", $/);
167 1         12 };
168              
169 1 50       77 if ($tx->error) {
170              
171             # Not found, no result
172 0 0       0 return if $tx->res->code == 404;
173              
174             # Any other error
175             croak(
176             sprintf(
177             "Error calling Xential API with operation '%s': '%s' (%s)",
178             $operation, $tx->result->body, $tx->error->{message}
179 0         0 ),
180             );
181             }
182              
183 1         69 return $tx->res->json;
184             }
185              
186              
187              
188             1;
189              
190             =pod
191              
192             =encoding UTF-8
193              
194             =head1 NAME
195              
196             WebService::Xential - A Xential REST API module
197              
198             =head1 VERSION
199              
200             version 0.004
201              
202             =head1 SYNOPSIS
203              
204             my $xential = WebService::Xential->new(
205             api_user => 'foo',
206             api_key => 'foo',
207             api_host => '127.0.0.1',
208             );
209              
210             my $who = $xential->whoami();
211             my $other = $xential->impersonate(..., $who->{XSessionId});
212             my $session_id = $other{XSessionID};
213              
214             my $ticket = $xential->create_ticket($xml, \%options, $session_id);
215             my $start = $xential->start_document(
216             $ticket->{startDocumentUrl},
217             $ticket->{ticketUuid},
218             $session_id
219             );
220              
221             # Status is either INVALID or VALID
222              
223             if ($start->{status} eq 'VALID') {
224             my $build = $xential->build_document(
225             1,
226             $start->{documentUuid},
227             $session_id
228             );
229              
230             if ($build->{status} eq 'done') {
231             # build succeeded
232             }
233             else {
234             # build failed
235             }
236             }
237             else {
238             use URI;
239             $uri = URI->new($start{resumeUrl});
240             $uri->scheme('https');
241             $uri->query_form($uri->query_form, afterOpenAction => 'close');
242             $uri->host($xential->api_host);
243             # redirect user to $uri
244             }
245              
246             =head1 DESCRIPTION
247              
248             This module implements the REST API of Xential.
249              
250             =head1 ATTRIBUTES
251              
252             =head2 api_host
253              
254             The API host of the Xential WebService
255              
256             =head2 client
257              
258             The L
259              
260             =head1 METHODS
261              
262             =head2 new()
263              
264             my $xential = WebService::Xential->new(
265             api_user => 'foo',
266             api_key => 'foo',
267             api_host => '127.0.0.1',
268             );
269              
270             =head2 has_api_host()
271              
272             Tells you if you have a custom API host defined
273              
274             =head2 whoami($session_id)
275              
276             Implements the whoami call from Xential
277              
278             =head2 logout($session_id)
279              
280             Implements the logout call from Xential
281              
282             =head2 impersonate($username, $user_uuid, $session_id)
283              
284             Implements the impersonate call from Xential
285              
286             =head2 create_ticket($xml, $options, $session_id)
287              
288             Implements the create_ticket call from Xential
289              
290             =head2 start_document($username, $user_uuid, $session_id)
291              
292             Implements the start_document call from Xential
293              
294             =head2 build_document($username, $user_uuid, $session_id)
295              
296             Implements the build_document call from Xential
297              
298             =head2 api_call($operation, $query, $content)
299              
300             A wrapper around the L function. Returns the JSON from
301             the endpoint.
302              
303             =head1 AUTHOR
304              
305             Wesley Schwengle
306              
307             =head1 COPYRIGHT AND LICENSE
308              
309             This software is Copyright (c) 2024 by Wesley Schwengle.
310              
311             This is free software, licensed under:
312              
313             The (three-clause) BSD License
314              
315             =cut
316              
317             __DATA__