Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cypress/cypress/fixtures/bucks_dvla_notok.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"registrationNumber":"L2WPS","engineCapacity":498,"markedForExport":false,"fuelType":"PETROL","motStatus":"Not valid","colour":"BLACK","make":"KAWASAKI","yearOfManufacture":1994,"taxDueDate":"2011-05-31","taxStatus":"Untaxed","dateOfLastV5CIssued":"2005-05-23","wheelplan":"2 WHEEL","monthOfFirstRegistration":"1994-05"}
1 change: 1 addition & 0 deletions .cypress/cypress/fixtures/bucks_dvla_ok.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"registrationNumber":"AA19MOT","co2Emissions":152,"engineCapacity":1984,"markedForExport":false,"fuelType":"PETROL","motStatus":"Valid","revenueWeight":2025,"colour":"WHITE","make":"AUDI","typeApproval":"M1","yearOfManufacture":2016,"taxDueDate":"2026-12-16","taxStatus":"Taxed","dateOfLastV5CIssued":"2016-10-17","motExpiryDate":"2026-12-16","wheelplan":"2 AXLE RIGID BODY","monthOfFirstRegistration":"2016-09"}
53 changes: 53 additions & 0 deletions .cypress/cypress/integration/buckinghamshire.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,56 @@ describe('buckinghamshire roads handling', function() {
cy.contains('Please select a road on which to make a report.').should('be.visible');
});
});

