Skip to content

Commit 70e6d12

Browse files
[Glos] Fetch jobs & job updates from Confirm using GraphQL
1 parent 9e4a674 commit 70e6d12

File tree

5 files changed

+835
-13
lines changed

5 files changed

+835
-13
lines changed

perllib/Integrations/Confirm.pm

+225
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,231 @@ sub perform_request {
289289
return $response;
290290
}
291291

292+
sub perform_request_graphql {
293+
my ($self, %args) = @_;
294+
295+
my $uri = URI->new( $self->config->{graphql_url} );
296+
my $request = HTTP::Request->new(
297+
'POST',
298+
$uri,
299+
);
300+
$request->header(
301+
Authorization => 'Basic '
302+
. $self->config->{graphql_key}
303+
);
304+
$request->content_type('application/json; charset=UTF-8');
305+
306+
my $query;
307+
if ( $args{type} eq 'job_types' ) {
308+
$query = $self->job_types_graphql_query();
309+
} elsif ( $args{type} eq 'jobs' ) {
310+
$query = $self->jobs_graphql_query(%args);
311+
} elsif ( $args{type} eq 'job_status_logs' ) {
312+
$query = $self->job_status_logs_graphql_query(%args);
313+
}
314+
315+
my $body = {
316+
query => $query,
317+
};
318+
319+
$request->content(encode_json($body));
320+
321+
my $response = $self->ua->request($request);
322+
323+
my $content = decode_json($response->content);
324+
325+
return $content;
326+
}
327+
328+
# GraphQL queries.
329+
# Confirm docs: https://help.dudesolutions.com/Content/PDF/Confirm/v21.10/confirm-v21-10-web-api-specification.pdf
330+
#
331+
# We use GraphQL to fetch 'job' objects from Confirm.
332+
# You can read about GraphQL at https://graphql.org/learn/
333+
# BUT
334+
# it appears that Confirm's implementation lacks some features, notably
335+
# variable support (hence the use of string interpolation below). It also
336+
# tends to ignore faulty filter definitions in favour of fetching everything.
337+
338+
sub job_status_logs_graphql_query {
339+
my ( $self, %args ) = @_;
340+
341+
my @job_type_codes
342+
= keys %{ $self->config->{job_service_whitelist} // () };
343+
344+
my @status_codes
345+
= keys %{ $self->config->{job_reverse_status_mapping} // () };
346+
347+
my (
348+
$start_date,
349+
$end_date,
350+
$job_type_codes_str,
351+
$status_codes_str,
352+
) = (
353+
$args{start_date},
354+
$args{end_date},
355+
join( ',', @job_type_codes ),
356+
join( ',', @status_codes ),
357+
);
358+
359+
return <<GRAPHQL;
360+
{
361+
jobStatusLogs(
362+
filter: {
363+
loggedDate: {
364+
greaterThanEquals: "$start_date"
365+
lessThanEquals: "$end_date"
366+
}
367+
statusCode: {
368+
inList: [ $status_codes_str ]
369+
}
370+
}
371+
) {
372+
jobNumber
373+
key
374+
loggedDate
375+
statusCode
376+
377+
job {
378+
jobType(
379+
filter: {
380+
code: {
381+
inList: [ $job_type_codes_str ]
382+
}
383+
}
384+
){
385+
code
386+
}
387+
}
388+
}
389+
}
390+
GRAPHQL
391+
}
392+
393+
sub jobs_graphql_query {
394+
my ( $self, %args ) = @_;
395+
396+
my @job_type_codes
397+
= keys %{ $self->config->{job_service_whitelist} // () };
398+
399+
my @status_codes
400+
= keys %{ $self->config->{job_reverse_status_mapping} // () };
401+
402+
my (
403+
$start_date,
404+
$end_date,
405+
$job_type_codes_str,
406+
$status_codes_str,
407+
) = (
408+
$args{start_date},
409+
$args{end_date},
410+
join( ',', @job_type_codes ),
411+
join( ',', @status_codes ),
412+
);
413+
414+
return <<"GRAPHQL"
415+
{
416+
jobs (
417+
filter: {
418+
entryDate: {
419+
greaterThanEquals: "$start_date"
420+
lessThanEquals: "$end_date"
421+
}
422+
}
423+
){
424+
jobType(
425+
filter: {
426+
code: {
427+
inList: [ $job_type_codes_str ]
428+
}
429+
}
430+
){
431+
code
432+
name
433+
}
434+
435+
statusLogs (
436+
filter: {
437+
statusCode: {
438+
inList: [ $status_codes_str ]
439+
}
440+
}
441+
) {
442+
loggedDate
443+
statusCode
444+
}
445+
446+
entryDate
447+
description
448+
geometry
449+
jobNumber
450+
451+
priority {
452+
code
453+
name
454+
}
455+
}
456+
}
457+
GRAPHQL
458+
}
459+
460+
sub job_types_graphql_query {
461+
return <<'GRAPHQL'
462+
{
463+
jobTypes{
464+
code
465+
name
466+
}
467+
}
468+
GRAPHQL
469+
}
470+
471+
sub GetJobStatusLogs {
472+
my ( $self, %args ) = @_;
473+
474+
my $content
475+
= $self->perform_request_graphql( type => 'job_status_logs', %args );
476+
477+
return $content->{data}{jobStatusLogs} // [];
478+
}
479+
480+
sub GetJobs {
481+
my ($self, %args) = @_;
482+
483+
my $content = $self->perform_request_graphql( type => 'jobs', %args );
484+
485+
return [] unless $content->{data}{jobs};
486+
487+
my @jobs;
488+
489+
# Extra filtering.
490+
# I don't know how to filter out jobs with certain priorities in the
491+
# graphql (possibly a limitation of Confirm's implementation), so let's
492+
# do it here.
493+
for my $job ( @{$content->{data}{jobs}} ) {
494+
next
495+
if $self->config->{job_priority_blacklist}
496+
&& $self->config->{job_priority_blacklist}{ $job->{priority}{code} };
497+
498+
push @jobs, $job;
499+
}
500+
501+
return \@jobs;
502+
}
503+
504+
sub GetJobLookups {
505+
my $self = shift;
506+
507+
my $lookups = $self->memcache->get('GetJobLookups');
508+
unless ($lookups) {
509+
$lookups = $self->perform_request_graphql(type => 'job_types');
510+
511+
$self->memcache->set('GetJobLookups', $lookups, 1800);
512+
}
513+
514+
return $lookups->{data}{jobTypes} // [];
515+
}
516+
292517
sub GetEnquiries {
293518
my $self = shift;
294519

perllib/Open311/Endpoint.pm

+1-1
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ sub GET_Service_List {
366366
keywords => (join ',' => @{ $service->keywords } ),
367367
metadata => $self->format_boolean( $service->has_attributes ),
368368
@{$service->groups} ? (groups => $service->groups) : (group => $service->group),
369-
map { $_ => $service->$_ }
369+
map { $_ => $service->$_ }
370370
qw/ service_name service_code description type /,
371371
}
372372
} $self->services($args);

0 commit comments

Comments
 (0)