describe('Abandoned vehicle behaviour', function() {
beforeEach(function() {
cy.server();
cy.route('/report/new/ajax*').as('report-ajax');
cy.route('/around\?ajax*').as('update-results');
cy.visit('http://buckinghamshire.localhost:3001/');
cy.contains('Buckinghamshire');
cy.get('[name=pc]').type('SL9 0NX');
cy.get('[name=pc]').parents('form').submit();
cy.wait('@update-results');
cy.get('#map_box').click(322, 307);
cy.wait('@report-ajax');
cy.pickCategory('Abandoned/Nuisance vehicle');
cy.nextPageReporting();
cy.pickSubcategory('Abandoned/Nuisance vehicle', 'A vehicle blocking a footpath');
cy.nextPageReporting();
});

it('No reg plate', function() {
cy.get('.js-reporting-page--active').contains('No').click();
cy.nextPageReporting();
cy.get('[name=VEHICLE_REGISTRATION]').should('have.value', 'Not known');
});

it('Said yes but no reg plate', function() {
cy.get('.js-reporting-page--active').contains('Yes').click();
cy.nextPageReporting();
cy.contains('This field is required');
});

it('Gave an okay reg plate', function() {
cy.route('POST', '/report/dvla', 'fixture:bucks_dvla_ok.json').as('dvla');
cy.get('.js-reporting-page--active').contains('Yes').click();
cy.get('[name=dvla_reg]').type('G00D');
cy.nextPageReporting();
cy.wait('@dvla');
cy.contains('White Audi car, Petrol, 2016');
cy.contains('that are taxed or have a valid MOT');
});

it('Gave an untaxed reg plate', function() {
cy.route('POST', '/report/dvla', 'fixture:bucks_dvla_notok.json').as('dvla');
cy.get('.js-reporting-page--active').contains('Yes').click();
cy.get('[name=dvla_reg]').type('B4D');
cy.nextPageReporting();
cy.wait('@dvla');
cy.get('[name=VEHICLE_REGISTRATION]').should('have.value', 'B4D');
cy.get('[name=ABANDONED_VEHICLE_TAXED]').should('have.value', 'No');
cy.get('[name=ABANDONED_SELECT_TYPE]').should('have.value', 'Motorbike');
cy.get('[name="MAKE_/_COLOUR_OF_THE_VEHI"]').should('have.value', 'Kawasaki / Black');
});
});
16 changes: 16 additions & 0 deletions bin/fixmystreet.com/fixture
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ if ($opt->test_fixtures) {
{ area_id => 164186, categories => ['Shelter Damaged', 'Very Urgent'], name => 'Northamptonshire Highways', cobrand => 'northamptonshire' },
{ area_id => 163793, categories => [
'Flytipping', 'Roads',
{ group => 'Abandoned/Nuisance vehicle', category => 'A vehicle blocking a footpath' },
{ group => 'Abandoned/Nuisance vehicle', category => 'A vehicle burnt out on the road' },
{ group => 'Grass, hedges and weeds', category => 'Grass cutting' },
{ group => 'Grass, hedges and weeds', category => 'Hedge problem' },
{ group => 'Roads & Pavements', category => 'Parks' },
Expand Down Expand Up @@ -284,6 +286,20 @@ if ($opt->test_fixtures) {
$child_cat->update;
}

for my $cat ('A vehicle blocking a footpath', 'A vehicle burnt out on the road') {
$child_cat = FixMyStreet::DB->resultset("Contact")->find({
body => $bodies->{163793},
category => $cat,
});
$child_cat->set_extra_fields(
{"code" => "VEHICLE_REGISTRATION", "datatype" => "string", "required" => "true", "variable" => "true", "protected" => "false", "description" => "Vehicle registration number"},
{"code" => "ABANDONED_VEHICLE_TAXED", "values" => [{"key" => "Yes", "name" => "Yes"}, {"key" => "No", "name" => "No"}], "datatype" => "singlevaluelist", "required" => "true", "variable" => "true", "protected" => "false", "description" => "Is the vehicle taxed?"},
{"code" => "ABANDONED_SELECT_TYPE", "values" => [{"key" => "Car", "name" => "Car"}, {"key" => "Motorbike", "name" => "Motorbike"}, {"key" => "Other", "name" => "Other"}, {"key" => "Van", "name" => "Van"}], "datatype" => "singlevaluelist", "required" => "false", "variable" => "true", "protected" => "false", "description" => "Please select the type of vehicle"},
{"code" => "MAKE_/_COLOUR_OF_THE_VEHI", "datatype" => "string", "required" => "false", "variable" => "true", "protected" => "false", "description" => "Make/colour of the vehicle (if not known, please note not known)"},
);
$child_cat->update;
}

$child_cat = FixMyStreet::DB->resultset("Contact")->find({
body => $bodies->{53822},
category => 'Grass cutting',
Expand Down
34 changes: 34 additions & 0 deletions perllib/FixMyStreet/App/Controller/Report/DVLA.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package FixMyStreet::App::Controller::Report::DVLA;

use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller'; }

use JSON::MaybeXS;
use LWP::UserAgent;

sub lookup : Path : Args(0) {
my ($self, $c) = @_;

my $reg = $c->req->body_params->{registration};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it worth doing any kind of input validation here, e.g. to check its alphanumeric? Guess the DVLA API does its own validation as well.

my $request = {
registrationNumber => $reg,
};

my $ua = LWP::UserAgent->new;

my $dvla = $c->cobrand->feature('dvla');
$c->detach( '/page_error_404_not_found' ) unless $dvla;

my $response = $ua->post(
$dvla->{uri} . '/v1/vehicles',
X_API_Key => $dvla->{key},
Content_Type => 'application/json',
Content => encode_json($request),
);

$c->res->content_type('application/json; charset=utf-8');
$c->res->body($response->decoded_content);
Comment on lines +23 to +31
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could do with some kind of error handling. Could either have it acting as a pure proxy, in which case we should be setting the status code on the response so that's passed through to the JS. Or alternatively we could add more complex error handling here on the server to handle 5xx and 4xx errors from the DVLA API and return a consistent "error" response to the JS.

}

1;
3 changes: 2 additions & 1 deletion templates/web/buckinghamshire/footer_extra_js.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
[%
IF bodyclass.match('mappage');
scripts.push(
version('/cobrands/buckinghamshire/grass_cutting.js')
version('/cobrands/buckinghamshire/grass_cutting.js'),
version('/cobrands/fixmystreet-uk-councils/dvla.js'),
);
END;
%]
4 changes: 4 additions & 0 deletions web/cobrands/buckinghamshire/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ dl dt {
background-image: none;
color: $bucks_charcoal !important;
}
&:disabled {
color: transparentize(#000, 0.4) !important;
background: #eee;
}
}

label {
Expand Down
161 changes: 161 additions & 0 deletions web/cobrands/fixmystreet-uk-councils/dvla.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/* Query the DVLA API on the tax status of a registration number */
// jshint esversion: 6

(function(){

var FIELDS = {
'buckinghamshire': {
'reg': 'VEHICLE_REGISTRATION',
'taxed': 'ABANDONED_VEHICLE_TAXED',
'type': 'ABANDONED_SELECT_TYPE',
'colour': 'COLOUR_OF_THE'
}
};

fixmystreet.dvla = {};

function title_case(str) {
return str.replace(/\w\S*/g, text => text.charAt(0).toUpperCase() + text.substring(1).toLowerCase());
}

fixmystreet.dvla.lookup = function(e) {
var yesno = document.querySelector('input[name=dvla_reg_have]:checked');

var fields = FIELDS[fixmystreet.cobrand];

if (!yesno) return;
yesno = yesno.value;
if (!yesno) {
field = document.querySelector('input[name*="' + fields.reg + '"]');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think field is declared anywhere?

if (field) {
field.value = 'Not known';
}
return;
}
var reg = document.getElementById('dvla_reg').value;
if (!reg) return;
e.preventDefault();
e.stopPropagation();
$.post('/report/dvla', {'registration':reg}, function(data) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similarly here, could do with some error handling for when the DVLA controller returns an error status.

var reasons = [];
if (data.taxStatus == 'Taxed') {
reasons.push('are taxed');
} else if (data.taxStatus == 'SORN') {
reasons.push('have SORN status');
}
if (data.motStatus == 'Valid') {
reasons.push('have a valid MOT');
}

data.make = title_case(data.make || '');
data.colour = title_case(data.colour || '');
data.fuelType = title_case(data.fuelType || '');

var type = data.typeApproval || '';
var wheelplan = data.wheelplan || '';
var vehicle_type = '';
if (type.match(/L[1-7]|motorcycle/i) || wheelplan.match(/motorcyle|moped|2 wheel/i)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should motorcyle be motorcycle?

vehicle_type = 'Motorbike';
} else if (type.match(/N1|commercial/i) || wheelplan.match(/van|commercial/i)) {
vehicle_type = 'Van';
} else if (type.match(/M1/i)) {
vehicle_type = 'Car';
} else if (type.match(/M[23]|N[23]/i) || wheelplan.match(/& artic|3 axle rigid|multi-axle rigid/i)) {
vehicle_type = 'Other';
}

if (reasons.length) {
$('.js-reporting-page--next').prop('disabled', true);
var stopperId = 'js-dvla-stopper';
var $id = $('#' + stopperId);

var vehicle_desc = [data.colour, data.make, vehicle_type=='Other'?'':vehicle_type.toLowerCase()].filter(Boolean).join(' ');
if (data.fuelType) vehicle_desc += ', ' + data.fuelType;
if (data.yearOfManufacture) vehicle_desc += ', ' + data.yearOfManufacture;
var reason = 'We cannot accept reports on vehicles that ' + reasons.join(' or ');
$msg = $('<div class="js-stopper-notice box-warning"><strong>' + vehicle_desc + '</strong><br>' + reason + '. You may be able to <a href="https://contact.dvla.gov.uk/report-untaxed-vehicle">contact the DVLA</a>.</div>');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think $msg is declared anywhere?

$msg.attr('id', stopperId);
$msg.attr('role', 'alert');
$msg.attr('aria-live', 'assertive');
if ($id.length) {
$id.replaceWith($msg);
} else {
$msg.prependTo('.js-reporting-page--active .pre-button-messaging');
}
$('.js-reporting-page--active').css('padding-bottom', $('.js-reporting-page--active .pre-button-messaging').height());
} else {
var field = document.querySelector('input[name*="' + fields.colour + '"]');
if (field) {
var a = [];
if (data.make) a.push(data.make);
if (data.colour) a.push(data.colour);
field.value = a.join(' / ');
}
field = document.querySelector('select[name*="' + fields.type + '"]');
if (field && vehicle_type) {
field.value = vehicle_type;
}
field = document.querySelector('select[name*="' + fields.taxed + '"]');
if (field && !data.errors) {
field.value = 'No';
}
field = document.querySelector('input[name*="' + fields.reg + '"]');
if (field) {
field.value = reg;
}
fixmystreet.pageController.toPage('next');
}
});
};

fixmystreet.dvla.setup = function() {
var selected = fixmystreet.reporting.selectedCategory();
if (selected.group == 'Abandoned/Nuisance vehicle') {
var $msg = $(`<div class="js-dvla-message">

<div class="govuk-form-group">
<fieldset class="govuk-radios govuk-radios--small">
<legend>
Do you know the vehicle’s registration number?
</legend>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="dvla_reg_have_yes" name="dvla_reg_have" type="radio" value="1" data-show="#dvla_reg_field" required>
<label class="govuk-label govuk-radios__label" for="dvla_reg_have_yes">Yes</label>
</div>
<div id="dvla_reg_field" class="hidden-js govuk-radios__conditional govuk-radios__conditional--hidden" id="conditional-contact">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This <div> has two id attributes.

<div class="govuk-form-group">
<label class="govuk-label" for="dvla_reg">Registration number</label>
<input class="govuk-input required" id="dvla_reg" name="dvla_reg" type="text" spellcheck="false">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I was testing this I pressed return instead of clicking "Continue" and it submitted the whole form. So think we need to e.preventDefault somewhere along the line.

</div>
</div>
<div class="govuk-radios__item">
<input class="govuk-radios__input" id="dvla_reg_have_no" name="dvla_reg_have" type="radio" value="" data-hide="#dvla_reg_field">
<label class="govuk-label govuk-radios__label" for="dvla_reg_have_no">No</label>
</div>
</fieldset>
</div>

</div>

<div class="floating-button-spacer"><div class="floating-button-wrapper"><div class="floating-button">
<div class="pre-button-messaging"></div>
<button class="btn btn--block btn--primary js-reporting-page--next">Continue</button>
</div></div></div>
Comment on lines +140 to +143
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want some kind of loading indicator around here somewhere, to show that we're waiting for a response from an external API?

`);

var $div = $(".js-reporting-page.js-dvla-page");
if (!$div.length) {
$div = $("<div class='js-dvla-page'></div>");
}
$div.html($msg);
$div.find('button').on('click', fixmystreet.dvla.lookup);
fixmystreet.pageController.addPageAfter('duplicates', 'dvla', $div);
fixmystreet.set_up.toggle_visibility();
} else {
$(".js-dvla-page").remove();
}
};

$(fixmystreet).on('report_new:category_change', fixmystreet.dvla.setup);

})();
5 changes: 5 additions & 0 deletions web/cobrands/fixmystreet/fixmystreet.js
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,11 @@ fixmystreet.pageController = {
$div.attr('data-page-name', name);
$div.append("<button class='btn btn--block btn--final js-reporting-page--next'>" + translation_strings.ok + "</button>");
$('.js-reporting-page--active').after($div);
},
addPageAfter: function(after, name, $div) {
$div.addClass('js-reporting-page');
$div.attr('data-page-name', name);
$('.js-reporting-page[data-page-name=' + after + ']').after($div);
}
};

Expand Down