diff options
Diffstat (limited to 't/cobrand')
-rw-r--r-- | t/cobrand/bathnes.t | 42 | ||||
-rw-r--r-- | t/cobrand/bexley.t | 281 | ||||
-rw-r--r-- | t/cobrand/bristol.t | 10 | ||||
-rw-r--r-- | t/cobrand/bromley.t | 7 | ||||
-rw-r--r-- | t/cobrand/bucks.t | 121 | ||||
-rw-r--r-- | t/cobrand/cheshireeast.t | 129 | ||||
-rw-r--r-- | t/cobrand/councils.t | 68 | ||||
-rw-r--r-- | t/cobrand/eastsussex.t | 42 | ||||
-rw-r--r-- | t/cobrand/features.t | 20 | ||||
-rw-r--r-- | t/cobrand/fixmystreet.t | 31 | ||||
-rw-r--r-- | t/cobrand/form_extras.t | 2 | ||||
-rw-r--r-- | t/cobrand/greenwich.t | 25 | ||||
-rw-r--r-- | t/cobrand/highwaysengland.t | 70 | ||||
-rw-r--r-- | t/cobrand/hounslow.t | 101 | ||||
-rw-r--r-- | t/cobrand/isleofwight.t | 628 | ||||
-rw-r--r-- | t/cobrand/national_assets.t | 1 | ||||
-rw-r--r-- | t/cobrand/northamptonshire.t | 126 | ||||
-rw-r--r-- | t/cobrand/oxfordshire.t | 223 | ||||
-rw-r--r-- | t/cobrand/peterborough.t | 84 | ||||
-rw-r--r-- | t/cobrand/restriction.t | 5 | ||||
-rw-r--r-- | t/cobrand/staging.t | 18 | ||||
-rw-r--r-- | t/cobrand/tfl.t | 1089 | ||||
-rw-r--r-- | t/cobrand/westminster.t | 259 | ||||
-rw-r--r-- | t/cobrand/zurich.t | 1100 | ||||
-rw-r--r-- | t/cobrand/zurich_attachments.txt | 4 |
25 files changed, 3668 insertions, 818 deletions
diff --git a/t/cobrand/bathnes.t b/t/cobrand/bathnes.t index 6586dcb96..006dd757d 100644 --- a/t/cobrand/bathnes.t +++ b/t/cobrand/bathnes.t @@ -1,6 +1,10 @@ +use Test::MockModule; use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; +my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::BathNES'); +$cobrand->mock('area_types', sub { [ 'UTA' ] }); + my $body = $mech->create_body_ok(2551, 'Bath and North East Somerset Council'); my @cats = ('Litter', 'Other', 'Potholes', 'Traffic lights'); for my $contact ( @cats ) { @@ -11,7 +15,7 @@ my $counciluser = $mech->create_user_ok('counciluser@example.com', name => 'Coun my $normaluser = $mech->create_user_ok('normaluser@example.com', name => 'Normal User'); $normaluser->update({ phone => "+447123456789" }); -$mech->create_problems_for_body(1, $body->id, 'Title', { +my ($problem) = $mech->create_problems_for_body(1, $body->id, 'Title', { areas => ",2651,", category => 'Potholes', cobrand => 'fixmystreet', user => $normaluser, service => 'iOS', extra => { _fields => [ @@ -59,6 +63,19 @@ subtest 'cobrand displays council name' => sub { $mech->content_like( qr/Bath and North East Somerset\b/ ); }; +subtest 'check override contact display name' => sub { + $mech->log_in_ok( $superuser->email ); + $mech->get_ok("/admin/body/" . $body->id . '/Litter'); + $mech->content_contains('<h1>Litter</h1>'); + $mech->content_contains('extra[display_name]'); + $mech->submit_form_ok({ with_fields => { + 'extra[display_name]' => 'Wittering' + }}); + $mech->get_ok('/reports/Bath+and+North+East+Somerset'); + $mech->content_like(qr/Traffic lights<\/option>\s*<option value="Litter">\s*Wittering<\/option>/); + $mech->content_lacks('Litter</option>'); +}; + subtest 'extra CSV columns are absent if permission not granted' => sub { $mech->log_in_ok( $counciluser->email ); @@ -156,28 +173,28 @@ subtest 'extra CSV columns are present if permission granted' => sub { is $rows[1]->[18], 'iOS', 'Site Used shows whether report made via app'; is $rows[1]->[19], '', 'Reported As is empty if not made on behalf of another user/body'; - is $rows[1]->[20], 'normaluser@example.com', 'User email is correct'; + is $rows[1]->[20], $normaluser->email, 'User email is correct'; is $rows[1]->[21], '+447123456789', 'User phone number is correct'; is $rows[1]->[22], '', 'Staff User is empty if not made on behalf of another user'; is $rows[1]->[23], 'width = 10cm; depth = 25cm', 'Attribute Data is correct'; is $rows[2]->[18], 'bathnes', 'Site Used shows correct cobrand'; is $rows[2]->[19], 'body', 'Reported As is correct if made on behalf of body'; - is $rows[2]->[20], 'counciluser@example.com', 'User email is correct'; + is $rows[2]->[20], $counciluser->email, 'User email is correct'; is $rows[2]->[21], '', 'User phone number is correct'; is $rows[2]->[22], '', 'Staff User is empty if not made on behalf of another user'; is $rows[2]->[23], '', 'Attribute Data is correct'; is $rows[3]->[18], 'bathnes', 'Site Used shows correct cobrand'; is $rows[3]->[19], 'another_user', 'Reported As is set if reported on behalf of another user'; - is $rows[3]->[20], 'normaluser@example.com', 'User email is correct'; + is $rows[3]->[20], $normaluser->email, 'User email is correct'; is $rows[3]->[21], '+447123456789', 'User phone number is correct'; - is $rows[3]->[22], 'counciluser@example.com', 'Staff User is correct if made on behalf of another user'; + is $rows[3]->[22], $counciluser->email, 'Staff User is correct if made on behalf of another user'; is $rows[3]->[23], '', 'Attribute Data is correct'; is $rows[4]->[18], 'bathnes', 'Site Used shows correct cobrand'; is $rows[4]->[19], 'anonymous_user', 'Reported As is set if reported on behalf of another user'; - is $rows[4]->[20], 'counciluser@example.com', 'User email is correct'; + is $rows[4]->[20], $counciluser->email, 'User email is correct'; is $rows[4]->[21], '', 'User phone number is correct'; is $rows[4]->[22], '', 'Staff User is empty if not made on behalf of another user'; is $rows[4]->[23], '', 'Attribute Data is correct'; @@ -199,4 +216,17 @@ subtest 'extra CSV columns are present if permission granted' => sub { }; +subtest 'check cobrand correctly reset on each request' => sub { + FixMyStreet::override_config { + 'ALLOWED_COBRANDS' => [ 'bathnes', 'fixmystreet' ], + }, sub { + $mech->log_in_ok( $superuser->email ); + $mech->host('www.fixmystreet.com'); + $mech->get_ok( '/contact?id=' . $problem->id ); + $mech->host('bathnes.fixmystreet.com'); + $mech->get_ok( '/contact?reject=1&id=' . $problem->id ); + $mech->content_contains('Reject report'); + } +}; + done_testing(); diff --git a/t/cobrand/bexley.t b/t/cobrand/bexley.t new file mode 100644 index 000000000..352e61389 --- /dev/null +++ b/t/cobrand/bexley.t @@ -0,0 +1,281 @@ +use CGI::Simple; +use Test::MockModule; +use Test::MockTime qw(:all); +use FixMyStreet::TestMech; +use FixMyStreet::Script::Reports; +use Catalyst::Test 'FixMyStreet::App'; + +set_fixed_time('2019-10-16T17:00:00Z'); # Out of hours + +use_ok 'FixMyStreet::Cobrand::Bexley'; +use_ok 'FixMyStreet::Geocode::Bexley'; + +my $ukc = Test::MockModule->new('FixMyStreet::Cobrand::UKCouncils'); +$ukc->mock('lookup_site_code', sub { + my ($self, $row, $buffer) = @_; + is $row->latitude, 51.408484, 'Correct latitude'; + return "Road ID"; +}); + +FixMyStreet::override_config { + COBRAND_FEATURES => { + contact_email => { + bexley => 'foo@bexley', + } + }, +}, sub { + my $cobrand = FixMyStreet::Cobrand::Bexley->new; + like $cobrand->contact_email, qr/bexley/; + is $cobrand->on_map_default_status, 'open'; + is_deeply $cobrand->disambiguate_location->{bounds}, [ 51.408484, 0.074653, 51.515542, 0.2234676 ]; +}; + +my $mech = FixMyStreet::TestMech->new; + +my $body = $mech->create_body_ok(2494, 'London Borough of Bexley', { + send_method => 'Open311', api_key => 'key', 'endpoint' => 'e', 'jurisdiction' => 'j' }); +$mech->create_contact_ok(body_id => $body->id, category => 'Abandoned and untaxed vehicles', email => "ConfirmABAN"); +$mech->create_contact_ok(body_id => $body->id, category => 'Lamp post', email => "StreetLightingLAMP"); +$mech->create_contact_ok(body_id => $body->id, category => 'Gulley covers', email => "GULL"); +$mech->create_contact_ok(body_id => $body->id, category => 'Damaged road', email => "ROAD"); +$mech->create_contact_ok(body_id => $body->id, category => 'Flooding in the road', email => "ConfirmFLOD"); +$mech->create_contact_ok(body_id => $body->id, category => 'Flytipping', email => "UniformFLY"); +$mech->create_contact_ok(body_id => $body->id, category => 'Dead animal', email => "ANIM"); +$mech->create_contact_ok(body_id => $body->id, category => 'Street cleaning and litter', email => "STREET"); +my $category = $mech->create_contact_ok(body_id => $body->id, category => 'Something dangerous', email => "DANG"); +$category->set_extra_metadata(group => 'Danger things'); +$category->update; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'bexley' ], + MAPIT_URL => 'http://mapit.uk/', + STAGING_FLAGS => { send_reports => 1, skip_checks => 0 }, + COBRAND_FEATURES => { open311_email => { bexley => { + p1 => 'p1@bexley', + p1confirm => 'p1confirm@bexley', + lighting => 'thirdparty@notbexley.example.com,another@notbexley.example.com', + outofhours => 'outofhours@bexley,ooh2@bexley', + flooding => 'flooding@bexley', + eh => 'eh@bexley', + } } }, +}, sub { + + subtest 'cobrand displays council name' => sub { + ok $mech->host("bexley.fixmystreet.com"), "change host to bexley"; + $mech->get_ok('/'); + $mech->content_contains('Bexley'); + }; + + subtest 'cobrand displays council name' => sub { + $mech->get_ok('/reports/Bexley'); + $mech->content_contains('Bexley'); + }; + + my $report; + foreach my $test ( + { category => 'Abandoned and untaxed vehicles', email => ['p1confirm'], code => 'ConfirmABAN', + extra => { 'name' => 'burnt', description => 'Was it burnt?', 'value' => 'Yes' } }, + { category => 'Abandoned and untaxed vehicles', code => 'ConfirmABAN', + extra => { 'name' => 'burnt', description => 'Was it burnt?', 'value' => 'No' } }, + { category => 'Dead animal', email => ['p1', 'outofhours', 'ooh2'], code => 'ANIM' }, + { category => 'Something dangerous', email => ['p1', 'outofhours', 'ooh2'], code => 'DANG', + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'Yes' } }, + { category => 'Something dangerous', code => 'DANG', + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'No' } }, + { category => 'Street cleaning and litter', email => ['p1', 'outofhours', 'ooh2'], code => 'STREET', + extra => { 'name' => 'reportType', description => 'Type of report', 'value' => 'Oil spillage' } }, + { category => 'Gulley covers', email => ['p1', 'outofhours', 'ooh2'], code => 'GULL', + extra => { 'name' => 'reportType', description => 'Type of report', 'value' => 'Cover missing' } }, + { category => 'Gulley covers', code => 'GULL', + extra => { 'name' => 'reportType', description => 'Type of report', 'value' => 'Cover damaged' } }, + { category => 'Gulley covers', email => ['p1', 'outofhours', 'ooh2'], code => 'GULL', + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'Yes' } }, + { category => 'Damaged road', code => 'ROAD', email => ['p1', 'outofhours', 'ooh2'], + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'No' } }, + { category => 'Damaged road', code => 'ROAD', email => ['p1', 'outofhours', 'ooh2'], + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'Yes' } }, + { category => 'Lamp post', code => 'StreetLightingLAMP', email => ['thirdparty', 'another'], + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'No' } }, + { category => 'Lamp post', code => 'StreetLightingLAMP', email => ['thirdparty', 'another'], + extra => { 'name' => 'dangerous', description => 'Was it dangerous?', 'value' => 'Yes' } }, + { category => 'Flytipping', code => 'UniformFLY', email => ['eh'] }, + { category => 'Flooding in the road', code => 'ConfirmFLOD', email => ['flooding'] }, + ) { + ($report) = $mech->create_problems_for_body(1, $body->id, 'On Road', { + category => $test->{category}, cobrand => 'bexley', + latitude => 51.408484, longitude => 0.074653, areas => '2494', + }); + if ($test->{extra}) { + $report->set_extra_fields(ref $test->{extra} eq 'ARRAY' ? @{$test->{extra}} : $test->{extra}); + $report->update; + } + + subtest 'NSGRef and correct email config' => sub { + my $test_data = FixMyStreet::Script::Reports::send(); + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('service_code'), $test->{code}; + if ($test->{code} =~ /Confirm/) { + is $c->param('attribute[site_code]'), 'Road ID'; + } elsif ($test->{code} =~ /Uniform/) { + is $c->param('attribute[uprn]'), 'Road ID'; + } else { + is $c->param('attribute[NSGRef]'), 'Road ID'; + } + + if (my $t = $test->{email}) { + my $email = $mech->get_email; + $t = join('@[^@]*', @$t); + like $email->header('To'), qr/^[^@]*$t@[^@]*$/; + if ($test->{code} =~ /Confirm/) { + like $mech->get_text_body_from_email($email), qr/Site code: Road ID/; + } elsif ($test->{code} =~ /Uniform/) { + like $mech->get_text_body_from_email($email), qr/UPRN: Road ID/; + like $mech->get_text_body_from_email($email), qr/Uniform ID: 248/; + } else { + like $mech->get_text_body_from_email($email), qr/NSG Ref: Road ID/; + } + $mech->clear_emails_ok; + } else { + $mech->email_count_is(0); + } + }; + } + + subtest 'resend is disabled in admin' => sub { + my $user = $mech->log_in_ok('super@example.org'); + $user->update({ from_body => $body, is_superuser => 1 }); + $mech->get_ok('/admin/report_edit/' . $report->id); + $mech->content_contains('View report on site'); + $mech->content_lacks('Resend report'); + }; + + subtest "resending of reports by changing category" => sub { + $mech->get_ok('/admin/report_edit/' . $report->id); + $mech->submit_form_ok({ with_fields => { category => 'Damaged road' } }); + my $test_data = FixMyStreet::Script::Reports::send(); + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('service_code'), 'ROAD', 'Report resent in new category'; + + $mech->submit_form_ok({ with_fields => { category => 'Gulley covers' } }); + $test_data = FixMyStreet::Script::Reports::send(); + is_deeply $test_data, {}, 'Report not resent'; + + $mech->submit_form_ok({ with_fields => { category => 'Lamp post' } }); + $test_data = FixMyStreet::Script::Reports::send(); + $req = $test_data->{test_req_used}; + $c = CGI::Simple->new($req->content); + is $c->param('service_code'), 'StreetLightingLAMP', 'Report resent'; + }; + + subtest 'extra CSV column present' => sub { + $mech->get_ok('/dashboard?export=1'); + $mech->content_contains(',Category,Subcategory,'); + $mech->content_contains('"Danger things","Something dangerous"'); + }; + + + subtest 'testing special Open311 behaviour', sub { + my @reports = $mech->create_problems_for_body( 1, $body->id, 'Test', { + category => 'Flooding in the road', cobrand => 'bexley', + latitude => 51.408484, longitude => 0.074653, areas => '2494', + photo => '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg,74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg', + }); + my $report = $reports[0]; + + my $test_data = FixMyStreet::Script::Reports::send(); + $report->discard_changes; + ok $report->whensent, 'Report marked as sent'; + is $report->send_method_used, 'Open311', 'Report sent via Open311'; + is $report->external_id, 248, 'Report has right external ID'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('attribute[title]'), 'Test Test 1 for ' . $body->id, 'Request had correct title'; + is_deeply [ $c->param('media_url') ], [ + 'http://bexley.example.org/photo/' . $report->id . '.0.full.jpeg?74e33622', + 'http://bexley.example.org/photo/' . $report->id . '.1.full.jpeg?74e33622', + ], 'Request had multiple photos'; + }; + +}; + +subtest 'nearest road returns correct road' => sub { + my $cobrand = FixMyStreet::Cobrand::Bexley->new; + my $cfg = { + accept_feature => sub { 1 }, + property => 'fid', + }; + my $features = [ + { geometry => { type => 'Polygon' } }, + { geometry => { type => 'MultiLineString', + coordinates => [ [ [ 545499, 174361 ], [ 545420, 174359 ], [ 545321, 174352 ] ] ] }, + properties => { fid => '20101226' } }, + { geometry => { type => 'LineString', + coordinates => [ [ 545420, 174359 ], [ 545419, 174375 ], [ 545418, 174380 ], [ 545415, 174391 ] ] }, + properties => { fid => '20100024' } }, + ]; + is $cobrand->_nearest_feature($cfg, 545451, 174380, $features), '20101226'; +}; + +my $geo = Test::MockModule->new('FixMyStreet::Geocode'); +$geo->mock('cache', sub { + my $typ = shift; + return [] if $typ eq 'osm'; + return { + features => [ + { + properties => { ADDRESS => 'BRAMPTON ROAD', TOWN => 'BEXLEY' }, + geometry => { type => 'LineString', coordinates => [ [ 1, 2 ], [ 3, 4] ] }, + }, + { + properties => { ADDRESS => 'FOOTPATH TO BRAMPTON ROAD', TOWN => 'BEXLEY' }, + geometry => { type => 'MultiLineString', coordinates => [ [ [ 1, 2 ], [ 3, 4 ] ], [ [ 5, 6 ], [ 7, 8 ] ] ] }, + }, + ], + } if $typ eq 'bexley'; +}); + +subtest 'geocoder' => sub { + my $c = ctx_request('/'); + my $results = FixMyStreet::Geocode::Bexley->string("Brampton Road", $c); + is_deeply $results, { error => [ + { + 'latitude' => '49.766844', + 'longitude' => '-7.557122', + 'address' => 'Brampton Road, Bexley' + }, { + 'address' => 'Footpath to Brampton Road, Bexley', + 'longitude' => '-7.557097', + 'latitude' => '49.766863' + } + ] }; +}; + +my $bex = Test::MockModule->new('FixMyStreet::Cobrand::Bexley'); +$bex->mock('get', sub { + return <<EOF +{ + "england-and-wales": { + "events": [ + { "date": "2019-12-25", "title": "Christmas Day", "notes": "", "bunting": true } + ] + } +} +EOF +}); + +subtest 'out of hours' => sub { + my $cobrand = FixMyStreet::Cobrand::Bexley->new; + set_fixed_time('2019-10-16T12:00:00Z'); + is $cobrand->_is_out_of_hours(), 0, 'not out of hours in the day'; + set_fixed_time('2019-10-16T04:00:00Z'); + is $cobrand->_is_out_of_hours(), 1, 'out of hours early in the morning'; + set_fixed_time('2019-10-13T12:00:00Z'); + is $cobrand->_is_out_of_hours(), 1, 'out of hours at weekends'; + set_fixed_time('2019-12-25T12:00:00Z'); + is $cobrand->_is_out_of_hours(), 1, 'out of hours on bank holiday'; +}; + +done_testing(); diff --git a/t/cobrand/bristol.t b/t/cobrand/bristol.t index b2b8cff13..d4770b6ee 100644 --- a/t/cobrand/bristol.t +++ b/t/cobrand/bristol.t @@ -21,6 +21,16 @@ my $email_contact = $mech->create_contact_ok( send_method => 'Email' ); +subtest 'Reports page works with no reports', sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'bristol' ], + MAPIT_URL => 'http://mapit.uk/', + MAP_TYPE => 'Bristol', + }, sub { + $mech->get_ok("/reports"); + }; +}; + subtest 'Only Open311 categories are shown on Bristol cobrand', sub { FixMyStreet::override_config { ALLOWED_COBRANDS => [ 'bristol' ], diff --git a/t/cobrand/bromley.t b/t/cobrand/bromley.t index 6750d3183..71180cd3e 100644 --- a/t/cobrand/bromley.t +++ b/t/cobrand/bromley.t @@ -169,7 +169,7 @@ for my $test ( like $body, qr/This update will be sent to Bromley Council/i, "Email indicates problem will be sent to Bromley"; unlike $body, qr/Note that we do not send updates to/i, "Email does not say updates aren't sent to Bromley"; - my $unreg_user = FixMyStreet::App->model( 'DB::User' )->find( { email => 'unregistered@example.com' } ); + my $unreg_user = FixMyStreet::DB->resultset('User')->find( { email => 'unregistered@example.com' } ); ok $unreg_user, 'found user'; @@ -233,10 +233,11 @@ subtest 'check heatmap page' => sub { FixMyStreet::override_config { ALLOWED_COBRANDS => 'bromley', MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { category_groups => { bromley => 1 }, heatmap => { bromley => 1 } }, }, sub { $mech->log_in_ok($user->email); - $mech->get_ok('/about/heatmap?end_date=2018-12-31'); - $mech->get_ok('/about/heatmap?filter_category=RED&ajax=1'); + $mech->get_ok('/dashboard/heatmap?end_date=2018-12-31'); + $mech->get_ok('/dashboard/heatmap?filter_category=RED&ajax=1'); }; }; diff --git a/t/cobrand/bucks.t b/t/cobrand/bucks.t index 965b90107..230a52f99 100644 --- a/t/cobrand/bucks.t +++ b/t/cobrand/bucks.t @@ -4,21 +4,38 @@ use FixMyStreet::Script::Reports; my $mech = FixMyStreet::TestMech->new; +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + my $body = $mech->create_body_ok(2217, 'Buckinghamshire', { - send_method => 'Open311', api_key => 'key', endpoint => 'endpoint', jurisdiction => 'fms' }); + send_method => 'Open311', api_key => 'key', endpoint => 'endpoint', jurisdiction => 'fms', can_be_devolved => 1 }); my $counciluser = $mech->create_user_ok('counciluser@example.com', name => 'Council User', from_body => $body); - -$mech->create_contact_ok(body_id => $body->id, category => 'Flytipping', email => "FLY"); +my $publicuser = $mech->create_user_ok('fmsuser@example.org', name => 'Simon Neil'); + +my $contact = $mech->create_contact_ok(body_id => $body->id, category => 'Flytipping', email => "FLY"); +$contact->set_extra_fields({ + code => 'road-placement', + datatype => 'singlevaluelist', + description => 'Is the fly-tip located on', + order => 100, + required => 'true', + variable => 'true', + values => [ + { key => 'road', name => 'The road' }, + { key => 'off-road', name => 'Off the road/on a verge' }, + ], +}); +$contact->update; $mech->create_contact_ok(body_id => $body->id, category => 'Potholes', email => "POT"); $mech->create_contact_ok(body_id => $body->id, category => 'Blocked drain', email => "DRA"); - -my $district = $mech->create_body_ok(2257, 'Chiltern'); -$mech->create_contact_ok(body_id => $district->id, category => 'Flytipping', email => "flytipping\@chiltern"); -$mech->create_contact_ok(body_id => $district->id, category => 'Graffiti', email => "graffiti\@chiltern"); +$mech->create_contact_ok(body_id => $body->id, category => 'Car Parks', email => "car\@chiltern", send_method => 'Email'); +$mech->create_contact_ok(body_id => $body->id, category => 'Graffiti', email => "graffiti\@chiltern", send_method => 'Email'); +$mech->create_contact_ok(body_id => $body->id, category => 'Flytipping (off-road)', email => "districts_flytipping", send_method => 'Email'); my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::Buckinghamshire'); $cobrand->mock('lookup_site_code', sub { - my ($self, $row, $buffer) = @_; + my ($self, $row) = @_; return "Road ID" if $row->latitude == 51.812244; }); @@ -26,6 +43,21 @@ FixMyStreet::override_config { ALLOWED_COBRANDS => [ 'buckinghamshire', 'fixmystreet' ], MAPIT_URL => 'http://mapit.uk/', STAGING_FLAGS => { send_reports => 1, skip_checks => 0 }, + COBRAND_FEATURES => { + open311_email => { + buckinghamshire => { + flytipping => 'flytipping@example.org', + flood => 'floods@example.org', + } + }, + borough_email_addresses => { + buckinghamshire => { + districts_flytipping => [ + { email => "flytipping\@chiltern", areas => [ 2257 ] }, + ] + } + } + } }, sub { subtest 'cobrand displays council name' => sub { @@ -36,24 +68,26 @@ subtest 'cobrand displays council name' => sub { subtest 'cobrand displays correct categories' => sub { my $json = $mech->get_ok_json('/report/new/ajax?latitude=51.615559&longitude=-0.556903'); - is @{$json->{bodies}}, 2, 'Both Chiltern and Bucks returned'; + is @{$json->{bodies}}, 1, 'Bucks returned'; + like $json->{category}, qr/Car Parks/, 'Car Parks displayed'; like $json->{category}, qr/Flytipping/, 'Flytipping displayed'; like $json->{category}, qr/Blocked drain/, 'Blocked drain displayed'; - unlike $json->{category}, qr/Graffiti/, 'Graffiti not displayed'; + like $json->{category}, qr/Graffiti/, 'Graffiti displayed'; + unlike $json->{category}, qr/Flytipping \(off-road\)/, 'Flytipping (off-road) not displayed'; $json = $mech->get_ok_json('/report/new/category_extras?latitude=51.615559&longitude=-0.556903'); - is @{$json->{bodies}}, 2, 'Still both Chiltern and Bucks returned'; + is @{$json->{bodies}}, 1, 'Still Bucks returned'; }; my ($report) = $mech->create_problems_for_body(1, $body->id, 'On Road', { category => 'Flytipping', cobrand => 'fixmystreet', latitude => 51.812244, longitude => -0.827363, + dt => DateTime->now()->subtract(minutes => 10), }); subtest 'flytipping on road sent to extra email' => sub { FixMyStreet::Script::Reports::send(); my @email = $mech->get_email; - my $tfb = join('', 'illegaldumpingcosts', '@', 'buckscc.gov.uk'); - is $email[0]->header('To'), '"TfB" <' . $tfb . '>'; + is $email[0]->header('To'), 'TfB <flytipping@example.org>'; like $mech->get_text_body_from_email($email[1]), qr/report's reference number/; $report->discard_changes; is $report->external_id, 248, 'Report has right external ID'; @@ -66,6 +100,7 @@ subtest 'flytipping on road sent to extra email' => sub { contributed_as => 'another_user', contributed_by => $counciluser->id, }, + dt => DateTime->now()->subtract(minutes => 9), }); subtest 'pothole on road not sent to extra email, only confirm sent' => sub { @@ -77,58 +112,50 @@ subtest 'pothole on road not sent to extra email, only confirm sent' => sub { is $report->external_id, 248, 'Report has right external ID'; }; -($report) = $mech->create_problems_for_body(1, $district->id, 'Off Road', { - category => 'Flytipping', cobrand => 'buckinghamshire', - latitude => 51.813173, longitude => -0.826741, -}); -subtest 'flytipping off road sent to extra email' => sub { + +# report made in Flytipping category off road should get moved to other category +subtest 'Flytipping not on a road gets recategorised' => sub { + $mech->log_in_ok($publicuser->email); + $mech->get_ok('/report/new?latitude=51.615559&longitude=-0.556903&category=Flytipping'); + $mech->submit_form_ok({ + with_fields => { + title => "Test Report", + detail => 'Test report details.', + category => 'Flytipping', + 'road-placement' => 'off-road', + } + }, "submit details"); + $mech->content_contains('Your issue is on its way to the council.'); + my $report = FixMyStreet::DB->resultset("Problem")->search(undef, { order_by => { -desc => 'id' } })->first; + ok $report, "Found the report"; + is $report->category, "Flytipping (off-road)", 'Report was recategorised correctly'; + + $mech->log_out_ok; +}; + +subtest 'Ex-district reports are sent to correct emails' => sub { FixMyStreet::Script::Reports::send(); + $mech->email_count_is(2); # one for council, one confirmation for user my @email = $mech->get_email; - is $email[0]->header('To'), '"Chiltern" <flytipping@chiltern>'; - like $mech->get_text_body_from_email($email[1]), qr/Please note that Buckinghamshire County Council is not responsible/; - $report->discard_changes; - is $report->external_id, undef, 'Report has right external ID'; + is $email[0]->header('To'), 'Buckinghamshire <flytipping@chiltern>'; }; my ($report2) = $mech->create_problems_for_body(1, $body->id, 'Drainage problem', { category => 'Blocked drain', cobrand => 'fixmystreet', latitude => 51.812244, longitude => -0.827363, + dt => DateTime->now()->subtract(minutes => 8), }); subtest 'blocked drain sent to extra email' => sub { $mech->clear_emails_ok; FixMyStreet::Script::Reports::send(); my @email = $mech->get_email; - my $e = join('@', 'floodmanagement', 'buckscc.gov.uk'); - is $email[0]->header('To'), '"Flood Management" <' . $e . '>'; + is $email[0]->header('To'), '"Flood Management" <floods@example.org>'; like $mech->get_text_body_from_email($email[1]), qr/report's reference number/; }; $cobrand = FixMyStreet::Cobrand::Buckinghamshire->new(); -subtest 'Flytipping extra question used if necessary' => sub { - my $errors = { 'road-placement' => 'This field is required' }; - - $report->update({ bodies_str => $body->id }); - $cobrand->flytipping_body_fix($report, 'road', $errors); - is $errors->{'road-placement'}, 'This field is required', 'Error stays if sent to county'; - - $report->update({ bodies_str => $district->id }); - $report->discard_changes; # As e.g. ->bodies has been remembered. - $cobrand->flytipping_body_fix($report, 'road', $errors); - is $errors->{'road-placement'}, undef, 'Error removed if sent to district'; - - $report->update({ bodies_str => $body->id . ',' . $district->id }); - $report->discard_changes; # As e.g. ->bodies has been remembered. - $cobrand->flytipping_body_fix($report, 'road', $errors); - is $report->bodies_str, $body->id, 'Sent to both becomes sent to county on-road'; - - $report->update({ bodies_str => $district->id . ',' . $body->id }); - $report->discard_changes; # As e.g. ->bodies has been remembered. - $cobrand->flytipping_body_fix($report, 'off-road', $errors); - is $report->bodies_str, $district->id, 'Sent to both becomes sent to district off-road'; -}; - for my $test ( { desc => 'filters basic emails', diff --git a/t/cobrand/cheshireeast.t b/t/cobrand/cheshireeast.t new file mode 100644 index 000000000..4924a96ee --- /dev/null +++ b/t/cobrand/cheshireeast.t @@ -0,0 +1,129 @@ +use CGI::Simple; +use Test::MockModule; +use FixMyStreet::TestMech; +use FixMyStreet::Script::Alerts; +use FixMyStreet::Script::Reports; + +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +my $mech = FixMyStreet::TestMech->new; + +my $body = $mech->create_body_ok( 21069, 'Cheshire East Council', { + send_method => 'Open311', + endpoint => 'endpoint', + api_key => 'key', + jurisdiction => 'cheshireeast_confirm', +}); + +my $contact = $mech->create_contact_ok( + body_id => $body->id, + category => 'Zebra Crossing', + email => 'ZEBRA', +); + +my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::CheshireEast'); +$cobrand->mock('_fetch_features', sub { + return []; +}); + +use_ok 'FixMyStreet::Cobrand::CheshireEast'; + +FixMyStreet::override_config { + COBRAND_FEATURES => { + contact_email => { + cheshireeast => 'foo@cheshireeast', + } + }, +}, sub { + my $cobrand = FixMyStreet::Cobrand::CheshireEast->new; + like $cobrand->contact_email, qr/cheshireeast/; + is_deeply $cobrand->disambiguate_location->{bounds}, [ 52.947150, -2.752929, 53.387445, -1.974789 ]; +}; + +my @reports = $mech->create_problems_for_body( 1, $body->id, 'Test', { + category => 'Zebra Crossing', + photo => '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg,74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg', +}); +my $report = $reports[0]; + +my $alert = FixMyStreet::DB->resultset("Alert")->create({ + alert_type => 'new_updates', + cobrand => 'cheshireeast', + parameter => $report->id, + user => { + email => 'alert@example.com', + email_verified => 1, + }, +}); +$alert->confirm; + +$mech->create_comment_for_problem($report, $report->user, $report->name, 'blah', 0, 'confirmed', 'confirmed', { + confirmed => \'current_timestamp' +}); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'cheshireeast', + MAPIT_URL => 'http://mapit.uk/', + STAGING_FLAGS => { skip_checks => 1, send_reports => 1 }, +}, sub { + + subtest 'cobrand displays council name' => sub { + ok $mech->host("cheshireeast.fixmystreet.com"), "change host to cheshireeast"; + $mech->get_ok('/'); + $mech->content_contains('Cheshire East'); + }; + + subtest 'testing special Open311 behaviour', sub { + my $test_data = FixMyStreet::Script::Reports::send(); + $report->discard_changes; + ok $report->whensent, 'Report marked as sent'; + is $report->send_method_used, 'Open311', 'Report sent via Open311'; + is $report->external_id, 248, 'Report has right external ID'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('attribute[title]'), 'Test Test 1 for ' . $body->id, 'Request had correct title'; + is_deeply [ $c->param('media_url') ], [ + 'http://www.example.org/photo/' . $report->id . '.0.full.jpeg?74e33622', + 'http://www.example.org/photo/' . $report->id . '.1.full.jpeg?74e33622', + ], 'Request had multiple photos'; + + }; + + subtest 'testing reference numbers shown' => sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_contains('Council ref: ' . $report->id); + FixMyStreet::Script::Alerts::send(); + like $mech->get_text_body_from_email, qr/reference number is @{[$report->id]}/; + }; + + subtest 'contact page blocked', sub { + $mech->get('/contact'); + is $mech->res->code, 404; + }; + + subtest 'check post-submission message', sub { + $mech->log_in_ok($report->user->email); + $mech->get_ok('/report/new?latitude=53.145324&longitude=-2.370437'); + $mech->submit_form_ok({ with_fields => { + title => 'title', + detail => 'detail', + }}); + my $report = FixMyStreet::DB->resultset('Problem')->search(undef, { order_by => { -desc => 'id' } })->first; + my $report_id = $report->id; + $mech->content_contains('0300 123 5020'); + $mech->content_like(qr/quoting your reference number $report_id/); + }; + + subtest 'checking alert pages', sub { + $mech->get_ok('/alert'); + $mech->content_contains('all reported problems'); + $mech->submit_form_ok({ with_fields => { pc => 'CW11 1HZ' } }); + $mech->content_contains('Reported problems within 10.0km'); + $mech->content_contains('All reported problems'); + $mech->content_contains('Reported problems within Sandbach Town'); + }; +}; + +done_testing(); diff --git a/t/cobrand/councils.t b/t/cobrand/councils.t index c44605bd9..aac682b19 100644 --- a/t/cobrand/councils.t +++ b/t/cobrand/councils.t @@ -47,4 +47,72 @@ foreach my $test ( }; +subtest "Test update shown/not shown appropriately" => sub { + my $user = $mech->create_user_ok('test@example.com'); + foreach my $cobrand ('oxfordshire', 'fixmystreet') { + foreach my $test ( + # Three bools are logged out, reporter, staff user + { type => 'none', update => [0,0,0] }, + { type => 'staff', update => [0,0,1] }, + { type => 'reporter', update => [0,1,1] }, + { type => 'reporter-open', state => 'closed', update => [0,0,0] }, + { type => 'reporter-open', state => 'in progress', update => [0,1,1] }, + { type => 'open', state => 'closed', update => [0,0,0] }, + { type => 'open', state => 'in progress', update => [1,1,1] }, + ) { + FixMyStreet::override_config { + ALLOWED_COBRANDS => $cobrand, + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + updates_allowed => { + oxfordshire => $test->{type}, + fixmystreet => { + Oxfordshire => $test->{type}, + } + } + }, + }, sub { + subtest "$cobrand, $test->{type}" => sub { + $report->update({ state => $test->{state} || 'confirmed' }); + $mech->log_out_ok; + $user->update({ from_body => undef }); + $mech->get_ok("/report/$report_id"); + $mech->contains_or_lacks($test->{update}[0], 'Provide an update'); + $mech->log_in_ok('test@example.com'); + $mech->get_ok("/report/$report_id"); + $mech->contains_or_lacks($test->{update}[1], 'Provide an update'); + $user->update({ from_body => $oxon->id }); + $mech->get_ok("/report/$report_id"); + $mech->contains_or_lacks($test->{update}[2], 'Provide an update'); + }; + }; + } + } +}; + +subtest "CSP header from feature" => sub { + foreach my $cobrand ( + { moniker => 'oxfordshire', test => 'oxon.analytics.example.org' }, + { moniker =>'fixmystreet', test => '' }, + { moniker => 'nonsecure', test => undef }, + ) { + FixMyStreet::override_config { + ALLOWED_COBRANDS => $cobrand->{moniker}, + COBRAND_FEATURES => { + content_security_policy => { + oxfordshire => 'oxon.analytics.example.org', + fixmystreet => 1, + } + }, + }, sub { + $mech->get_ok("/"); + if (defined $cobrand->{test}) { + like $mech->res->header('Content-Security-Policy'), qr/script-src 'self' 'unsafe-inline' 'nonce-[^']*' $cobrand->{test}/; + } else { + is $mech->res->header('Content-Security-Policy'), undef; + } + }; + } +}; + done_testing(); diff --git a/t/cobrand/eastsussex.t b/t/cobrand/eastsussex.t new file mode 100644 index 000000000..13383d44c --- /dev/null +++ b/t/cobrand/eastsussex.t @@ -0,0 +1,42 @@ +use FixMyStreet::TestMech; +use FixMyStreet::Script::Reports; +use CGI::Simple; + +my $mech = FixMyStreet::TestMech->new; + +my $body = $mech->create_body_ok(2224, 'East Sussex Council', + { send_method => 'Open311', api_key => 'KEY', endpoint => 'endpoint', jurisdiction => 'eastsussex' }); +my $contact = $mech->create_contact_ok(body => $body, category => 'Pothole', email => 'POTHOLE'); +$contact->set_extra_fields( + { code => 'urgent', description => 'Is it urgent?', variable => 'true' }, + { code => 'notice', description => 'This is a notice', variable => 'false' }); +$contact->update; +my ($p) = $mech->create_problems_for_body(1, $body->id, 'East Sussex report', { category => 'Pothole' }); +$p->set_extra_fields({ name => 'urgent', value => 'no'}); +$p->update; + +subtest 'Check special Open311 request handling', sub { + my $orig_detail = $p->detail; + my $test_data; + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => 'eastsussex', + BASE_URL => 'https://www.fixmystreet.com', + }, sub { + $test_data = FixMyStreet::Script::Reports::send(); + }; + + $p->discard_changes; + ok $p->whensent, 'Report marked as sent'; + is $p->send_method_used, 'Open311', 'Report sent via Open311'; + is $p->external_id, 248, 'Report has right external ID'; + is $p->detail, $orig_detail, 'Detail in database not changed'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + my $expected = join "\r\n", $p->title, '', $p->detail, '', + 'Is it urgent?', 'no', '', "https://www.fixmystreet.com" . $p->url, ''; + is $c->param('description'), $expected, 'Correct description, with extra question and no notice text'; +}; + +done_testing; diff --git a/t/cobrand/features.t b/t/cobrand/features.t new file mode 100644 index 000000000..45ea6336d --- /dev/null +++ b/t/cobrand/features.t @@ -0,0 +1,20 @@ +use FixMyStreet::Test; +use FixMyStreet::Cobrand; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => ['bromley'], + COBRAND_FEATURES => { + foo => { tester => 1 }, + bar => { default => 1 }, + suggest_duplicates => { bromley => 1 }, + } +}, sub { + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('default')->new; + my $bromley = FixMyStreet::Cobrand->get_class_for_moniker('bromley')->new; + + is $cobrand->feature('foo'), undef; + is $cobrand->feature('bar'), 1; + is $bromley->suggest_duplicates, 1; +}; + +done_testing(); diff --git a/t/cobrand/fixmystreet.t b/t/cobrand/fixmystreet.t index b47269db4..a54e782f2 100644 --- a/t/cobrand/fixmystreet.t +++ b/t/cobrand/fixmystreet.t @@ -1,8 +1,13 @@ +use utf8; use FixMyStreet::Script::UpdateAllReports; +use Test::MockModule; use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; +my $resolver = Test::MockModule->new('Email::Valid'); +$resolver->mock('address', sub { $_[1] }); + my $body = $mech->create_body_ok( 2514, 'Birmingham' ); my $contact = $mech->create_contact_ok( @@ -53,7 +58,7 @@ FixMyStreet::override_config { subtest 'check marketing dashboard csv' => sub { $mech->log_in_ok('someone@birmingham.gov.uk'); - $mech->create_problems_for_body(105, $body->id, 'Title', { + $mech->create_problems_for_body(105, $body->id, 'Titlē', { detail => "this report\nis split across\nseveral lines", areas => ",2514,", }); @@ -80,7 +85,7 @@ FixMyStreet::override_config { 'Column headers look correct'; my $body_id = $body->id; - like $rows[1]->[1], qr/Title Test \d+ for $body_id/, 'problem title correct'; + like $rows[1]->[1], qr/Titlē Test \d+ for $body_id/, 'problem title correct'; }; subtest 'check marketing dashboard contact listings' => sub { @@ -106,6 +111,22 @@ FixMyStreet::override_config { }; }; -END { - done_testing(); -} +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'fixmystreet', +}, sub { + subtest 'test enforced 2FA for superusers' => sub { + my $test_email = 'test@example.com'; + my $user = FixMyStreet::DB->resultset('User')->find_or_create({ email => $test_email }); + $user->password('password'); + $user->is_superuser(1); + $user->update; + + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $test_email, password_sign_in => 'password' } }, + "sign in using form" ); + $mech->content_contains('requires two-factor'); + }; +}; + +done_testing(); diff --git a/t/cobrand/form_extras.t b/t/cobrand/form_extras.t index df76ccbe1..3807dd56a 100644 --- a/t/cobrand/form_extras.t +++ b/t/cobrand/form_extras.t @@ -84,7 +84,7 @@ FixMyStreet::override_config { ); $mech->content_contains('Now check your email'); - my $problem = FixMyStreet::DB->resultset('Problem')->search({}, { order_by => '-id' })->first; + my $problem = FixMyStreet::DB->resultset('Problem')->search({}, { order_by => { -desc => 'id' } })->first; is $problem->get_extra_metadata('address'), 'My address', 'Address is stored'; is $problem->get_extra_metadata('passport'), 'P123456', 'Passport number is stored'; }; diff --git a/t/cobrand/greenwich.t b/t/cobrand/greenwich.t index e6aaca973..14ddba9be 100644 --- a/t/cobrand/greenwich.t +++ b/t/cobrand/greenwich.t @@ -5,7 +5,7 @@ use Open311::PopulateServiceList; my $mech = FixMyStreet::TestMech->new; -my $body = $mech->create_body_ok( 2493, 'Greenwich Council', { +my $body = $mech->create_body_ok( 2493, 'Royal Borough of Greenwich', { send_method => 'Open311', endpoint => 'endpoint', api_key => 'key', @@ -110,5 +110,26 @@ subtest 'testing special Open311 behaviour', sub { is $c->param('attribute[easting]'), 529025, 'Request had correct easting'; }; -done_testing(); +subtest 'RSS feed on .com' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'fixmystreet', + MAPIT_TYPES => ['GRE'], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->get_ok('/rss/reports/Greenwich'); + is $mech->uri->path, '/rss/reports/Greenwich'; + }; +}; +subtest 'RSS feed on Greenwich' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'greenwich', + MAPIT_TYPES => ['GRE'], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->get_ok('/rss/reports/Greenwich'); + is $mech->uri->path, '/rss/reports/Greenwich'; + }; +}; + +done_testing(); diff --git a/t/cobrand/highwaysengland.t b/t/cobrand/highwaysengland.t new file mode 100644 index 000000000..f6400ea7c --- /dev/null +++ b/t/cobrand/highwaysengland.t @@ -0,0 +1,70 @@ +use FixMyStreet::TestMech; +use FixMyStreet::App; +use FixMyStreet::Script::Reports; +use FixMyStreet::Cobrand::HighwaysEngland; +use HighwaysEngland; +use Test::MockModule; + +my $he_mock = Test::MockModule->new('HighwaysEngland'); +$he_mock->mock('database_file', sub { FixMyStreet->path_to('t/geocode/roads.sqlite'); }); + +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + + +my $he_mock_cobrand = Test::MockModule->new('FixMyStreet::Cobrand::HighwaysEngland'); +$he_mock_cobrand->mock('anonymous_account', sub { { email => 'anoncategory@example.org', name => 'Anonymous Category' } }); + +my $he = FixMyStreet::Cobrand::HighwaysEngland->new(); + +my $r = $he->geocode_postcode('M1'); +ok $r->{error}, "searching for road only generates error"; + +$r = $he->geocode_postcode('m1'); +ok $r->{error}, "searching for lowecase road only generates error"; + +my $mech = FixMyStreet::TestMech->new; +my $highways = $mech->create_body_ok(2234, 'Highways England'); + +$mech->create_contact_ok(email => 'highways@example.com', body_id => $highways->id, category => 'Pothole'); + +# Br1 3UH +subtest "check where heard from saved" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'highwaysengland', + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'M1, J16', } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + $mech->submit_form_ok( + { + button => 'report_anonymously', + with_fields => { + title => "Test Report for HE", + detail => 'Test report details.', + category => 'Pothole', + where_hear => 'Facebook', + } + }, + "submit good details" + ); + $mech->content_contains('Thank you'); + + my $report = FixMyStreet::DB->resultset("Problem")->first; + ok $report, "Found the report"; + is $report->get_extra_metadata('where_hear'), 'Facebook', 'saved where hear'; + + $mech->clear_emails_ok; + FixMyStreet::Script::Reports::send(); + $mech->email_count_is(1); + my $email = $mech->get_email; + like $mech->get_text_body_from_email($email), qr/Heard from: Facebook/, 'where hear included in email' + + }; +}; + + +done_testing(); diff --git a/t/cobrand/hounslow.t b/t/cobrand/hounslow.t new file mode 100644 index 000000000..91c1cb455 --- /dev/null +++ b/t/cobrand/hounslow.t @@ -0,0 +1,101 @@ +use FixMyStreet::TestMech; + +ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' ); + +my $hounslow_id = $mech->create_body_ok(2483, 'Hounslow Borough Council')->id; +$mech->create_contact_ok( + body_id => $hounslow_id, + category => 'Potholes', + email => 'pothole@example.org', +); + +my $user = $mech->create_user_ok('staff@example.org', from_body => $hounslow_id); +$user->user_body_permissions->create({ body_id => $hounslow_id, permission_type => 'user_edit' }); + +my $tfl = $mech->create_body_ok( 2483, 'TfL'); +$mech->create_contact_ok( + body_id => $tfl->id, + category => 'Traffic lights', + email => 'tfl@example.org', +); + +$mech->create_problems_for_body(1, $hounslow_id, 'An old problem made before Hounslow FMS launched', { + confirmed => '2018-12-25 09:00', + lastupdate => '2018-12-25 09:00', + latitude => 51.482286, + longitude => -0.328163, + +}); +$mech->create_problems_for_body(1, $hounslow_id, 'A brand new problem made on the Hounslow site', { + latitude => 51.482286, + longitude => -0.328163, + cobrand => 'hounslow' +}); +my ($report) = $mech->create_problems_for_body(1, $hounslow_id, 'A brand new problem made on fixmystreet.com', { + latitude => 51.482286, + longitude => -0.328163, + external_id => 'ABC123', + cobrand => 'fixmystreet' +}); + +subtest "it still shows old reports on fixmystreet.com" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'fixmystreet', + }, sub { + $mech->get_ok('/reports/Hounslow'); + + $mech->content_contains('An old problem made before Hounslow FMS launched'); + $mech->content_contains('A brand new problem made on the Hounslow site'); + $mech->content_contains('A brand new problem made on fixmystreet.com'); + }; +}; + +subtest "it does not show old reports on Hounslow" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'hounslow', + }, sub { + $mech->get_ok('/reports/Hounslow'); + $mech->content_lacks('An old problem made before Hounslow FMS launched'); + $mech->content_contains('A brand new problem made on the Hounslow site') or diag $mech->content; + $mech->content_contains('A brand new problem made on fixmystreet.com'); + }; +}; + +subtest "it shows the right things on an /around page" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'hounslow', + }, sub { + $mech->get_ok('/around?pc=TW7+5JN'); + $mech->content_lacks('An old problem made before Hounslow FMS launched'); + $mech->content_contains('A brand new problem made on the Hounslow site') or diag $mech->content; + $mech->content_contains('A brand new problem made on fixmystreet.com'); + }; +}; + +subtest "Shows external ID on report page to staff users only" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'hounslow', + }, sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('ABC123'); + $mech->log_in_ok('staff@example.org'); + $mech->get_ok('/report/' . $report->id); + $mech->content_contains('ABC123'); + }; +}; + +subtest "Admin searches right domains" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'hounslow', + }, sub { + foreach ('hounslowhighways.org', 'hounslow.gov.uk') { + $mech->get_ok('/admin/users?search=xyz@' . $_); + $mech->content_contains('xyz@' . $_); + } + }; +}; + +done_testing(); diff --git a/t/cobrand/isleofwight.t b/t/cobrand/isleofwight.t new file mode 100644 index 000000000..3cac710da --- /dev/null +++ b/t/cobrand/isleofwight.t @@ -0,0 +1,628 @@ +use utf8; +use CGI::Simple; +use DateTime; +use Test::MockModule; +use FixMyStreet::TestMech; +use Open311; +use Open311::GetServiceRequests; +use Open311::GetServiceRequestUpdates; +use Open311::PostServiceRequestUpdates; +use FixMyStreet::Script::Alerts; +use FixMyStreet::Script::Reports; + +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::IsleOfWight'); +$cobrand->mock('lookup_site_code', sub { + my ($self, $row) = @_; + return "Road ID" if $row->latitude == 50.7108; +}); + +ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' ); + +my $params = { + send_method => 'Open311', + send_comments => 1, + api_key => 'KEY', + endpoint => 'endpoint', + jurisdiction => 'home', + can_be_devolved => 1, +}; +my $isleofwight = $mech->create_body_ok(2636, 'Isle of Wight Council', $params); +my $contact = $mech->create_contact_ok( + body_id => $isleofwight->id, + category => 'Potholes', + email => 'pothole@example.org', +); +$contact->set_extra_fields( ( { + code => 'urgent', + datatype => 'string', + description => 'question', + variable => 'true', + required => 'false', + order => 1, + datatype_description => 'datatype', +} ) ); +$contact->update; + +my $user = $mech->create_user_ok('user@example.org', name => 'Test User'); +my $iow_user = $mech->create_user_ok('iow_user@example.org', name => 'IoW User', from_body => $isleofwight); +$iow_user->user_body_permissions->create({ + body => $isleofwight, + permission_type => 'moderate', +}); + +my $contact2 = $mech->create_contact_ok( + body_id => $isleofwight->id, + category => 'Roads', + email => 'roads@example.org', + send_method => 'Triage', +); + +my $admin_user = $mech->create_user_ok('admin-user@example.org', name => 'Admin User', from_body => $isleofwight); + +$admin_user->user_body_permissions->create({ + body => $isleofwight, + permission_type => 'triage' +}); + +my @reports = $mech->create_problems_for_body(1, $isleofwight->id, 'An Isle of wight report', { + confirmed => '2019-10-25 09:00', + lastupdate => '2019-10-25 09:00', + latitude => 50.7108, + longitude => -1.29573, + user => $user, + external_id => 101202303 +}); + +subtest "check clicking all reports link" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $mech->get_ok('/'); + $mech->follow_link_ok({ text => 'All reports' }); + }; + + $mech->content_contains("An Isle of wight report", "Isle of Wight report there"); + $mech->content_contains("Island Roads", "is still on cobrand"); +}; + +subtest "use external id for reference number" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $mech->get_ok('/report/' . $reports[0]->id); + }; + + $mech->content_contains("101202303", "Display external id as reference number"); +}; + +subtest "only original reporter can comment" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + COBRAND_FEATURES => { updates_allowed => { isleofwight => 'reporter' } }, + }, sub { + $mech->get_ok('/report/' . $reports[0]->id); + $mech->content_contains('Only the original reporter may leave updates'); + + $mech->log_in_ok('user@example.org'); + $mech->get_ok('/report/' . $reports[0]->id); + $mech->content_lacks('Only the original reporter may leave updates'); + }; +}; + +subtest "check moderation label uses correct name" => sub { + my $REPORT_URL = '/report/' . $reports[0]->id; + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight'], + }, sub { + $mech->log_out_ok; + $mech->log_in_ok( $iow_user->email ); + $mech->get_ok($REPORT_URL); + $mech->content_lacks('show-moderation'); + $mech->follow_link_ok({ text_regex => qr/^Moderate$/ }); + $mech->content_contains('show-moderation'); + $mech->submit_form_ok({ with_fields => { + problem_title => 'Good good', + problem_detail => 'Good good improved', + }}); + $mech->base_like( qr{\Q$REPORT_URL\E} ); + $mech->content_like(qr/Moderated by Island Roads/); + }; +}; + +subtest "front page summary uses report category not title" => sub { + my $category = $reports[0]->category; + ok $category, "category is not blank"; + my $title = $reports[0]->title; + ok $title, "title is not blank"; + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight'], + }, sub { + $mech->log_out_ok; + $mech->get_ok('/'); + $mech->content_like( qr/item-list__heading">$category/ ); + $mech->content_unlike( qr/item-list__heading">$title/ ); + }; +}; + +$_->delete for @reports; + +my $system_user = $mech->create_user_ok('system_user@example.org'); + +for my $status ( qw/ CLOSED FIXED DUPLICATE NOT_COUNCILS_RESPONSIBILITY NO_FURTHER_ACTION / ) { + subtest "updates which mark report as $status close it to comments" => sub { + my $dt = DateTime->now(formatter => DateTime::Format::W3CDTF->new)->add( minutes => -5 ); + my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, '', { lastupdate => $dt }); + $p->update({ external_id => $p->id }); + + my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?> + <service_requests_updates> + <request_update> + <update_id>UPDATE_ID</update_id> + <service_request_id>SERVICE_ID</service_request_id> + <service_request_id_ext>ID_EXTERNAL</service_request_id_ext> + <status>STATUS</status> + <description>This is a note</description> + <updated_datetime>UPDATED_DATETIME</updated_datetime> + </request_update> + </service_requests_updates> + }; + + my $update_dt = DateTime->now(formatter => DateTime::Format::W3CDTF->new); + + $requests_xml =~ s/STATUS/$status/; + $requests_xml =~ s/UPDATE_ID/@{[$p->id]}/; + $requests_xml =~ s/SERVICE_ID/@{[$p->id]}/; + $requests_xml =~ s/ID_EXTERNAL/@{[$p->id]}/; + $requests_xml =~ s/UPDATED_DATETIME/$update_dt/; + + my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'servicerequestupdates.xml' => $requests_xml } ); + + my $update = Open311::GetServiceRequestUpdates->new( + system_user => $system_user, + current_open311 => $o, + current_body => $isleofwight, + ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $update->process_body; + }; + + $mech->log_in_ok('user@example.org'); + $mech->get_ok('/report/' . $p->id); + $mech->content_lacks('Provide an update', "No update form on report"); + + $p->discard_changes; + is $p->get_extra_metadata('closed_updates'), 1, "report closed to updates"; + $p->comments->delete; + $p->delete; + }; +} + +subtest "fetched requests do not use the description text" => sub { + my $requests_xml = qq{<?xml version="1.0" encoding="utf-8"?> + <service_requests> + <request> + <service_request_id>638344</service_request_id> + <status>open</status> + <status_notes>This is a note.</status_notes> + <service_name>Potholes</service_name> + <service_code>potholes\@example.org</service_code> + <description>This the description of a pothole problem</description> + <agency_responsible></agency_responsible> + <service_notice></service_notice> + <requested_datetime>DATETIME</requested_datetime> + <updated_datetime>DATETIME</updated_datetime> + <expected_datetime>DATETIME</expected_datetime> + <lat>50.71086</lat> + <long>-1.29573</long> + </request> + </service_requests> + }; + + my $dt = DateTime->now(formatter => DateTime::Format::W3CDTF->new)->add( minutes => -5 ); + $requests_xml =~ s/DATETIME/$dt/gm; + + my $o = Open311->new( jurisdiction => 'mysociety', endpoint => 'http://example.com', test_mode => 1, test_get_returns => { 'requests.xml' => $requests_xml } ); + + my $update = Open311::GetServiceRequests->new( + system_user => $iow_user, + ); + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + $update->create_problems( $o, $isleofwight ); + }; + + my $p = FixMyStreet::DB->resultset('Problem')->search( + { external_id => 638344 } + )->first; + + ok $p, 'Found problem'; + is $p->title, 'Potholes problem', 'correct problem title'; + is $p->detail, 'Potholes problem', 'correct problem description'; + $p->delete; +}; + +subtest "fixing passes along the correct message" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'isleofwight', + }, sub { + my $test_res = HTTP::Response->new(); + $test_res->code(200); + $test_res->message('OK'); + $test_res->content('<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>248</update_id></request_update></service_request_updates>'); + + my $o = Open311->new( + fixmystreet_body => $isleofwight, + test_mode => 1, + test_get_returns => { 'servicerequestupdates.xml' => $test_res }, + ); + + my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, 'Title', { external_id => 1 }); + + my $c = FixMyStreet::DB->resultset('Comment')->create({ + problem => $p, user => $p->user, anonymous => 't', text => 'Update text', + problem_state => 'fixed - council', state => 'confirmed', mark_fixed => 0, + confirmed => DateTime->now(), + }); + + my $id = $o->post_service_request_update($c); + is $id, 248, 'correct update ID returned'; + my $cgi = CGI::Simple->new($o->test_req_used->content); + like $cgi->param('description'), qr/^FMS-Update:/, 'FMS update prefix included'; + unlike $cgi->param('description'), qr/The customer indicated that this issue had been fixed/, 'No fixed message included'; + + $c = $mech->create_comment_for_problem($p, $p->user, 'Name', 'Update text', 'f', 'confirmed', 'fixed - user'); + $c->discard_changes; # Otherwise cannot set_nanosecond + + $id = $o->post_service_request_update($c); + is $id, 248, 'correct update ID returned'; + $cgi = CGI::Simple->new($o->test_req_used->content); + like $cgi->param('description'), qr/^FMS-Update: \[The customer indicated that this issue had been fixed/, 'Fixed message included'; + $p->comments->delete; + $p->delete; + }; +}; + +subtest 'Check special Open311 request handling', sub { + $mech->clear_emails_ok; + my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, 'Title', { category => 'Potholes', latitude => 50.7108, longitude => -1.29573, cobrand => 'isleofwight' }); + $p->set_extra_fields({ name => 'urgent', value => 'no'}); + $p->update; + + my $test_data; + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => ['isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $test_data = FixMyStreet::Script::Reports::send(); + }; + + $p->discard_changes; + ok $p->whensent, 'Report marked as sent'; + is $p->send_method_used, 'Open311', 'Report sent via Open311'; + is $p->external_id, 248, 'Report has right external ID'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('attribute[urgent]'), undef, 'no urgent param sent'; + is $c->param('attribute[site_code]'), 'Road ID', 'road ID set'; + + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), + qr/your enquiry has been received by Island Roads/, "correct report send email text"; +}; + +subtest "comment recording triage details is not sent" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => [ 'isleofwight' ], + }, sub { + my $test_res = HTTP::Response->new(); + $test_res->code(200); + $test_res->message('OK'); + $test_res->content('<?xml version="1.0" encoding="utf-8"?><service_request_updates></service_request_updates>'); + + my $o = Open311->new( + fixmystreet_body => $isleofwight, + test_mode => 1, + test_get_returns => { 'servicerequestupdates.xml' => $test_res }, + ); + + my ($p) = $mech->create_problems_for_body( + 1, $isleofwight->id, 'Title', + { + category => 'Roads', + areas => 2636, + latitude => 50.71086, + longitude => -1.29573, + whensent => DateTime->now->add( minutes => -5 ), + send_method_used => 'Triage', + state => 'for triage', + external_id => 1, + }); + + $mech->log_out_ok; + $mech->log_in_ok($admin_user->email); + my $report_url = '/report/' . $p->id; + $mech->get_ok($report_url); + $mech->submit_form_ok( { + with_fields => { + category => 'Potholes', + include_update => 0, + } + }, + 'triage form submitted' + ); + + ok $p->comments->first, 'comment created for problem'; + + $p->update({ + send_method_used => 'Open311', + whensent => DateTime->now->add( minutes => -5 ), + }); + + my $updates = Open311::PostServiceRequestUpdates->new( + current_open311 => $o, + ); + my $id = $updates->process_body($isleofwight); + ok !$o->test_req_used, 'no open311 update sent'; + + $p->comments->delete; + $p->delete; + }; +}; + +my ($p) = $mech->create_problems_for_body(1, $isleofwight->id, '', { cobrand => 'isleofwight' }); +my $alert = FixMyStreet::DB->resultset('Alert')->create( { + parameter => $p->id, + alert_type => 'new_updates', + user => $user, + cobrand => 'isleofwight', +} )->confirm; + +subtest "sends branded alert emails" => sub { + $mech->create_comment_for_problem($p, $system_user, 'Other User', 'This is some update text', 'f', 'confirmed', undef); + $mech->clear_emails_ok; + + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight','fixmystreet'], + }, sub { + FixMyStreet::Script::Alerts::send(); + }; + + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), qr/Island Roads/, "emails are branded"; +}; + +$p->comments->delete; +$p->delete; + +subtest "check not responsible as correct text" => sub { + my ($p) = $mech->create_problems_for_body( + 1, $isleofwight->id, 'Title', + { + category => 'Roads', + areas => 2636, + latitude => 50.71086, + longitude => -1.29573, + whensent => DateTime->now->add( minutes => -5 ), + send_method_used => 'Open311', + state => 'not responsible', + external_id => 1, + }); + + my $c = FixMyStreet::DB->resultset('Comment')->create({ + problem => $p, user => $p->user, anonymous => 't', text => 'Update text', + problem_state => 'not responsible', state => 'confirmed', mark_fixed => 0, + confirmed => DateTime->now(), + }); + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight'], + }, sub { + $mech->get_ok('/report/' . $p->id); + }; + + $mech->content_contains("not Island Roads’ responsibility", "not reponsible message contains correct text"); + $p->comments->delete; + $p->delete; +}; + +subtest "sends branded confirmation emails" => sub { + $mech->log_out_ok; + $mech->clear_emails_ok; + $mech->get_ok('/around'); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + $mech->submit_form_ok( + { + button => 'submit_register', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo1 => '', + name => 'Joe Bloggs', + username => 'test-1@example.com', + category => 'Roads', + } + }, + "submit good details" + ); + + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), qr/Island Roads/, "emails are branded"; + + my $url = $mech->get_link_from_email($email); + $mech->get_ok($url); + $mech->clear_emails_ok; + }; +}; + +subtest "sends branded report sent emails" => sub { + $mech->clear_emails_ok; + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight','fixmystreet'], + }, sub { + FixMyStreet::Script::Reports::send(); + }; + $mech->email_count_is(1); + my $email = $mech->get_email; + ok $email, "got an email"; + like $mech->get_text_body_from_email($email), qr/Island Roads/, "emails are branded"; +}; + +subtest "check category extra uses correct name" => sub { + my @extras = ( { + code => 'test', + datatype => 'string', + description => 'question', + variable => 'true', + required => 'false', + order => 1, + datatype_description => 'datatype', + } ); + $contact2->set_extra_fields( @extras ); + $contact2->update; + + my $extra_details; + + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => ['isleofwight','fixmystreet'], + }, sub { + $extra_details = $mech->get_ok_json('/report/new/category_extras?category=Roads&latitude=50.71086&longitude=-1.29573'); + }; + + like $extra_details->{category_extra}, qr/Island Roads/, 'correct name in category extras'; +}; + +subtest "reports are marked for triage upon submission" => sub { + $mech->log_out_ok; + $mech->clear_emails_ok; + $mech->log_in_ok($user->email); + $mech->get_ok('/around'); + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1, skip_checks => 0 }, + ALLOWED_COBRANDS => [ 'isleofwight' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + $mech->submit_form_ok( + { + button => 'submit_register', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo1 => '', + category => 'Roads', + } + }, + "submit good details" + ); + + my $report = $user->problems->first; + ok $report, "Found the report"; + is $report->state, 'confirmed', 'report confirmed'; + + $mech->clear_emails_ok; + + FixMyStreet::Script::Reports::send(); + $report->discard_changes; + is $report->state, 'for triage', 'report marked as for triage'; + ok $report->whensent, 'report marked as sent'; + + $mech->email_count_is(1); + my $email = $mech->get_email; + like $mech->get_text_body_from_email($email), + qr/submitted to Island Roads for review/, 'correct text for email sent for Triage'; + }; +}; + +for my $cobrand ( 'fixmystreet', 'isleofwight' ) { + subtest "only categories for Triage are displayed on " . $cobrand => sub { + $mech->log_out_ok; + $mech->get_ok('/around'); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ $cobrand ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + my $f = $mech->form_name('mapSkippedForm'); + ok $f, 'found form'; + my $cats = $f->find_input('category'); + ok $cats, 'found category element'; + my @values = $cats->possible_values; + is_deeply \@values, [ '-- Pick a category --', 'Roads' ], 'correct category list'; + }; + }; + + subtest "staff user can see non Triage categories on " . $cobrand => sub { + $mech->log_out_ok; + $mech->log_in_ok($admin_user->email); + $mech->get_ok('/around'); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ $cobrand ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->submit_form_ok( { with_fields => { pc => 'PO30 5XJ', } }, + "submit location" ); + + # click through to the report page + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + my $f = $mech->form_name('mapSkippedForm'); + ok $f, 'found form'; + my $cats = $f->find_input('category'); + ok $cats, 'found category element'; + my @values = $cats->possible_values; + is_deeply \@values, [ '-- Pick a category --', 'Potholes' ], 'correct category list'; + }; + }; +} + +done_testing(); diff --git a/t/cobrand/national_assets.t b/t/cobrand/national_assets.t index 378425193..32e27079b 100644 --- a/t/cobrand/national_assets.t +++ b/t/cobrand/national_assets.t @@ -20,6 +20,7 @@ subtest 'cobrand assets includes not applied on cobrand sites', sub { ALLOWED_COBRANDS => [ 'bathnes' ], MAPIT_URL => 'http://mapit.uk/', MAP_TYPE => 'FMS,OSM,BathNES,Buckinghamshire', + STAGING_FLAGS => { skip_checks => 1 }, }, sub { $mech->get_ok("/report/new?latitude=51.494885&longitude=-2.602237"); $mech->content_lacks('buckinghamshire/assets.js'); diff --git a/t/cobrand/northamptonshire.t b/t/cobrand/northamptonshire.t new file mode 100644 index 000000000..57fe319a9 --- /dev/null +++ b/t/cobrand/northamptonshire.t @@ -0,0 +1,126 @@ +use Test::MockModule; + +use FixMyStreet::TestMech; +use Open311::PostServiceRequestUpdates; + +use_ok 'FixMyStreet::Cobrand::Northamptonshire'; + +my $mech = FixMyStreet::TestMech->new; + +use open ':std', ':encoding(UTF-8)'; + +my $ncc = $mech->create_body_ok(2234, 'Northamptonshire County Council', { + send_method => 'Open311', api_key => 'key', 'endpoint' => 'e', 'jurisdiction' => 'j', send_comments => 1 }); +my $nbc = $mech->create_body_ok(2397, 'Northampton Borough Council'); + +my $counciluser = $mech->create_user_ok('counciluser@example.com', name => 'Council User', from_body => $ncc); +my $user = $mech->create_user_ok('user@example.com', name => 'User'); + +my $ncc_contact = $mech->create_contact_ok( + body_id => $ncc->id, + category => 'Trees', + email => 'trees-2234@example.com', +); + +my $nbc_contact = $mech->create_contact_ok( + body_id => $nbc->id, + category => 'Flytipping', + email => 'flytipping-2397@example.com', +); + +my ($report) = $mech->create_problems_for_body(1, $ncc->id, 'Defect Problem', { + whensent => DateTime->now()->subtract( minutes => 5 ), + external_id => 1, + send_method_used => 'Open311', + user => $counciluser +}); + +my $comment = FixMyStreet::DB->resultset('Comment')->create( { + mark_fixed => 0, + user => $user, + problem => $report, + anonymous => 0, + text => 'this is a comment', + confirmed => DateTime->now, + state => 'confirmed', + problem_state => 'confirmed', + cobrand => 'default', +} ); + +$ncc->update( { comment_user_id => $counciluser->id } ); + + +subtest 'Check district categories hidden on cobrand' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { northamptonshire => '.' } ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + $mech->get_ok( '/around' ); + $mech->submit_form_ok( { with_fields => { pc => 'NN1 1NS' } }, + "submit location" ); + is_deeply $mech->page_errors, [], "no errors for pc"; + + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, + "follow 'skip this step' link" ); + + $mech->content_contains('Trees'); + $mech->content_lacks('Flytipping'); + }; +}; + +subtest 'Check updates not sent for defects' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { northamptonshire => '.' } ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + my $updates = Open311::PostServiceRequestUpdates->new(); + $updates->send; + }; + + $comment->discard_changes; + is $comment->send_fail_count, 0, "comment sending not attempted"; + is $comment->get_extra_metadata('cobrand_skipped_sending'), 1, "skipped sending comment"; +}; + +$report->update({ user => $user }); +$comment->update({ extra => undef }); +subtest 'check updates sent for non defects' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { northamptonshire => '.' } ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + my $updates = Open311::PostServiceRequestUpdates->new(); + $updates->send; + }; + + $comment->discard_changes; + is $comment->send_fail_count, 1, "comment sending attempted"; +}; + +my $cobrand = FixMyStreet::Cobrand::Northamptonshire->new; + +subtest 'check updates disallowed correctly' => sub { + is $cobrand->updates_disallowed($report), 0; + $report->update({ state => 'closed' }); + is $cobrand->updates_disallowed($report), 1; + $report->update({ state => 'confirmed', user => $counciluser }); + is $cobrand->updates_disallowed($report), 1; +}; + +subtest 'check pin colour / reference shown' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'northamptonshire', + #MAPIT_URL => 'http://mapit.uk/', + }, sub { + is $cobrand->pin_colour($report, 'around'), 'blue'; + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('ref: ' . $report->id); + $report->update({ user => $user }); + is $cobrand->pin_colour($report, 'around'), 'yellow'; + is $cobrand->pin_colour($report, 'my'), 'red'; + $mech->get_ok('/report/' . $report->id); + $mech->content_contains('ref: ' . $report->id); + }; +}; + +done_testing(); diff --git a/t/cobrand/oxfordshire.t b/t/cobrand/oxfordshire.t index 2625aa0d5..65c6a3864 100644 --- a/t/cobrand/oxfordshire.t +++ b/t/cobrand/oxfordshire.t @@ -1,11 +1,11 @@ - use Test::MockModule; -use FixMyStreet::Integrations::ExorRDI; use FixMyStreet::TestMech; +use FixMyStreet::Script::Alerts; my $mech = FixMyStreet::TestMech->new; my $oxon = $mech->create_body_ok(2237, 'Oxfordshire County Council'); +my $counciluser = $mech->create_user_ok('counciluser@example.com', name => 'Council User', from_body => $oxon); subtest 'check /around?ajax defaults to open reports only' => sub { my $categories = [ 'Bridges', 'Fences', 'Manhole' ]; @@ -31,7 +31,7 @@ subtest 'check /around?ajax defaults to open reports only' => sub { } FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'oxfordshire' => '.' } ], + ALLOWED_COBRANDS => 'oxfordshire', }, sub { my $json = $mech->get_ok_json( '/around?ajax=1&status=all&bbox=' . $bbox ); my $pins = $json->{pins}; @@ -47,160 +47,87 @@ subtest 'check /around?ajax defaults to open reports only' => sub { } }; -my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); -my $inspector = $mech->create_user_ok('inspector@example.com', name => 'Inspector'); -$inspector->user_body_permissions->create({ body => $oxon, permission_type => 'report_inspect' }); +my @problems = FixMyStreet::DB->resultset('Problem')->search({}, { rows => 3, order_by => 'id' })->all; -my @problems = FixMyStreet::DB->resultset('Problem')->search({}, { rows => 3 })->all; +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'oxfordshire', + MAPIT_URL => 'http://mapit.uk/', +}, sub { -subtest 'Exor RDI download appears on Oxfordshire cobrand admin' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'oxfordshire' => '.' } ], - }, sub { - $mech->log_in_ok( $superuser->email ); - $mech->get_ok('/admin'); - $mech->content_contains("Download Exor RDI"); - } -}; + subtest 'can use customer reference to search for reports' => sub { + my $problem = $problems[0]; + $problem->set_extra_metadata( customer_reference => 'ENQ12456' ); + $problem->update; -subtest "Exor RDI download doesn't appear outside of Oxfordshire cobrand admin" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - }, sub { - $mech->log_in_ok( $superuser->email ); - $mech->get_ok('/admin'); - $mech->content_lacks("Download Exor RDI"); - } -}; + $mech->get_ok('/around?pc=ENQ12456'); + is $mech->uri->path, '/report/' . $problem->id, 'redirects to report'; + }; -subtest 'Exor file looks okay' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'oxfordshire' ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->log_in_ok( $superuser->email ); - $mech->get_ok('/admin/exordefects'); - $mech->submit_form_ok( { with_fields => { - start_date => '2017-05-05', - end_date => '2017-05-05', - user_id => $inspector->id, - } }, 'submit download'); - $mech->content_contains("No inspections by that inspector in the selected date range"); - - my $dt = FixMyStreet::DB->resultset('DefectType')->create({ - body => $oxon, - name => 'Footpath', - description => 'Footpath stuff', - }); - $dt->set_extra_metadata(activity_code => 'FC'); - $dt->set_extra_metadata(defect_code => 'SFP1'); - $dt->update; - my $dt2 = FixMyStreet::DB->resultset('DefectType')->create({ - body => $oxon, - name => 'Accidental sign damage', - description => 'Accidental sign damage', - }); - $dt2->set_extra_metadata(activity_code => 'S'); - $dt2->set_extra_metadata(defect_code => 'ACC2'); - $dt2->update; - my $i = 123; - foreach my $problem (@problems) { - $problem->update({ state => 'action scheduled', external_id => $i }); - $problem->update({ defect_type => $dt }) if $i == 123; - $problem->set_extra_metadata(traffic_information => 'Signs and Cones') if $i == 124; - $problem->update({ defect_type => $dt2 }) if $i == 124; - FixMyStreet::DB->resultset('AdminLog')->create({ - admin_user => $inspector->name, - user => $inspector, - object_type => 'problem', - action => 'inspected', - object_id => $problem->id, - whenedited => DateTime->new(year => 2017, month => 5, day => 5, hour => 12), - }); - $i++; - } - $mech->submit_form_ok( { with_fields => { - start_date => '2017-05-05', - end_date => '2017-05-05', - user_id => $inspector->id, - } }, 'submit download'); - (my $rdi = $mech->content) =~ s/\r\n/\n/g; - $rdi =~ s/(I,[FMS]C?,,)\d+/$1XXX/g; # Remove unique ID figures, unknown order - is $rdi, <<EOF, "RDI file matches expected"; -"1,1.8,1.0.0.0,ENHN," -"G,1989169,,,XX,170505,1600,D,INS,N,,,," -"H,FC" -"I,FC,,XXX,"434970E 209683N Nearest postcode: OX28 4DS.",1200,,,,,,,,"TM none","123 XX TM0 "" -"J,SFP1,2,,,434970,209683,,,,," -"M,resolve,,,/CFC,," -"P,0,999999" -"G,1989169,,,XX,170505,1600,D,INS,N,,,," -"H,MC" -"I,MC,,XXX,"434970E 209683N Nearest postcode: OX28 4DS.",1200,,,,,,,,"TM none","125 XX TM0 "" -"J,SFP2,2,,,434970,209683,,,,," -"M,resolve,,,/CMC,," -"P,0,999999" -"G,1989169,,,XX,170505,1600,D,INS,N,,,," -"H,S" -"I,S,,XXX,"434970E 209683N Nearest postcode: OX28 4DS.",1200,,,,,,,,"TM Signs and Cones","124 XX TM1 "" -"J,ACC2,2,,,434970,209683,,,,," -"M,resolve,,,/CSI,," -"P,0,999999" -"X,3,3,3,3,0,0,0,3,0,3,0,0,0" -EOF - foreach my $problem (@problems) { - $problem->discard_changes; - is $problem->get_extra_metadata('rdi_processed'), undef, "Problem was not logged as sent in RDI"; - } + subtest 'check unable to fix label' => sub { + my $user = $mech->create_user_ok( 'user@example.com', name => 'Test User' ); + my $user2 = $mech->create_user_ok( 'user2@example.com', name => 'Test User2' ); - } -}; + my $problem = $problems[0]; + $problem->state( 'unable to fix' ); + $problem->update; -subtest 'Reports are marked as inspected correctly' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'oxfordshire' ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - my $date = DateTime->new(year => 2017, month => 5, day => 5, hour => 12); - - my $now = DateTime->now( - time_zone => FixMyStreet->time_zone || FixMyStreet->local_time_zone - ); - my $datetime = Test::MockModule->new('DateTime'); - $datetime->mock('now', sub { $now }); - - my $params = { - start_date => $date, - end_date => $date, - inspection_date => $date, - user => $inspector, - mark_as_processed => 1, - }; - my $rdi = FixMyStreet::Integrations::ExorRDI->new($params); - $rdi->construct; - - foreach my $problem (@problems) { - $problem->discard_changes; - is $problem->get_extra_metadata('rdi_processed'), $now->strftime( '%Y-%m-%d %H:%M' ), "Problem was logged as sent in RDI"; - } + my $alert = FixMyStreet::DB->resultset('Alert')->create( { + parameter => $problem->id, + alert_type => 'new_updates', + cobrand => 'oxfordshire', + user => $user, + } )->confirm; + + FixMyStreet::DB->resultset('Comment')->create( { + problem_state => 'unable to fix', + problem_id => $problem->id, + user_id => $user2->id, + name => 'User', + mark_fixed => 'f', + text => "this is an update", + state => 'confirmed', + confirmed => 'now()', + anonymous => 'f', + } ); + + + $mech->get_ok('/report/' . $problem->id); + $mech->content_contains('Investigation complete'); + + FixMyStreet::Script::Alerts::send(); + $mech->email_count_is(1); + my $email = $mech->get_email; + my $body = $mech->get_text_body_from_email($email); + like $body, qr/Investigation complete/, 'state correct in email'; }; -}; -subtest 'can use customer reference to search for reports' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'oxfordshire' ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - my $problem = $problems[0]; - $problem->set_extra_metadata( customer_reference => 'ENQ12456' ); - $problem->update; + subtest 'extra CSV columns are present' => sub { - $mech->log_out_ok; - $mech->get_ok('/around?pc=ENQ12456'); - is $mech->uri->path, '/report/' . $problem->id, 'redirects to report'; + $problems[1]->update({ external_id => $problems[1]->id }); + $problems[2]->update({ external_id => "123098123" }); + + $mech->log_in_ok( $counciluser->email ); + + $mech->get_ok('/dashboard?export=1'); + + my @rows = $mech->content_as_csv; + is scalar @rows, 7, '1 (header) + 6 (reports) = 7 lines'; + is scalar @{$rows[0]}, 21, '21 columns present'; + + is_deeply $rows[0], + [ + 'Report ID', 'Title', 'Detail', 'User Name', 'Category', + 'Created', 'Confirmed', 'Acknowledged', 'Fixed', 'Closed', + 'Status', 'Latitude', 'Longitude', 'Query', 'Ward', + 'Easting', 'Northing', 'Report URL', 'Site Used', + 'Reported As', 'HIAMS/Exor Ref', + ], + 'Column headers look correct'; + + is $rows[1]->[20], 'ENQ12456', 'HIAMS reference included in row'; + is $rows[2]->[20], '', 'Report without HIAMS ref has empty ref field'; + is $rows[3]->[20], '123098123', 'Older Exor report has correct ref'; }; }; -END { - done_testing(); -} +done_testing(); diff --git a/t/cobrand/peterborough.t b/t/cobrand/peterborough.t new file mode 100644 index 000000000..5d07acb9f --- /dev/null +++ b/t/cobrand/peterborough.t @@ -0,0 +1,84 @@ +use FixMyStreet::TestMech; +use FixMyStreet::Script::Reports; +use CGI::Simple; + +my $mech = FixMyStreet::TestMech->new; + +my $params = { + send_method => 'Open311', + send_comments => 1, + api_key => 'KEY', + endpoint => 'endpoint', + jurisdiction => 'home', + can_be_devolved => 1, +}; +my $peterborough = $mech->create_body_ok(2566, 'Peterborough City Council', $params); + +subtest 'open311 request handling', sub { + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => ['peterborough' ], + MAPIT_URL => 'http://mapit.uk/', + }, sub { + my $contact = $mech->create_contact_ok(body_id => $peterborough->id, category => 'Trees', email => 'TREES'); + my ($p) = $mech->create_problems_for_body(1, $peterborough->id, 'Title', { category => 'Trees', latitude => 52.5608, longitude => 0.2405, cobrand => 'peterborough' }); + $p->push_extra_fields({ name => 'emergency', value => 'no'}); + $p->push_extra_fields({ name => 'private_land', value => 'no'}); + $p->push_extra_fields({ name => 'PCC-light', value => 'whatever'}); + $p->push_extra_fields({ name => 'PCC-skanska-csc-ref', value => '1234'}); + $p->push_extra_fields({ name => 'tree_code', value => 'tree-42'}); + $p->update; + + my $test_data = FixMyStreet::Script::Reports::send(); + + $p->discard_changes; + ok $p->whensent, 'Report marked as sent'; + is $p->send_method_used, 'Open311', 'Report sent via Open311'; + is $p->external_id, 248, 'Report has correct external ID'; + is $p->get_extra_field_value('emergency'), 'no'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('attribute[description]'), "Title Test 1 for " . $peterborough->id . " Detail\r\n\r\nSkanska CSC ref: 1234", 'Ref added to description'; + is $c->param('attribute[emergency]'), undef, 'no emergency param sent'; + is $c->param('attribute[private_land]'), undef, 'no private_land param sent'; + is $c->param('attribute[PCC-light]'), undef, 'no pcc- param sent'; + is $c->param('attribute[tree_code]'), 'tree-42', 'tree_code param sent'; + }; +}; + +subtest "extra update params are sent to open311" => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'peterborough', + }, sub { + my $contact = $mech->create_contact_ok(body_id => $peterborough->id, category => 'Trees', email => 'TREES'); + my $test_res = HTTP::Response->new(); + $test_res->code(200); + $test_res->message('OK'); + $test_res->content('<?xml version="1.0" encoding="utf-8"?><service_request_updates><request_update><update_id>ezytreev-248</update_id></request_update></service_request_updates>'); + + my $o = Open311->new( + fixmystreet_body => $peterborough, + test_mode => 1, + test_get_returns => { 'servicerequestupdates.xml' => $test_res }, + ); + + my ($p) = $mech->create_problems_for_body(1, $peterborough->id, 'Title', { external_id => 1, category => 'Trees' }); + + my $c = FixMyStreet::DB->resultset('Comment')->create({ + problem => $p, user => $p->user, anonymous => 't', text => 'Update text', + problem_state => 'fixed - council', state => 'confirmed', mark_fixed => 0, + confirmed => DateTime->now(), + }); + + my $id = $o->post_service_request_update($c); + is $id, "ezytreev-248", 'correct update ID returned'; + my $cgi = CGI::Simple->new($o->test_req_used->content); + is $cgi->param('description'), '[Customer FMS update] Update text', 'FMS update prefix included'; + is $cgi->param('service_request_id_ext'), $p->id, 'Service request ID included'; + is $cgi->param('service_code'), $contact->email, 'Service code included'; + }; +}; + +done_testing; diff --git a/t/cobrand/restriction.t b/t/cobrand/restriction.t index 63fe326b1..185f365c8 100644 --- a/t/cobrand/restriction.t +++ b/t/cobrand/restriction.t @@ -19,7 +19,10 @@ package main; use FixMyStreet::TestMech; -my $c = FixMyStreet::App->new; +use Catalyst::Test 'FixMyStreet::App'; + +my ($res, $c) = ctx_request('/'); + my $cobrand = FixMyStreet::Cobrand::Tester->new({c => $c}); $c->stash->{cobrand} = $cobrand; diff --git a/t/cobrand/staging.t b/t/cobrand/staging.t new file mode 100644 index 000000000..5d79daa4b --- /dev/null +++ b/t/cobrand/staging.t @@ -0,0 +1,18 @@ +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +subtest 'staging banner is visible by default on staging sites' => sub { + $mech->get_ok('/'); + $mech->content_contains('<div class="dev-site-notice">'); +}; + +FixMyStreet::override_config { + STAGING_FLAGS => { hide_staging_banner => 1 }, +}, sub { + subtest 'staging banner can be hidden through STAGING_FLAGS config' => sub { + $mech->get_ok('/'); + $mech->content_lacks('<div class="dev-site-notice">'); + }; +}; + +done_testing(); diff --git a/t/cobrand/tfl.t b/t/cobrand/tfl.t new file mode 100644 index 000000000..8ddc3d671 --- /dev/null +++ b/t/cobrand/tfl.t @@ -0,0 +1,1089 @@ +use FixMyStreet::TestMech; +use FixMyStreet::App; +use FixMyStreet::Script::Reports; +use FixMyStreet::Script::Questionnaires; + +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +my $mech = FixMyStreet::TestMech->new; + +use t::Mock::Tilma; +my $tilma = t::Mock::Tilma->new; +LWP::Protocol::PSGI->register($tilma->to_psgi_app, host => 'tilma.mysociety.org'); + + +my $body = $mech->create_body_ok(2482, 'TfL'); +FixMyStreet::DB->resultset('BodyArea')->find_or_create({ + area_id => 2483, # Hounslow + body_id => $body->id, +}); +FixMyStreet::DB->resultset('BodyArea')->find_or_create({ + area_id => 2457, # Epsom Ewell, outside London, for bus stop test + body_id => $body->id, +}); +my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); +my $staffuser = $mech->create_user_ok('counciluser@example.com', name => 'Council User', from_body => $body, password => 'password'); +$staffuser->user_body_permissions->create({ + body => $body, + permission_type => 'contribute_as_body', +}); +$staffuser->user_body_permissions->create({ + body => $body, + permission_type => 'default_to_body', +}); +my $user = $mech->create_user_ok('londonresident@example.com'); + +my $bromley = $mech->create_body_ok(2482, 'Bromley'); +my $bromleyuser = $mech->create_user_ok('bromleyuser@bromley.example.com', name => 'Bromley Staff', from_body => $bromley); +$mech->create_contact_ok( + body_id => $bromley->id, + category => 'Accumulated Litter', + email => 'litter-bromley@example.com', +); +my $bromley_flooding = $mech->create_contact_ok( + body_id => $bromley->id, + category => 'Flooding (Bromley)', + email => 'litter-bromley@example.com', +); +$bromley_flooding->set_extra_metadata(display_name => 'Flooding'); +$bromley_flooding->update; + +my $bromley_flytipping = $mech->create_contact_ok( + body_id => $bromley->id, + category => 'Flytipping (Bromley)', + email => 'flytipping-bromley@example.com', +); +$bromley_flytipping->set_extra_metadata(group => [ 'Street cleaning' ]); +$bromley_flytipping->update; + +my $contact1 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Bus stops', + email => 'busstops@example.com', +); +$contact1->set_extra_metadata(group => [ 'Bus things' ]); +$contact1->set_extra_fields( + { + code => 'leaning', + description => 'Is the pole leaning?', + datatype => 'string', + }, + { + code => 'stop_code', + description => 'Stop number', + datatype => 'string', + automated => 'hidden_field', + } +); +$contact1->update; +my $contact2 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Traffic lights', + email => 'trafficlights@example.com', +); +$contact2->set_extra_fields({ + code => "safety_critical", + description => "Safety critical", + automated => "hidden_field", + order => 1, + datatype => "singlevaluelist", + values => [ + { + name => "Yes", + key => "yes" + }, + { + name => "No", + key => "no" + } + ] +}); +$contact2->update; +my $contact2b = $mech->create_contact_ok( + body_id => $body->id, + category => 'Timings', + email => 'trafficlighttimings@example.com', +); + +my $contact3 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Pothole', + email => 'pothole@example.com', +); +$contact3->set_extra_fields({ + code => "safety_critical", + description => "Safety critical", + automated => "hidden_field", + order => 1, + datatype => "singlevaluelist", + values => [ + { + name => "Yes", + key => "yes" + }, + { + name => "No", + key => "no" + } + ] +}); +$contact3->update; +my $contact4 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Flooding', + email => 'flooding@example.com', +); +$contact4->set_extra_fields( + { + code => "safety_critical", + description => "Safety critical", + automated => "hidden_field", + order => 1, + datatype => "singlevaluelist", + values => [ + { + name => "Yes", + key => "yes" + }, + { + name => "No", + key => "no" + } + ] + }, + { + code => "location", + description => "Where is the flooding?", + variable => "true", + order => 1, + required => "true", + datatype => "singlevaluelist", + values => [ + { + name => "Carriageway", + key => "carriageway" + }, + { + name => "Footway", + key => "footway" + } + ] + } +); +$contact4->update; +my $contact5 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Trees', + email => 'AOAT', +); +my $contact6 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Grit bins', + email => 'AOAT,gritbins@example.com', +); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'tfl', 'bromley', 'fixmystreet'], + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + internal_ips => { tfl => [ '127.0.0.1' ] }, + base_url => { + tfl => 'https://street.tfl' + }, + borough_email_addresses => { tfl => { + AOAT => [ + { + email => 'hounslow@example.com', + areas => [ 2483 ], + }, + { + email => 'bromley@example.com', + areas => [ 2482 ], + }, + ], + } }, + anonymous_account => { + tfl => 'anonymous' + }, + contact_name => { + tfl => 'TfL Street Care', + }, + do_not_reply_email => { + tfl => 'fms-tfl-DO-NOT-REPLY@example.com', + }, + send_questionnaire => { + fixmystreet => { + TfL => 0, + } + }, + }, +}, sub { + +$mech->host("tfl.fixmystreet.com"); + +subtest "test report creation anonymously by button" => sub { + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'BR1 3UH', } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok( + { + button => 'report_anonymously', + with_fields => { + title => 'Anonymous Test Report 1', + detail => 'Test report details.', + category => 'Bus stops', + } + }, + "submit report anonymously" + ); + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Anonymous Test Report 1'}); + ok $report, "Found the report"; + + $mech->content_contains('Your issue is on its way to Transport for London'); + $mech->content_contains('Your reference for this report is FMS' . $report->id) or diag $mech->content; + + is_deeply $mech->page_errors, [], "check there were no errors"; + + is $report->state, 'confirmed', "report confirmed"; + $mech->get_ok( '/report/' . $report->id ); + + is $report->bodies_str, $body->id; + is $report->name, 'Anonymous user'; + is $report->user->email, 'anonymous@tfl.gov.uk'; + is $report->anonymous, 1; # Doesn't change behaviour here, but uses anon account's name always + is $report->get_extra_metadata('contributed_as'), 'anonymous_user'; + + my $alert = FixMyStreet::App->model('DB::Alert')->find( { + user => $report->user, + alert_type => 'new_updates', + parameter => $report->id, + } ); + is $alert, undef, "no alert created"; + + $mech->not_logged_in_ok; +}; + +subtest "test report creation anonymously by staff user" => sub { + $mech->clear_emails_ok; + $mech->log_in_ok( $staffuser->email ); + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'BR1 3UH', } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok( + { + button => 'report_anonymously', + with_fields => { + title => 'Anonymous Test Report 2', + detail => 'Test report details.', + category => 'Bus stops', + } + }, + "submit report" + ); + is_deeply $mech->page_errors, [], "check there were no errors"; + + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Anonymous Test Report 2'}); + ok $report, "Found the report"; + + $mech->content_contains('Your issue is on its way to Transport for London'); + $mech->content_contains('Your reference for this report is FMS' . $report->id) or diag $mech->content; + + is $report->state, 'confirmed', "report confirmed"; + $mech->get_ok( '/report/' . $report->id ); + + $report->update({ state => 'fixed - council' }); + my $json = $mech->get_ok_json('/around/nearby?latitude=' . $report->latitude . '&longitude=' . $report->longitude); + is @{$json->{pins}}, 2, 'right number of pins'; + + is $report->bodies_str, $body->id; + is $report->name, 'Anonymous user'; + is $report->user->email, 'anonymous@tfl.gov.uk'; + is $report->anonymous, 1; + is $report->get_extra_metadata('contributed_as'), 'anonymous_user'; + + my $alerts = FixMyStreet::App->model('DB::Alert')->search( { + alert_type => 'new_updates', + parameter => $report->id, + } ); + is $alerts->count, 0, "no alerts created"; + ok $mech->email_count_is(0), "no emails sent"; + + $mech->log_out_ok; +}; + +FixMyStreet::DB->resultset("Problem")->delete_all; + +subtest "test report creation and reference number" => sub { + $mech->log_in_ok( $user->email ); + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'BR1 3UH', } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok( + { + with_fields => { + title => 'Test Report 1', + detail => 'Test report details.', + name => 'Joe Bloggs', + may_show_name => '1', + category => 'Bus stops', + } + }, + "submit good details" + ); + + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + ok $report, "Found the report"; + + $mech->content_contains('Your issue is on its way to Transport for London'); + $mech->content_contains('Your reference for this report is FMS' . $report->id) or diag $mech->content; + + is_deeply $mech->page_errors, [], "check there were no errors"; + + is $report->state, 'confirmed', "report confirmed"; + + is $report->bodies_str, $body->id; + is $report->name, 'Joe Bloggs'; +}; + +subtest "test bus report creation outside London, .com" => sub { + $mech->host('www.fixmystreet.com'); + $mech->get_ok('/report/new?latitude=51.345714&longitude=-0.227959'); + $mech->content_lacks('Bus things'); + $mech->host('tfl.fixmystreet.com'); +}; + +subtest "test bus report creation outside London" => sub { + $mech->get_ok('/report/new?latitude=51.345714&longitude=-0.227959'); + $mech->submit_form_ok( + { + with_fields => { + # A bus stop in East Ewell + latitude => 51.345714, + longitude => -0.227959, + title => 'Test outwith London', + detail => 'Test report details.', + name => 'Joe Bloggs', + may_show_name => '1', + category => 'Bus stops', + } + }, + "submit good details" + ); + $mech->content_contains('Your issue is on its way to Transport for London'); + is_deeply $mech->page_errors, [], "check there were no errors"; + + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test outwith London'}); + ok $report, "Found the report"; + is $report->state, 'confirmed', "report confirmed"; + is $report->bodies_str, $body->id; + $report->delete; + + $mech->log_out_ok; +}; + +subtest "extra information included in email" => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + $report->set_extra_fields({ name => 'stop_code', value => '12345678' }); + $report->update; + my $id = $report->id; + + $mech->clear_emails_ok; + FixMyStreet::Script::Reports::send(); + my @email = $mech->get_email; + is $email[0]->header('To'), 'TfL <busstops@example.com>'; + like $mech->get_text_body_from_email($email[0]), qr/Report reference: FMS$id/, "FMS-prefixed ID in TfL email"; + like $mech->get_text_body_from_email($email[0]), qr/Stop number: 12345678/, "Bus stop code in TfL email"; + is $email[1]->header('To'), $report->user->email; + is $email[1]->header('From'), '"TfL Street Care" <fms-tfl-DO-NOT-REPLY@example.com>'; + like $mech->get_text_body_from_email($email[1]), qr/report's reference number is FMS$id/, "FMS-prefixed ID in reporter email"; + $mech->clear_emails_ok; + + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('FMS' . $report->id) or diag $mech->content; +}; + +subtest 'Dashboard CSV extra columns' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + $report->set_extra_fields({ name => 'leaning', value => 'Yes' }); + $report->update; + + $mech->log_in_ok( $staffuser->email ); + $mech->get_ok('/dashboard?export=1&category=Bus+stops'); + $mech->content_contains('Category,Subcategory'); + $mech->content_contains('Query,Borough'); + $mech->content_contains(',"Safety critical","Delivered to","Closure email at","Reassigned at","Reassigned by","Is the pole leaning?"'); + $mech->content_contains('"Bus things","Bus stops"'); + $mech->content_contains('"BR1 3UH",Bromley,'); + $mech->content_contains(',,,no,busstops@example.com,,,,Yes'); + + $report->set_extra_fields({ name => 'safety_critical', value => 'yes' }); + $report->anonymous(1); + $report->update; + my $dt = DateTime->now(); + FixMyStreet::DB->resultset("AdminLog")->create({ + action => 'category_change', + whenedited => $dt, + object_id => $report->id, + object_type => 'problem', + admin_user => $staffuser->name, + user => $staffuser, + }); + $mech->get_ok('/dashboard?export=1'); + $mech->content_contains('Query,Borough'); + $mech->content_contains(',"Safety critical","Delivered to","Closure email at","Reassigned at","Reassigned by"'); + $mech->content_contains('(anonymous ' . $report->id . ')'); + $mech->content_contains(',,,yes,busstops@example.com,,' . $dt . ',"Council User"'); +}; + +subtest 'Inspect form state choices' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + my $id = $report->id; + $mech->get_ok("/report/$id"); + $mech->content_lacks('for triage'); + $mech->content_lacks('action scheduled'); +}; + +subtest "change category, report resent to new location" => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + my $id = $report->id; + + $mech->log_in_ok( $superuser->email ); + $mech->get_ok("/admin/report_edit/$id"); + $mech->content_lacks('Timings'); + $mech->submit_form_ok({ with_fields => { category => 'Traffic lights' } }); + + FixMyStreet::Script::Reports::send(); + my @email = $mech->get_email; + is $email[0]->header('To'), 'TfL <trafficlights@example.com>'; + $mech->clear_emails_ok; + + $mech->log_out_ok; +}; + +for my $test ( + [ 'BR1 3UH', 'tfl.fixmystreet.com', 'Trees', 'TfL <bromley@example.com>', 'Bromley borough team', 'reference number is FMS' ], + [ 'BR1 3UH', 'www.fixmystreet.com', 'Trees', 'TfL <bromley@example.com>', 'Bromley borough team', 'reference number is' ], + [ 'BR1 3UH', 'bromley.fixmystreet.com', 'Trees', 'TfL <bromley@example.com>', 'Bromley borough team', '' ], + [ 'TW7 5JN', 'tfl.fixmystreet.com', 'Trees', 'TfL <hounslow@example.com>', 'Hounslow borough team', 'reference number is FMS' ], + [ 'TW7 5JN', 'www.fixmystreet.com', 'Trees', 'TfL <hounslow@example.com>', 'Hounslow borough team', 'reference number is' ], + [ 'TW7 5JN', 'tfl.fixmystreet.com', 'Grit bins', 'TfL <hounslow@example.com>, TfL <gritbins@example.com>', 'Hounslow borough team and additional address', 'reference number is FMS' ], + [ 'TW7 5JN', 'www.fixmystreet.com', 'Grit bins', 'TfL <hounslow@example.com>, TfL <gritbins@example.com>', 'Hounslow borough team and additional address', 'reference number is' ], +) { + my ($postcode, $host, $category, $to, $name, $ref ) = @$test; + subtest "test report is sent to $name on $host" => sub { + $mech->host($host); + $mech->log_in_ok( $user->email ); + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => $postcode, } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok( + { + with_fields => { + title => 'Test Report for borough team', + detail => 'Test report details.', + may_show_name => '1', + category => $category, + $host eq 'bromley.fixmystreet.com' ? ( + fms_extra_title => 'DR', + first_name => "Joe", + last_name => "Bloggs", + ) : ( + name => 'Joe Bloggs', + ), + } + }, + "submit good details" + ); + + $mech->clear_emails_ok; + FixMyStreet::Script::Reports::send(); + my @email = $mech->get_email; + is $email[0]->header('To'), $to, 'Sent to correct address'; + like $email[0]->as_string, qr/iEYI87gX6Upb\+tKYzrSmN83pTnv606AOtahHTepSm/, 'Right logo'; + like $mech->get_text_body_from_email($email[0]), qr/https:\/\/street.tfl/, 'Correct link'; + like $mech->get_text_body_from_email($email[1]), qr/$ref/, "Correct reference number in reporter email" if $ref; + $mech->clear_emails_ok; + FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report for borough team'})->delete; + }; +} + +$mech->host("tfl.fixmystreet.com"); + +subtest 'check lookup by reference' => sub { + my $id = FixMyStreet::DB->resultset("Problem")->first->id; + + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => 'FMS12345' } }, 'bad ref'); + $mech->content_contains('Searching found no reports'); + + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => "FMS$id" } }, 'good FMS-prefixed ref'); + is $mech->uri->path, "/report/$id", "redirected to report page when using FMS-prefixed ref"; + + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => "fms $id" } }, 'good FMS-prefixed with a space ref'); + is $mech->uri->path, "/report/$id", "redirected to report page when using FMS-prefixed ref"; + + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => "$id" } }, 'good ref'); + is $mech->uri->path, "/report/$id", "redirected to report page when using non-prefixed ref"; +}; + +for my $test ( + { + states => [ 'confirmed' ], + colour => 'red' + }, + { + states => ['action scheduled', 'in progress', 'investigating', 'planned'], + colour => 'orange' + }, + { + states => [ FixMyStreet::DB::Result::Problem->fixed_states, FixMyStreet::DB::Result::Problem->closed_states ], + colour => 'green' + }, +) { + subtest 'check ' . $test->{colour} . ' pin states' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + my $url = '/around?ajax=1&bbox=' . ($report->longitude - 0.01) . ',' . ($report->latitude - 0.01) + . ',' . ($report->longitude + 0.01) . ',' . ($report->latitude + 0.01); + + for my $state ( @{ $test->{states} } ) { + $report->update({ state => $state }); + my $json = $mech->get_ok_json( $url ); + my $colour = $json->{pins}[0][2]; + is $colour, $test->{colour}, 'correct ' . $test->{colour} . ' pin for state ' . $state; + } + }; +} + +subtest 'check correct base URL & title in AJAX pins' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + my $url = '/around?ajax=1&bbox=' . ($report->longitude - 0.01) . ',' . ($report->latitude - 0.01) + . ',' . ($report->longitude + 0.01) . ',' . ($report->latitude + 0.01); + + $report->update({ state => 'confirmed' }); + $report->discard_changes; + is $report->cobrand, 'tfl', 'Report made on TfL cobrand'; + + $mech->host("fixmystreet.com"); + my $json = $mech->get_ok_json( $url ); + is $json->{pins}[0][4], $report->category . " problem", "category is used for title" or diag $mech->content; + is $json->{pins}[0][7], "https://street.tfl", "base_url is included and correct" or diag $mech->content; + + $mech->host("tfl.fixmystreet.com"); + $json = $mech->get_ok_json( $url ); + is $json->{pins}[0][4], $report->title, "title is shown on TfL cobrand" or diag $mech->content; + is $json->{pins}[0][7], undef, "base_url is not present on TfL cobrand response"; + + $mech->host("fixmystreet.com"); + $report->update({cobrand => 'fixmystreet'}); + $json = $mech->get_ok_json( $url ); + is $json->{pins}[0][4], $report->title, "title is shown if report made on fixmystreet cobrand" or diag $mech->content; + is $json->{pins}[0][7], undef, "base_url is not present if report made on fixmystreet cobrand"; + + $report->update({cobrand => 'tfl'}); + $mech->host("tfl.fixmystreet.com"); +}; + +subtest 'check report age on /around' => sub { + $mech->log_in_ok($staffuser->email); + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + $report->update({ state => 'confirmed' }); + + $mech->get_ok( '/around?lat=' . $report->latitude . '&lon=' . $report->longitude ); + $mech->content_contains($report->title); + $mech->content_contains('item-list__item__borough">Bromley'); + + $report->update({ + confirmed => \"current_timestamp-'7 weeks'::interval", + whensent => \"current_timestamp-'7 weeks'::interval", + lastupdate => \"current_timestamp-'7 weeks'::interval", + }); + + $mech->get_ok( '/around?lat=' . $report->latitude . '&lon=' . $report->longitude ); + $mech->content_lacks($report->title); + + $report->update({ + confirmed => \"current_timestamp", + whensent => \"current_timestamp", + lastupdate => \"current_timestamp", + }); +}; + +subtest 'check report age in general' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); + $report->update({ state => 'confirmed' }); + $mech->get_ok('/report/' . $report->id); + $report->update({ lastupdate => \"current_timestamp-'4 years'::interval" }); + $mech->get('/report/' . $report->id); + is $mech->res->code, 404; + $report->update({ lastupdate => \"current_timestamp" }); +}; + +subtest 'TfL admin allows inspectors to be assigned to borough areas' => sub { + $mech->log_in_ok($superuser->email); + + $mech->get_ok("/admin/users/" . $staffuser->id) or diag $mech->content; + + $mech->submit_form_ok( { with_fields => { + area_ids => [2482], + } } ); + + $staffuser->discard_changes; + is_deeply $staffuser->area_ids, [2482], "User assigned to Bromley LBO area"; + + $staffuser->update({ area_ids => undef}); # so login below doesn't break +}; + +my $report = FixMyStreet::DB->resultset("Problem")->find({ title => 'Test Report 1'}); +$report->update({ cobrand => 'fixmystreet' }); +$staffuser->add_to_planned_reports($report); + +for my $host ( 'www.fixmystreet.com', 'tfl.fixmystreet.com' ) { + subtest "Leave an update on a shortlisted report on $host, get an email" => sub { + $mech->host($host); + $mech->log_in_ok( $user->email ); + $mech->get_ok('/report/' . $report->id); + $mech->submit_form_ok({ with_fields => { update => 'This is an update' }}); + my $email = $mech->get_email; + my $text = $mech->get_text_body_from_email; + like $text, qr/This is an update/, 'Right email'; + like $text, qr/street.tfl/, 'Right url'; + like $text, qr/Street Care/, 'Right name'; + like $email->as_string, qr/iEYI87gX6Upb\+tKYzrSmN83pTnv606AOtahHTepSm/, 'Right logo'; + }; +} + +subtest 'TfL staff can access TfL admin' => sub { + $mech->log_in_ok( $staffuser->email ); + $mech->get_ok('/admin'); + $mech->content_contains( 'This is the administration interface for' ); + $mech->log_out_ok; +}; + +subtest 'Bromley staff cannot access TfL admin' => sub { + $mech->log_in_ok( $bromleyuser->email ); + ok $mech->get('/admin'); + is $mech->res->code, 403, "got 403"; + $mech->log_out_ok; +}; + +subtest 'Test passwords work appropriately' => sub { + $mech->host('www.fixmystreet.com'); + $mech->get_ok('/auth'); + $user->password('dotcom'); + $user->update; + $mech->submit_form_ok( + { with_fields => { username => $user->email, password_sign_in => 'dotcom' } }, + "sign in using form" ); + $mech->content_contains('Your account'); + $mech->host('tfl.fixmystreet.com'); + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $user->email, password_sign_in => 'dotcom' } }, + "sign in using form" ); + $mech->content_lacks('Your account'); + + $user->password('tfl'); + $user->update; + $mech->submit_form_ok( + { with_fields => { username => $user->email, password_sign_in => 'tfl' } }, + "sign in using form" ); + $mech->content_contains('Your account'); + $mech->host('www.fixmystreet.com'); + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $user->email, password_sign_in => 'tfl' } }, + "sign in using form" ); + $mech->content_lacks('Your account'); +}; + +my $tfl_report; +subtest 'Test user reports are visible on cobrands appropriately' => sub { + ($tfl_report) = $mech->create_problems_for_body(1, $body->id, 'Test TfL report made on TfL', { cobrand => 'tfl' }); + $mech->create_problems_for_body(1, $body->id, 'Test TfL report made on .com', { cobrand => 'fixmystreet' }); + $mech->create_problems_for_body(1, $bromley->id, 'Test Bromley report made on .com', { cobrand => 'fixmystreet' }); + + $mech->log_in_ok('test@example.com'); + $mech->get_ok('/my'); + $mech->content_contains('1 to 2 of 2'); + $mech->content_contains('Test TfL report made on .com'); + $mech->content_lacks('Test TfL report made on TfL'); + $mech->content_contains('Test Bromley report'); + + $mech->host('tfl.fixmystreet.com'); + $mech->log_in_ok('test@example.com'); + $mech->get_ok('/my'); + $mech->content_contains('1 to 2 of 2'); + $mech->content_contains('Test TfL report made on .com'); + $mech->content_contains('Test TfL report made on TfL'); + $mech->content_lacks('Test Bromley report'); +}; + +subtest 'Test public reports are visible on cobrands appropriately' => sub { + $mech->get_ok('/around?pc=SW1A+1AA'); + $mech->content_contains('Test TfL report made on .com'); + $mech->content_contains('Test TfL report made on TfL'); + $mech->content_lacks('Test Bromley report'); + + $mech->host('www.fixmystreet.com'); + $mech->get_ok('/around?pc=SW1A+1AA'); + $mech->content_contains('Test TfL report made on .com'); + $mech->content_lacks('Test TfL report made on TfL'); + $mech->content_contains('Test Bromley report'); + $mech->content_contains('https://street.tfl/report/' . $tfl_report->id); + $mech->content_contains('Other problem'); +}; + +subtest 'Test no questionnaire sending' => sub { + $report->update({ send_questionnaire => 1, whensent => \"current_timestamp-'7 weeks'::interval" }); + FixMyStreet::Script::Questionnaires::send(); + $mech->email_count_is(0); +}; + +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'tfl', 'bromley', 'fixmystreet' ], + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + internal_ips => { tfl => [ '127.0.0.1' ] }, + safety_critical_categories => { tfl => { + Pothole => 1, + Flooding => { + location => [ "carriageway" ], + }, + } }, + anonymous_account => { + tfl => 'anonymous' + }, + do_not_reply_email => { + tfl => 'fms-tfl-DO-NOT-REPLY@example.com', + }, + }, +}, sub { + +for my $test ( + { + host => 'www.fixmystreet.com', + name => "test red route categories", + lat => 51.4039, + lon => 0.018697, + expected => [ + 'Accumulated Litter', # Tests TfL->_cleaning_categories + 'Bus stops', + 'Flooding', + 'Flytipping (Bromley)', # In the 'Street cleaning' group + 'Grit bins', + 'Pothole', + 'Timings', + 'Traffic lights', + 'Trees' + ], + }, + { + host => 'www.fixmystreet.com', + name => "test non-red route categories", + lat => 51.4021, + lon => 0.01578, + expected => [ + 'Accumulated Litter', # Tests TfL->_cleaning_categories + 'Bus stops', + 'Flooding (Bromley)', + 'Flytipping (Bromley)', # In the 'Street cleaning' group + 'Grit bins', + 'Timings', + 'Traffic lights', + 'Trees' + ], + }, + { + host => 'tfl.fixmystreet.com', + name => "test red route categories", + lat => 51.4039, + lon => 0.018697, + expected => [ + 'Bus stops', + 'Flooding', + 'Grit bins', + 'Pothole', + 'Timings', + 'Traffic lights', + 'Trees' + ], + }, + { + host => 'tfl.fixmystreet.com', + name => "test non-red route categories", + lat => 51.4021, + lon => 0.01578, + expected => [ + 'Bus stops', + 'Flooding', + 'Grit bins', + 'Pothole', + 'Timings', + 'Traffic lights', + 'Trees' + ], + }, + { + host => 'bromley.fixmystreet.com', + name => "test red route categories", + lat => 51.4039, + lon => 0.018697, + expected => [ + 'Accumulated Litter', + 'Bus stops', + 'Flooding', + 'Flytipping (Bromley)', + 'Grit bins', + 'Pothole', + 'Timings', + 'Traffic lights', + 'Trees' + ], + }, + { + host => 'bromley.fixmystreet.com', + name => "test non-red route categories", + lat => 51.4021, + lon => 0.01578, + expected => [ + 'Accumulated Litter', + 'Bus stops', + 'Flooding (Bromley)', + 'Flytipping (Bromley)', + 'Grit bins', + 'Timings', + 'Traffic lights', + 'Trees' + ], + }, +) { + subtest $test->{name} . ' on ' . $test->{host} => sub { + $mech->host($test->{host}); + my $resp = $mech->get_ok_json( '/report/new/ajax?latitude=' . $test->{lat} . '&longitude=' . $test->{lon} ); + my @actual = sort keys %{ $resp->{by_category} }; + is_deeply \@actual, $test->{expected}; + }; +} + +for my $host ( 'tfl.fixmystreet.com', 'www.fixmystreet.com', 'bromley.fixmystreet.com' ) { + for my $test ( + { + name => "test non-safety critical category", + safety_critical => 'no', + category => "Traffic lights", + subject => "Problem Report: Test Report", + }, + { + name => "test safety critical category", + safety_critical => 'yes', + category => "Pothole", + subject => "Dangerous Pothole Report: Test Report", + pc => "BR1 3EF", # this is on a red route (according to Mock::MapIt and Mock::Tilma anyway) + }, + { + name => "test category extra field - safety critical", + safety_critical => 'yes', + category => "Flooding", + extra_fields => { + location => "carriageway", + }, + subject => "Dangerous Flooding Report: Test Report", + pc => "BR1 3EF", # this is on a red route (according to Mock::MapIt and Mock::Tilma anyway) + }, + { + name => "test category extra field - non-safety critical", + safety_critical => 'no', + category => "Flooding", + extra_fields => { + location => "footway", + }, + subject => "Problem Report: Test Report", + pc => "BR1 3EF", # this is on a red route (according to Mock::MapIt and Mock::Tilma anyway) + }, + ) { + subtest $test->{name} . ' on ' . $host => sub { + $mech->log_in_ok( $user->email ); + $mech->host($host); + $mech->get_ok('/around'); + my $pc = $test->{pc} || 'BR1 3UH'; + $mech->submit_form_ok( { with_fields => { pc => $pc, } }, "submit location ($pc)" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok( + { + with_fields => { + category => $test->{category} + }, + button => 'submit_category_part_only', + } + ); + $mech->submit_form_ok( + { + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + may_show_name => '1', + category => $test->{category}, + %{ $test->{extra_fields} || {} }, + $host eq 'bromley.fixmystreet.com' ? ( + fms_extra_title => 'DR', + first_name => "Joe", + last_name => "Bloggs", + ) : ( + name => 'Joe Bloggs', + ), + } + }, + "submit report form" + ); + + my $report = FixMyStreet::App->model('DB::Problem')->to_body( $body->id )->search(undef, { + order_by => { -desc => 'id' }, + })->first; + ok $report, "Found the report"; + + is $report->get_extra_field_value('safety_critical'), $test->{safety_critical}, "safety critical flag set to " . $test->{safety_critical}; + + $mech->clear_emails_ok; + FixMyStreet::Script::Reports::send(); + my @email = $mech->get_email; + is $email[0]->header('Subject'), $test->{subject}; + if ($test->{safety_critical} eq 'yes') { + like $mech->get_text_body_from_email($email[0]), qr/This report is marked as safety critical./, "Safety critical message included in email body"; + } + $mech->clear_emails_ok; + + + $mech->log_out_ok; + }; + } +} +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'tfl', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { internal_ips => { tfl => [ '127.0.0.1' ] } }, +}, sub { + subtest 'On internal network, user not asked to sign up for 2FA' => sub { + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $staffuser->email, password_sign_in => 'password' } }, + "sign in using form" ); + $mech->content_contains('Your account'); + }; + subtest 'On internal network, user with 2FA not asked to enter it' => sub { + use Auth::GoogleAuth; + my $auth = Auth::GoogleAuth->new; + my $code = $auth->code; + + $staffuser->set_extra_metadata('2fa_secret', $auth->secret32); + $staffuser->update; + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $staffuser->email, password_sign_in => 'password' } }, + "sign in using form" ); + $mech->content_lacks('generate a two-factor code'); + $mech->content_contains('Your account'); + }; + subtest 'On internal network, cannot disable 2FA' => sub { + $mech->get_ok('/auth/generate_token'); + $mech->content_contains('Change two-factor'); + $mech->content_lacks('Deactivate two-factor'); + $staffuser->unset_extra_metadata('2fa_secret'); + $staffuser->update; + }; +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'tfl', + MAPIT_URL => 'http://mapit.uk/', +}, sub { + subtest 'On external network, user asked to sign up for 2FA' => sub { + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $staffuser->email, password_sign_in => 'password' } }, + "sign in using form" ); + $mech->content_contains('requires two-factor authentication'); + }; + subtest 'On external network, user with 2FA asked to enter it' => sub { + use Auth::GoogleAuth; + my $auth = Auth::GoogleAuth->new; + my $code = $auth->code; + + $staffuser->set_extra_metadata('2fa_secret', $auth->secret32); + $staffuser->update; + $mech->get_ok('/auth'); + $mech->submit_form_ok( + { with_fields => { username => $staffuser->email, password_sign_in => 'password' } }, + "sign in using form" ); + $mech->content_contains('Please generate a two-factor code'); + $mech->submit_form_ok({ with_fields => { '2fa_code' => $code } }, "provide correct 2FA code" ); + }; + subtest 'On external network, cannot disable 2FA' => sub { + $mech->get_ok('/auth/generate_token'); + $mech->content_contains('Change two-factor'); + $mech->content_lacks('Deactivate two-factor'); + $staffuser->unset_extra_metadata('2fa_secret'); + $staffuser->update; + }; + + subtest 'RSS feed has correct name' => sub { + $mech->get_ok('/rss/xsl'); + $mech->content_contains('RSS feed from the Street Care website'); + $mech->content_lacks('FixMyStreet'); + $mech->get_ok('/rss/problems'); + $mech->content_contains('New problems on Street Care'); + $mech->content_lacks('FixMyStreet'); + }; +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fixmystreet', 'tfl' ], + MAPIT_URL => 'http://mapit.uk/' +}, sub { + foreach (qw(tfl.fixmystreet.com fixmystreet.com)) { + $mech->host($_); + my ($p) = $mech->create_problems_for_body(1, $body->id, 'NotResp'); + my $c = FixMyStreet::DB->resultset('Comment')->create({ + problem => $p, user => $p->user, anonymous => 't', text => 'Update text', + problem_state => 'not responsible', state => 'confirmed', mark_fixed => 0, + confirmed => DateTime->now(), + }); + subtest "check not responsible as correct text on $_" => sub { + $mech->get_ok('/report/' . $p->id); + $mech->content_contains("not TfL’s responsibility", "not reponsible message contains correct text"); + }; + $p->comments->delete; + $p->delete; + } +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'bromley', + MAPIT_URL => 'http://mapit.uk/' +}, sub { + +subtest 'Bromley staff can access Bromley admin' => sub { + $mech->log_in_ok( $bromleyuser->email ); + $mech->get_ok('/admin'); + $mech->content_contains( 'This is the administration interface for' ); + $mech->log_out_ok; +}; + +subtest 'TfL staff cannot access Bromley admin' => sub { + $mech->log_in_ok( $staffuser->email ); + ok $mech->get('/admin'); + is $mech->res->code, 403, "got 403"; + $mech->log_out_ok; +}; + +}; + +done_testing(); diff --git a/t/cobrand/westminster.t b/t/cobrand/westminster.t new file mode 100644 index 000000000..54de5a160 --- /dev/null +++ b/t/cobrand/westminster.t @@ -0,0 +1,259 @@ +use CGI::Simple; +use Test::MockModule; +use FixMyStreet::TestMech; +use FixMyStreet::Script::Reports; + +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +ok( my $mech = FixMyStreet::TestMech->new, 'Created mech object' ); + +my $cobrand = Test::MockModule->new('FixMyStreet::Cobrand::Westminster'); +$cobrand->mock('lookup_site_code', sub { + my ($self, $row) = @_; + return "My USRN" if $row->latitude == 51.501009; +}); + +my $body = $mech->create_body_ok(2504, 'Westminster City Council', { + send_method => 'Open311', api_key => 'key', 'endpoint' => 'e', 'jurisdiction' => 'j' }); +my $superuser = $mech->create_user_ok( + 'superuser@example.com', + name => 'Test Superuser', + is_superuser => 1 +); +my $staff_user = $mech->create_user_ok( + 'westminster@example.com', + name => 'Test User', + from_body => $body +); +my $normal_user = $mech->create_user_ok( + 'westminster-resident@example.com', + name => 'Public User' +); +my ($report) = $mech->create_problems_for_body(1, $body->id, 'Title'); +my $comment1 = $mech->create_comment_for_problem($report, $normal_user, 'User', 'this update was left on the Westminster cobrand', 0, 'confirmed', 'confirmed', { cobrand => 'westminster' }); +my $comment2 = $mech->create_comment_for_problem($report, $normal_user, 'User', 'this update was left on the fixmystreet.com cobrand', 0, 'confirmed', 'confirmed', { cobrand => 'fixmystreet' }); +my $comment3 = $mech->create_comment_for_problem($report, $normal_user, 'User', 'this update was imported via Open311', 0, 'confirmed', 'confirmed', { cobrand => '' }); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'westminster', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + updates_allowed => { + westminster => 'staff', + }, + oidc_login => { + westminster => { + client_id => 'example_client_id', + secret => 'example_secret_key', + auth_uri => 'http://oidc.example.org/oauth2/v2.0/authorize', + token_uri => 'http://oidc.example.org/oauth2/v2.0/token', + display_name => 'MyWestminster' + } + } + } +}, sub { + subtest 'Cobrand allows social auth' => sub { + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('westminster')->new(); + ok $cobrand->social_auth_enabled; + }; + + subtest 'Login button displayed correctly' => sub { + $mech->get_ok("/auth"); + $mech->content_contains("Sign in with MyWestminster"); + }; + + subtest 'Reports do not have update form' => sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('Provide an update'); + }; + + subtest 'Reports show updates from Westminster cobrand' => sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_contains($comment1->text); + }; + + subtest 'Reports show updates from Open311' => sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_contains($comment3->text); + }; + + subtest "Reports don't show updates from fixmystreet.com cobrand" => sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks($comment2->text); + }; +}; + +subtest 'Reports have an update form for superusers' => sub { + # Westminster cobrand disables email signin, so we have to + # login and *then* set the cobrand. + $mech->log_in_ok( $superuser->email ); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'westminster', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + updates_allowed => { + westminster => 'staff', + }, + }, + }, sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_contains('Provide an update'); + }; + + $mech->log_out_ok(); +}; + +subtest 'Reports have an update form for staff users' => sub { + $mech->log_in_ok( $staff_user->email ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'westminster', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + updates_allowed => { + westminster => 'staff', + }, + }, + }, sub { + $mech->get_ok('/report/' . $report->id); + $mech->content_contains('Provide an update'); + }; + $mech->log_out_ok(); +}; + +for ( + { + ALLOWED_COBRANDS => 'westminster', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + oidc_login => { + westminster => 0 + } + } + }, + { + ALLOWED_COBRANDS => 'westminster', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + oidc_login => { + hounslow => { + client_id => 'example_client_id', + secret => 'example_secret_key', + auth_uri => 'http://oidc.example.org/oauth2/v2.0/authorize', + token_uri => 'http://oidc.example.org/oauth2/v2.0/token', + display_name => 'MyHounslow' + } + } + } + }, + { + ALLOWED_COBRANDS => 'westminster', + MAPIT_URL => 'http://mapit.uk/', + } +) { + FixMyStreet::override_config $_, sub { + subtest 'Cobrand disallows social auth' => sub { + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('westminster')->new(); + ok !$cobrand->social_auth_enabled; + }; + + subtest 'Login button not displayed' => sub { + $mech->get_ok("/auth"); + $mech->content_lacks("Login with MyWestminster"); + }; + }; +} + +$mech->delete_problems_for_body($body->id); +$mech->create_contact_ok(body_id => $body->id, category => 'Abandoned bike', email => "BIKE"); +($report) = $mech->create_problems_for_body(1, $body->id, 'Bike', { + category => "Abandoned bike", cobrand => 'westminster', + latitude => 51.501009, longitude => -0.141588, areas => '2504', +}); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'westminster' ], + MAPIT_URL => 'http://mapit.uk/', + STAGING_FLAGS => { send_reports => 1, skip_checks => 0 }, + COBRAND_FEATURES => { anonymous_account => { westminster => 'anon' } }, +}, sub { + subtest 'USRN set correctly' => sub { + my $test_data = FixMyStreet::Script::Reports::send(); + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('service_code'), 'BIKE'; + is $c->param('attribute[USRN]'), 'My USRN'; + }; +}; + +for my $cobrand (qw(westminster fixmystreet)) { + FixMyStreet::override_config { + ALLOWED_COBRANDS => $cobrand, + MAPIT_URL => 'http://mapit.uk/', + }, sub { + subtest "No reporter alert created in $cobrand" => sub { + my $user = $mech->log_in_ok('test@example.org'); + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => 'SW1A1AA' } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok( { with_fields => { + title => 'Title', detail => 'Detail', category => 'Abandoned bike', name => 'Test Example', + } }, 'submitted okay' ); + is $user->alerts->count, 0; + }; + }; +} + +my $westminster = FixMyStreet::Cobrand::Westminster->new; +subtest 'correct config returned for USRN/UPRN lookup' => sub { + my $actual = $westminster->lookup_site_code_config('USRN'); + delete $actual->{accept_feature}; # is_deeply doesn't like code + is_deeply $actual, { + buffer => 1000, + proxy_url => "https://tilma.mysociety.org/resource-proxy/proxy.php", + url => "https://westminster.assets/40/query", + property => 'USRN', + }; + $actual = $westminster->lookup_site_code_config('UPRN'); + delete $actual->{accept_feature}; # is_deeply doesn't like code + is_deeply $actual, { + buffer => 1000, + proxy_url => "https://tilma.mysociety.org/resource-proxy/proxy.php", + url => "https://westminster.assets/25/query", + property => 'UPRN', + accept_types => { + Point => 1 + }, + }; +}; + +subtest 'nearest UPRN returns correct point' => sub { + my $cfg = { + accept_feature => sub { 1 }, + property => 'UPRN', + accept_types => { + Point => 1, + }, + }; + my $features = [ + # A couple of incorrect geometry types to check they're ignored... + { geometry => { type => 'Polygon' } }, + { geometry => { type => 'LineString', + coordinates => [ [ 527735, 181004 ], [ 527755, 181004 ] ] }, + properties => { fid => '20100024' } }, + # And two points which are further away than the above linestring, + # the second of which is the closest to our testing point. + { geometry => { type => 'Point', + coordinates => [ 527795, 181024 ] }, + properties => { UPRN => '10012387122' } }, + { geometry => { type => 'Point', + coordinates => [ 527739, 181009 ] }, + properties => { UPRN => '10012387123' } }, + ]; + is $westminster->_nearest_feature($cfg, 527745, 180994, $features), '10012387123'; +}; + + +done_testing(); diff --git a/t/cobrand/zurich.t b/t/cobrand/zurich.t index ee2724a07..8c5acddca 100644 --- a/t/cobrand/zurich.t +++ b/t/cobrand/zurich.t @@ -1,11 +1,13 @@ # TODO # Overdue alerts +use utf8; use DateTime; use Email::MIME; use File::Temp; use LWP::Protocol::PSGI; use Test::LongString; +use Test::MockModule; use Path::Tiny; use t::Mock::MapItZurich; use FixMyStreet::Script::Reports; @@ -28,18 +30,8 @@ $cobrand->db_state_migration; my $sample_file = path(__FILE__)->parent->parent->child("app/controller/sample.jpg"); ok $sample_file->exists, "sample file $sample_file exists"; -# This is a helper method that will send the reports but with the config -# correctly set - notably STAGING_FLAGS send_reports needs to be true, and -# zurich must be allowed cobrand if we want to be able to call cobrand -# methods on it. sub send_reports_for_zurich { - FixMyStreet::override_config { - STAGING_FLAGS => { send_reports => 1 }, - ALLOWED_COBRANDS => ['zurich'] - }, sub { - # Actually send the report - FixMyStreet::Script::Reports::send('zurich'); - }; + FixMyStreet::Script::Reports::send(); } sub reset_report_state { my ($report, $created) = @_; @@ -51,45 +43,47 @@ sub reset_report_state { $report->whensent(undef); $report->state('submitted'); $report->created($created) if $created; + $report->category('Other'); $report->update; } -# Front page test -ok $mech->host("zurich.example.com"), "change host to Zurich"; +my $UPLOAD_DIR = File::Temp->newdir(); FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], + STAGING_FLAGS => { send_reports => 1 }, + BASE_URL => 'https://www.zurich', + ALLOWED_COBRANDS => 'zurich', + MAPIT_URL => 'http://mapit.zurich/', + MAPIT_TYPES => [ 'O08' ], + MAPIT_ID_WHITELIST => [ 423017 ], + MAP_TYPE => 'Zurich,OSM', + PHOTO_STORAGE_BACKEND => 'FileSystem', + PHOTO_STORAGE_OPTIONS => { + UPLOAD_DIR => $UPLOAD_DIR, + }, }, sub { - $mech->get_ok('/'); -}; + +# Front page test +ok $mech->host("zurich.example.com"), "change host to Zurich"; +$mech->get_ok('/'); $mech->content_like( qr/zurich/i ); # Set up bodies my $zurich = $mech->create_body_ok( 1, 'Zurich' ); -$zurich->parent( undef ); -$zurich->update; -my $division = $mech->create_body_ok( 2, 'Division 1' ); -$division->parent( $zurich->id ); -$division->send_method( 'Zurich' ); -$division->endpoint( 'division@example.org' ); -$division->update; -$division->body_areas->find_or_create({ area_id => 423017 }); -my $subdivision = $mech->create_body_ok( 3, 'Subdivision A' ); -$subdivision->parent( $division->id ); -$subdivision->send_method( 'Zurich' ); -$subdivision->endpoint( 'subdivision@example.org' ); -$subdivision->update; -my $external_body = $mech->create_body_ok( 4, 'External Body' ); -$external_body->send_method( 'Zurich' ); -$external_body->endpoint( 'external_body@example.net' ); -$external_body->update; +my $division = $mech->create_body_ok( 423017, 'Division 1', { + parent => $zurich->id, send_method => 'Zurich', endpoint => 'division@example.org' } ); +my $division2 = $mech->create_body_ok( 423017, 'Division 2', { + parent => $zurich->id, send_method => 'Zurich', endpoint => 'division2@example.org' } ); +my $subdivision = $mech->create_body_ok( 3, 'Subdivision A', + { parent => $division->id, send_method => 'Zurich', endpoint => 'subdivision@example.org' } ); +my $external_body = $mech->create_body_ok( 4, 'External Body', + { send_method => 'Zurich', endpoint => 'external_body@example.net' } ); +my $external_body2 = $mech->create_body_ok( 4, 'Another Body External', + { send_method => 'Zurich', endpoint => 'external_body2@example.net' } ); sub get_export_rows_count { my $mech = shift; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get_ok( '/admin/stats?export=1' ); - }; + my $extra = shift || ''; + $mech->get_ok( '/admin/stats?export=1' . $extra); is $mech->res->code, 200, 'csv retrieved ok'; is $mech->content_type, 'text/csv', 'content_type correct' and do { my @lines = split /\n/, $mech->content; @@ -117,29 +111,24 @@ my @reports = $mech->create_problems_for_body( 1, $division->id, 'Test', { }); my $report = $reports[0]; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { - $mech->get_ok( '/report/' . $report->id ); -}; -$mech->content_contains('Überprüfung ausstehend') +$mech->get_ok( '/report/' . $report->id ); +$mech->content_contains('Überprüfung ausstehend') or die $mech->content; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { - my $json = $mech->get_ok_json( '/report/ajax/' . $report->id ); - is $json->{report}->{title}, "Überprüfung ausstehend", "correct title"; - is $json->{report}->{state}, "submitted", "correct state"; -}; +my $json = $mech->get_ok_json( '/report/ajax/' . $report->id ); +is $json->{report}->{title}, "Überprüfung ausstehend", "correct title"; +is $json->{report}->{state}, "submitted", "correct state"; + +$report->state('fixed - council'); +$report->set_extra_metadata(public_response => 'Freundliche Grüsse'); +$report->update; +$json = $mech->get_ok_json( '/report/ajax/' . $report->id ); +is $json->{report}->{state}, "closed", "correct state"; +is $json->{updates}->{details}, "Freundliche Grüsse", "correct public response"; + +$report->update({ state => 'submitted' }); subtest "Banners are displayed correctly" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { for my $test ( { description => 'new report', @@ -162,8 +151,8 @@ subtest "Banners are displayed correctly" => sub { { description => 'closed report', state => 'external', - banner_id => 'closed', - banner_text => 'Extern', + banner_id => 'fixed', + banner_text => 'Beantwortet', }, { description => 'in progress report', @@ -211,17 +200,14 @@ subtest "Banners are displayed correctly" => sub { }; } $report->update({ state => 'submitted' }); - }; }; -# Check logging in to deal with this report -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], -}, sub { +my $user; +subtest 'check logging in to deal with this report' => sub { $mech->get_ok( '/admin' ); is $mech->uri->path, '/auth', "got sent to the sign in page"; - my $user = $mech->log_in_ok( 'dm1@example.org') ; + $user = $mech->log_in_ok( 'dm1@example.org') ; $user->from_body( undef ); $user->update; ok $mech->get( '/admin' ); @@ -230,12 +216,12 @@ FixMyStreet::override_config { $user->update; $mech->get_ok( '/admin' ); -}; -is $mech->uri->path, '/admin', "am logged in"; + is $mech->uri->path, '/admin', "am logged in"; -$mech->content_contains( 'report_edit/' . $report->id ); -$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); -$mech->content_contains( 'Erfasst' ); + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); + $mech->content_contains( 'Erfasst' ); +}; subtest "changing of categories" => sub { # create a few categories (which are actually contacts) @@ -260,13 +246,8 @@ subtest "changing of categories" => sub { ok ( !$comments_rs->first, "There are no comments yet" ); # change the category via the web interface - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { category => 'Cat2' } } ); - }; + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { category => 'Cat2' } } ); # check changes correctly saved $report->discard_changes(); @@ -280,6 +261,38 @@ subtest "changing of categories" => sub { $report->update({category => $original_category }); }; +subtest "private categories" => sub { + $mech->log_in_ok( 'super@example.org' ); + $mech->get_ok('/admin/bodies'); + $mech->follow_link_ok({ text => 'Division 1' }); + $mech->submit_form_ok({ with_fields => { + category => 'Allgemein', + state => 'inactive', + email => 'allgemein@example.org', + 'extra[admin_label]' => 'StadtPeople', + 'extra[abbreviation]' => 'STA', + note => 'New', + }}); + $mech->follow_link_ok({ text => 'Allgemein' }); + $mech->content_contains('<option value="inactive" selected>'); + $mech->content_like(qr/admin_label.*?StadtPeople/); + + $mech->get_ok( '/around?lat=47.381817&lon=8.529156' ); + $mech->content_lacks('StadtPeople'); + $mech->content_contains('Allgemein'); + $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); + $mech->content_lacks('StadtPeople'); + $mech->content_lacks('Allgemein'); + + $report->update({ category => 'Allgemein' }); + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('StadtPeople'); + $mech->content_contains('Allgemein'); + + $mech->get_ok('/admin/report_edit/' . $report->id); + $mech->content_contains('<option value="Allgemein">StadtPeople (STA)</option>'); +}; + sub get_moderated_count { # my %date_params = ( ); # my $moderated = FixMyStreet::DB->resultset('Problem')->search({ @@ -288,17 +301,12 @@ sub get_moderated_count { # use a separate mech to avoid stomping on test state my $mech = FixMyStreet::TestMech->new; - my $user = $mech->log_in_ok( 'super@example.org' ); + $mech->log_in_ok( 'super@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get( '/admin/stats' ); - }; + $mech->get( '/admin/stats' ); if ($mech->content =~/Innerhalb eines Arbeitstages moderiert: (\d+)/) { return $1; - } - else { + } else { fail sprintf "Could not get moderation results (%d)", $mech->status; return undef; } @@ -306,127 +314,112 @@ sub get_moderated_count { subtest "report_edit" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { + reset_report_state($report); + ok ( ! $report->get_extra_metadata('moderated_overdue'), 'Report currently unmoderated' ); + is get_moderated_count(), 0; - reset_report_state($report); - ok ( ! $report->get_extra_metadata('moderated_overdue'), 'Report currently unmoderated' ); - is get_moderated_count(), 0; - - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains( 'Unbestätigt' ); # Unconfirmed email - $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); - $mech->get_ok( '/report/' . $report->id ); + $mech->log_in_ok( 'dm1@example.org') ; + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Unbestätigt' ); # Unconfirmed email + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); - $report->discard_changes(); + $report->discard_changes(); - $mech->content_contains('Aufgenommen'); - $mech->content_contains('Test Test'); - $mech->content_lacks('photo/' . $report->id . '.0.jpeg'); - $mech->email_count_is(0); + $mech->content_contains('Aufgenommen'); + $mech->content_contains('Test Test'); + $mech->content_lacks('photo/' . $report->id . '.0.jpeg'); + $mech->email_count_is(0); - $report->discard_changes; + $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Report now marked moderated' ); - is get_moderated_count(), 1; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Report now marked moderated' ); + is get_moderated_count(), 1; - # Set state back to 10 days ago so that report is overdue - my $created = $report->created; - reset_report_state($report, $created->clone->subtract(days => 10)); + # Set state back to 10 days ago so that report is overdue + my $created = $report->created; + reset_report_state($report, $created->clone->subtract(days => 10)); - is get_moderated_count(), 0; + is get_moderated_count(), 0; - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); - $mech->get_ok( '/report/' . $report->id ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 1, 'moderated_overdue set correctly when overdue' ); - is get_moderated_count(), 0, 'Moderated count not increased when overdue'; + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 1, 'moderated_overdue set correctly when overdue' ); + is get_moderated_count(), 0, 'Moderated count not increased when overdue'; - reset_report_state($report, $created); + reset_report_state($report, $created); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); - $mech->get_ok( '/report/' . $report->id ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking confirmed sets moderated_overdue' ); - is ( $report->get_extra_metadata('closed_overdue'), undef, 'Marking confirmed does NOT set closed_overdue' ); - is get_moderated_count(), 1; + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking confirmed sets moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), undef, 'Marking confirmed does NOT set closed_overdue' ); + is get_moderated_count(), 1; - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); - $mech->get_ok( '/report/' . $report->id, 'still visible as response not published yet' ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); + $mech->get_ok( '/report/' . $report->id, 'still visible as response not published yet' ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Still marked moderated_overdue' ); - is ( $report->get_extra_metadata('closed_overdue'), undef, "Marking hidden doesn't set closed_overdue..." ); - is ( $report->state, 'feedback pending', 'Marking hidden actually sets state to feedback pending'); - is ( $report->get_extra_metadata('closure_status'), 'hidden', 'Marking hidden sets closure_status to hidden'); - is get_moderated_count(), 1, 'Check still counted moderated' - or diag $report->get_column('extra'); - - # publishing actually sets hidden - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'status_update' ); - $mech->submit_form_ok( { button => 'publish_response' } ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $report->discard_changes; + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Still marked moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), undef, "Marking hidden doesn't set closed_overdue..." ); + is ( $report->state, 'feedback pending', 'Marking hidden actually sets state to feedback pending'); + is ( $report->get_extra_metadata('closure_status'), 'hidden', 'Marking hidden sets closure_status to hidden'); + is get_moderated_count(), 1, 'Check still counted moderated' + or diag $report->get_column('extra'); + + # publishing actually sets hidden + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $report->discard_changes; - is ( $report->get_extra_metadata('closed_overdue'), 0, "Closing as hidden sets closed_overdue..." ); - is ( $report->state, 'hidden', 'Closing as hidden sets state to hidden'); - is ( $report->get_extra_metadata('closure_status'), undef, 'Closing as hidden unsets closure_status'); + is ( $report->get_extra_metadata('closed_overdue'), 0, "Closing as hidden sets closed_overdue..." ); + is ( $report->state, 'hidden', 'Closing as hidden sets state to hidden'); + is ( $report->get_extra_metadata('closure_status'), undef, 'Closing as hidden unsets closure_status'); - $mech->submit_form_ok( { with_fields => { new_internal_note => 'Initial internal note.' } } ); - $report->discard_changes; - is ( $report->state, 'hidden', 'Another internal note does not reopen'); + $mech->submit_form_ok( { with_fields => { new_internal_note => 'Initial internal note.' } } ); + $report->discard_changes; + is ( $report->state, 'hidden', 'Another internal note does not reopen'); - $mech->get( '/report/' . $report->id); - is $mech->res->code, 410; + $mech->get( '/report/' . $report->id); + is $mech->res->code, 410; - reset_report_state($report); - is ( $report->get_extra_metadata('moderated_overdue'), undef, 'Sanity check' ); - is get_moderated_count(), 0; + reset_report_state($report); + is ( $report->get_extra_metadata('moderated_overdue'), undef, 'Sanity check' ); + is get_moderated_count(), 0; - # Check that setting to 'hidden' also triggers moderation - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'status_update' ); - $mech->submit_form_ok( { button => 'publish_response' } ); + # Check that setting to 'hidden' also triggers moderation + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); - $report->discard_changes; - is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking hidden from scratch sets moderated_overdue' ); - is ( $report->get_extra_metadata('closed_overdue'), 0, 'Marking hidden from scratch also set closed_overdue' ); - is get_moderated_count(), 1; + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking hidden from scratch sets moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), 0, 'Marking hidden from scratch also set closed_overdue' ); + is get_moderated_count(), 1; - is ($cobrand->get_or_check_overdue($report), 0, 'sanity check'); - $report->update({ created => $created->clone->subtract(days => 10) }); - is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased'); + is ($cobrand->get_or_check_overdue($report), 0, 'sanity check'); + $report->update({ created => $created->clone->subtract(days => 10) }); + is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased'); - reset_report_state($report, $created); - } + reset_report_state($report, $created); }; # Give the report three photos -my $UPLOAD_DIR = File::Temp->newdir(); my @files = map { $_ x 40 . ".jpeg" } (1..3); $sample_file->copy(path($UPLOAD_DIR, $_)) for @files; $report->photo(join(',', @files)); $report->update; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAP_TYPE => 'Zurich,OSM', - PHOTO_STORAGE_BACKEND => 'FileSystem', - PHOTO_STORAGE_OPTIONS => { - UPLOAD_DIR => $UPLOAD_DIR, - }, -}, sub { - # Photo publishing +subtest 'Photo publishing' => sub { $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->submit_form_ok( { with_fields => { state => 'confirmed', publish_photo_1 => 1 } } ); $mech->get_ok( '/around?lat=' . $report->latitude . ';lon=' . $report->longitude); @@ -469,50 +462,37 @@ $mech->log_out_ok; subtest 'SDM' => sub { my $user = $mech->log_in_ok( 'sdm1@example.org') ; $user->update({ from_body => undef }); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - ok $mech->get( '/admin' ); - }; + ok $mech->get( '/admin' ); is $mech->res->code, 403, 'Got 403'; $user->from_body( $subdivision->id ); $user->update; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get_ok( '/admin' ); - }; + $mech->get_ok( '/admin' ); is $mech->uri->path, '/admin', "am logged in"; $mech->content_contains( 'report_edit/' . $report->id ); $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); $mech->content_contains( 'In Bearbeitung' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains( 'Initial internal note' ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Initial internal note' ); - $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } ); - is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page"; - $mech->content_contains('This is an update'); - ok $mech->form_with_fields( 'status_update' ); - $mech->submit_form_ok( { button => 'no_more_updates' } ); - is $mech->uri->path, '/admin/summary', "redirected now finished with report."; + $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } ); + is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page"; + $mech->content_contains('This is an update'); + ok $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'no_more_updates' } ); + is $mech->uri->path, '/admin/summary', "redirected now finished with report."; - # Can still view the edit page but can't change anything - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains('<input disabled'); - $mech->submit_form_ok( { with_fields => { status_update => 'This is a disallowed update.' } } ); - $mech->content_lacks('This is a disallowed update'); + # Can still view the edit page but can't change anything + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains('<input disabled'); + $mech->submit_form_ok( { with_fields => { status_update => 'This is a disallowed update.' } } ); + $mech->content_lacks('This is a disallowed update'); - $mech->get_ok( '/report/' . $report->id ); - $mech->content_contains('In Bearbeitung'); - $mech->content_contains('Test Test'); - }; + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('In Bearbeitung'); + $mech->content_contains('Test Test'); send_reports_for_zurich(); $email = $mech->get_email; @@ -524,119 +504,99 @@ subtest 'SDM' => sub { is $report->state, 'feedback pending', 'Report now in feedback pending state'; subtest 'send_back' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { form_number => 2, button => 'send_back' } ); - $report->discard_changes; - is $report->state, 'confirmed', 'Report sent back to confirmed state'; - is $report->bodies_str, $division->id, 'Report sent back to division'; - }; + $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { form_number => 2, button => 'send_back' } ); + $report->discard_changes; + is $report->state, 'confirmed', 'Report sent back to confirmed state'; + is $report->bodies_str, $division->id, 'Report sent back to division'; }; subtest 'not contactable' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->submit_form_ok( { button => 'not_contactable', form_number => 2 } ); - $report->discard_changes; - is $report->state, 'feedback pending', 'Report sent back to Rueckmeldung ausstehend state'; - is $report->get_extra_metadata('closure_status'), 'not contactable', 'Report sent back to not_contactable state'; - is $report->bodies_str, $division->id, 'Report sent back to division'; - }; + $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { button => 'not_contactable', form_number => 2 } ); + $report->discard_changes; + is $report->state, 'feedback pending', 'Report sent back to Rueckmeldung ausstehend state'; + is $report->get_extra_metadata('closure_status'), 'not contactable', 'Report sent back to not_contactable state'; + is $report->bodies_str, $division->id, 'Report sent back to division'; }; $mech->log_out_ok; }; -my $user = $mech->log_in_ok( 'dm1@example.org') ; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], -}, sub { +subtest 'Test publishing of final update by DM' => sub { + $user = $mech->log_in_ok( 'dm1@example.org'); $mech->get_ok( '/admin' ); -}; -reset_report_state($report); -$report->update({ state => 'feedback pending' }); + reset_report_state($report); + $report->update({ state => 'feedback pending' }); -$mech->content_contains( 'report_edit/' . $report->id ); -$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); -# User confirms their email address -$report->set_extra_metadata(email_confirmed => 1); -$report->confirmed(DateTime->now); -$report->update; + # User confirms their email address + $report->set_extra_metadata(email_confirmed => 1); + $report->confirmed(DateTime->now); + $report->update; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { # Quick RSS check here, while we have a report $mech->get_ok('/rss/problems'); + my $module = Test::MockModule->new('FixMyStreet::Geocode::Zurich'); + $module->mock(admin_district => sub { 'Admin district' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_lacks( 'Unbestätigt' ); # Confirmed email + + $mech->content_contains('Admin district'); + + $mech->content_lacks( 'Unbestätigt' ); # Confirmed email $mech->submit_form_ok( { with_fields => { status_update => 'FINAL UPDATE' } } ); $mech->form_with_fields( 'status_update' ); $mech->submit_form_ok( { button => 'publish_response' } ); $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Beantwortet'); + $mech->content_contains('Test Test'); + $mech->content_contains('FINAL UPDATE'); + + $email = $mech->get_email; + like $email->header('To'), qr/test\@example.com/, 'to line looks correct'; + like $email->header('From'), qr/do-not-reply\@example.org/, 'from line looks correct'; + like $email->body, qr/FINAL UPDATE/, 'body looks correct'; + $mech->clear_emails_ok; }; -$mech->content_contains('Beantwortet'); -$mech->content_contains('Test Test'); -$mech->content_contains('FINAL UPDATE'); - -$email = $mech->get_email; -like $email->header('To'), qr/test\@example.com/, 'to line looks correct'; -like $email->header('From'), qr/do-not-reply\@example.org/, 'from line looks correct'; -like $email->body, qr/FINAL UPDATE/, 'body looks correct'; -$mech->clear_emails_ok; -# Assign feedback pending (via confirmed), don't confirm email -@reports = $mech->create_problems_for_body( 1, $division->id, 'Second', { - state => 'submitted', - confirmed => undef, - cobrand => 'zurich', - areas => ',423017,', -}); -$report = $reports[0]; +subtest "Assign feedback pending (via confirmed), don't confirm email, no email sent" => sub { + @reports = $mech->create_problems_for_body( 1, $division->id, 'Second', { + state => 'submitted', + confirmed => undef, + cobrand => 'zurich', + areas => ',423017,', + }); + $report = $reports[0]; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); $mech->get_ok( '/admin/report_edit/' . $report->id ); $mech->submit_form_ok( { with_fields => { state => 'feedback pending' } } ); $mech->get_ok( '/report/' . $report->id ); -}; -$mech->content_contains('In Bearbeitung'); -$mech->content_contains('Second Test'); + $mech->content_contains('In Bearbeitung'); + $mech->content_contains('Second Test'); -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', -}, sub { $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_contains( 'Unbestätigt' ); + $mech->content_contains( 'Unbestätigt' ); $report->discard_changes; $mech->form_with_fields( 'status_update' ); $mech->submit_form_ok( { button => 'publish_response', with_fields => { status_update => 'FINAL UPDATE' } } ); $mech->get_ok( '/report/' . $report->id ); -}; -$mech->content_contains('Beantwortet'); -$mech->content_contains('Second Test'); -$mech->content_contains('FINAL UPDATE'); + $mech->content_contains('Beantwortet'); + $mech->content_contains('Second Test'); + $mech->content_contains('FINAL UPDATE'); -$mech->email_count_is(0); + $mech->email_count_is(0); +}; # Report assigned to third party @@ -650,31 +610,27 @@ $report = $reports[0]; subtest "external report triggers email" => sub { my $EXTERNAL_MESSAGE = 'Look Ma, no hands!'; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # required to see body_external field - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'external'); - # Set the public_response manually here because the default one will have line breaks that get escaped as HTML, causing the comparison to fail. - $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); - $report->update; + # required to see body_external field + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + # Set the public_response manually here because the default one will have line breaks that get escaped as HTML, causing the comparison to fail. + $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); + $report->update; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + } }); + $report->discard_changes; + $mech->get_ok( '/report/' . $report->id ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - external_message => $EXTERNAL_MESSAGE, - } }); - $report->discard_changes; - $mech->get_ok( '/report/' . $report->id ); - }; is ($report->state, 'external', 'Report was closed correctly'); - $mech->content_contains('Extern') + $mech->content_contains('Beantwortet') or die $mech->content; $mech->content_contains('Third Test'); $mech->content_contains($report->get_extra_metadata('public_response')) or die $mech->content; @@ -688,30 +644,25 @@ subtest "external report triggers email" => sub { $mech->clear_emails_ok; subtest "Test third_personal boolean setting" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin' ); - # required to see body_external field - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'external'); - $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); - $report->update; + $mech->get_ok( '/admin' ); + # required to see body_external field + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); + $report->update; - is $mech->uri->path, '/admin', "am logged in"; - $mech->content_contains( 'report_edit/' . $report->id ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - third_personal => 1, - } }); - $mech->get_ok( '/report/' . $report->id ); - }; - $mech->content_contains('Extern'); + is $mech->uri->path, '/admin', "am logged in"; + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + third_personal => 1, + } }); + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Beantwortet'); $mech->content_contains('Third Test'); $mech->content_contains($report->get_extra_metadata('public_response')); send_reports_for_zurich(); @@ -724,30 +675,25 @@ subtest "external report triggers email" => sub { }; subtest "Test external wish sending" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # set as wish - $report->discard_changes; - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'wish'); - $report->update; - is ($report->state, 'feedback pending', 'Sanity check') or die; - - $mech->get_ok( '/admin/report_edit/' . $report->id ); - - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - external_message => $EXTERNAL_MESSAGE, - } }); - # Wishes publicly viewable - $mech->get_ok( '/report/' . $report->id ); - $mech->content_contains('Freundliche Gruesse Ihre Stadt Zuerich'); - }; + # set as wish + $report->discard_changes; + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'wish'); + $report->update; + is ($report->state, 'feedback pending', 'Sanity check') or die; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + } }); + # Wishes publicly viewable + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Freundliche Gruesse Ihre Stadt Zuerich'); send_reports_for_zurich(); $email = $mech->get_email; like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay'; @@ -760,30 +706,26 @@ subtest "external report triggers email" => sub { subtest "Closure email includes public response" => sub { my $PUBLIC_RESPONSE = "This is the public response to your report. Freundliche Gruesse."; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # set as extern - reset_report_state($report); - $report->state('feedback pending'); - $report->set_extra_metadata('closure_status' => 'external'); - $report->set_extra_metadata('email_confirmed' => 1); - $report->unset_extra_metadata('public_response'); - $report->update; - is ($report->state, 'feedback pending', 'Sanity check') or die; - - $mech->get_ok( '/admin/report_edit/' . $report->id ); - - $mech->form_with_fields( 'publish_response' ); - $mech->submit_form_ok( { - button => 'publish_response', - with_fields => { - body_external => $external_body->id, - external_message => $EXTERNAL_MESSAGE, - status_update => $PUBLIC_RESPONSE, - } }); - }; + # set as extern + reset_report_state($report); + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + $report->set_extra_metadata('email_confirmed' => 1); + $report->unset_extra_metadata('public_response'); + $report->update; + is ($report->state, 'feedback pending', 'Sanity check') or die; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + status_update => $PUBLIC_RESPONSE, + } }); + $email = $mech->get_email; my $report_id = $report->id; like Encode::decode('MIME-Header', $email->header('Subject')), qr/Meldung #$report_id/, 'subject looks okay'; @@ -798,91 +740,89 @@ subtest "superuser and dm can see stats" => sub { $mech->log_out_ok; $user = $mech->log_in_ok( 'super@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get( '/admin/stats' ); - }; + $mech->get( '/admin/stats' ); is $mech->res->code, 200, "superuser should be able to see stats page"; $mech->log_out_ok; $user = $mech->log_in_ok( 'dm1@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $mech->get( '/admin/stats' ); - }; + $mech->get( '/admin/stats' ); is $mech->res->code, 200, "dm can now also see stats page"; $mech->log_out_ok; }; subtest "only superuser can edit bodies" => sub { $user = $mech->log_in_ok( 'dm1@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - }, sub { - $mech->get( '/admin/body/' . $zurich->id ); - }; + $mech->get( '/admin/body/' . $zurich->id ); is $mech->res->code, 403, "only superuser should be able to edit bodies"; $mech->log_out_ok; }; subtest "only superuser can see 'Add body' form" => sub { $user = $mech->log_in_ok( 'dm1@example.org' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAPIT_TYPES => [ 'O08' ], - MAPIT_ID_WHITELIST => [ 423017 ], - }, sub { - $mech->get_ok( '/admin/bodies' ); - }; + $mech->get_ok( '/admin/bodies' ); $mech->content_contains('External Body'); $mech->content_lacks( '<form method="post" action="bodies"' ); $mech->log_out_ok; }; subtest "phone number is mandatory" => sub { - FixMyStreet::override_config { - MAPIT_TYPES => [ 'O08' ], - MAPIT_URL => 'http://mapit.zurich/', - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $user = $mech->log_in_ok( 'dm1@example.org' ); - $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); - $mech->submit_form( with_fields => { phone => "" } ); - $mech->content_contains( 'Diese Information wird benötigt' ); - $mech->log_out_ok; - }; + $user = $mech->log_in_ok( 'dm1@example.org' ); + $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); + $mech->submit_form( with_fields => { phone => "" } ); + $mech->content_contains( 'Diese Information wird benötigt' ); + $mech->log_out_ok; }; subtest "phone number is not mandatory for reports from mobile apps" => sub { - FixMyStreet::override_config { - MAPIT_TYPES => [ 'O08' ], - MAPIT_URL => 'http://mapit.zurich/', - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->post_ok( '/report/new/mobile?lat=47.381817&lon=8.529156' , { - service => 'iPhone', - detail => 'Problem-Bericht', - lat => 47.381817, - lon => 8.529156, - email => 'user@example.org', - pc => '', - name => '', - category => 'bad category', - }); - my $res = $mech->response; - ok $res->header('Content-Type') =~ m{^application/json\b}, 'response should be json'; - unlike $res->content, qr/Diese Information wird benötigt/, 'response should not contain phone error'; - # Clear out the mailq - $mech->clear_emails_ok; - }; + $mech->post_ok( '/report/new/mobile?lat=47.381817&lon=8.529156' , { + service => 'iPhone', + detail => 'Problem-Bericht', + lat => 47.381817, + lon => 8.529156, + email => 'user@example.org', + pc => '', + name => '', + category => 'bad category', + }); + my $res = $mech->response; + ok $res->header('Content-Type') =~ m{^application/json\b}, 'response should be json'; + unlike $res->content, qr/Diese Information wird benötigt/, 'response should not contain phone error'; + # Clear out the mailq + $mech->clear_emails_ok; +}; + +subtest "link external body to category" => sub { + $mech->log_in_ok( 'super@example.org' ); + $mech->get_ok( '/admin/body/' . $zurich->id ); + $mech->content_lacks('extra[category]'); + $mech->get_ok( '/admin/body/' . $division->id ); + $mech->content_lacks('extra[category]'); + $mech->get_ok( '/admin/body/' . $subdivision->id ); + $mech->content_lacks('extra[category]'); + $mech->get_ok( '/admin/body/' . $external_body->id ); + $mech->content_contains('extra[category]'); + $mech->submit_form_ok({ with_fields => { 'extra[category]' => 'Cat1' } }); + $mech->content_contains('<option value="Cat1" selected>'); + $external_body->discard_changes; + is $external_body->get_extra_metadata('category'), 'Cat1'; +}; + +subtest "shows correct external bodies" => sub { + $report->discard_changes; + $report->state('feedback pending'); + $report->set_extra_metadata('closure_status' => 'external'); + $report->update; + $user = $mech->log_in_ok( 'dm1@example.org' ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_like(qr/<option[^>]*>External Body<\/option>\s*<option[^>]*>Another Body External<\/option>/); # Test order + + $user = $mech->log_in_ok( 'dm2@example.org' ); + $user->update({ from_body => $division2->id }); + $report->update({ bodies_str => $division2->id }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains('Another Body External'); + $mech->content_lacks('External Body'); + $report->update({ bodies_str => $division->id }); }; subtest "problems can't be assigned to deleted bodies" => sub { @@ -891,30 +831,22 @@ subtest "problems can't be assigned to deleted bodies" => sub { $user->update; $report->state( 'confirmed' ); $report->update; - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAPIT_TYPES => [ 'O08' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok( '/admin/body/' . $external_body->id ); - $mech->submit_form_ok( { with_fields => { deleted => 1 } } ); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->content_lacks( $external_body->name ) - or do { - diag $mech->content; - diag $external_body->name; - die; - }; - }; + $mech->get_ok( '/admin/body/' . $external_body->id ); + $mech->submit_form_ok( { with_fields => { deleted => 1 } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_lacks( $external_body->name ) + or do { + diag $mech->content; + diag $external_body->name; + die; + }; $user->from_body( $division->id ); $user->update; $mech->log_out_ok; }; subtest "photo must be supplied for categories that require it" => sub { - FixMyStreet::App->model('DB::Contact')->find_or_create({ + FixMyStreet::DB->resultset('Contact')->find_or_create({ body => $division, category => "Graffiti - photo required", email => "graffiti\@example.org", @@ -924,44 +856,34 @@ subtest "photo must be supplied for categories that require it" => sub { note => "note for graffiti", extra => { photo_required => 1 } }); - FixMyStreet::override_config { - MAPIT_TYPES => [ 'O08' ], - MAPIT_URL => 'http://mapit.zurich/', - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_ID_WHITELIST => [ 423017 ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - $mech->get_ok('/report/new?lat=47.381817&lon=8.529156'); - $mech->submit_form_ok({ with_fields => { - detail => 'Problem-Bericht', - username => 'user@example.org', - category => 'Graffiti - photo required', - }}); - is $mech->res->code, 200, "missing photo shouldn't return anything but 200"; - $mech->content_contains(_("Photo is required."), 'response should contain photo error message'); - }; + $mech->get_ok('/report/new?lat=47.381817&lon=8.529156'); + $mech->submit_form_ok({ with_fields => { + detail => 'Problem-Bericht', + username => 'user@example.org', + category => 'Graffiti - photo required', + }}); + is $mech->res->code, 200, "missing photo shouldn't return anything but 200"; + $mech->content_contains(_("Photo is required."), 'response should contain photo error message'); }; subtest "test stats" => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - }, sub { - $user = $mech->log_in_ok( 'super@example.org' ); - - $mech->get_ok( '/admin/stats' ); - is $mech->res->code, 200, "superuser should be able to see stats page"; - - $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 3'); - $mech->content_contains('Innerhalb von fünf Arbeitstagen abgeschlossen: 3'); - # my @data = $mech->content =~ /(?:moderiert|abgeschlossen): \d+/g; - # diag Dumper(\@data); use Data::Dumper; - - my $export_count = get_export_rows_count($mech); - if (defined $export_count) { - is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports'; - $mech->content_contains('fixed - council'); - } - }; + $user = $mech->log_in_ok( 'super@example.org' ); + + $mech->get_ok( '/admin/stats' ); + is $mech->res->code, 200, "superuser should be able to see stats page"; + + $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 3'); + $mech->content_contains('Innerhalb von fünf Arbeitstagen abgeschlossen: 3'); + # my @data = $mech->content =~ /(?:moderiert|abgeschlossen): \d+/g; + # diag Dumper(\@data); use Data::Dumper; + + my $export_count = get_export_rows_count($mech); + if (defined $export_count) { + is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports'; + $mech->content_contains('fixed - council'); + } + $export_count = get_export_rows_count($mech, '&ym=' . DateTime->now->strftime("%m.%Y")); + is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports when filtering by month'; }; subtest "test admin_log" => sub { @@ -977,136 +899,108 @@ subtest "test admin_log" => sub { }; subtest 'email images to external partners' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - reset_report_state($report); + reset_report_state($report); - my $photo = path(__FILE__)->parent->child('zurich-logo_portal.x.jpg')->slurp_raw; - my $photoset = FixMyStreet::App::Model::PhotoSet->new({ - data_items => [ $photo ], - }); - my $fileid = $photoset->data; - - $report->set_extra_metadata('publish_photo' => { 0 => 1 }); - # The below email comparison must not have an external message. - $report->unset_extra_metadata('external_message'); - $report->update({ - state => 'external', - photo => $fileid, - external_body => $external_body->id, - }); + my $photo = path(__FILE__)->parent->child('zurich-logo_portal.x.jpg')->slurp_raw; + my $photoset = FixMyStreet::App::Model::PhotoSet->new({ + data_items => [ $photo ], + }); + my $fileid = $photoset->data; + + $report->set_extra_metadata('publish_photo' => { 0 => 1 }); + # The below email comparison must not have an external message. + $report->unset_extra_metadata('external_message'); + $report->update({ + state => 'external', + photo => $fileid, + external_body => $external_body->id, + }); - $mech->clear_emails_ok; - send_reports_for_zurich(); + $mech->clear_emails_ok; + send_reports_for_zurich(); - my @emails = $mech->get_email; - my $email_as_string = $mech->get_first_email(@emails); - my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms; - my $email = Email::MIME->new($email_as_string); - - my $expected_email_content = path(__FILE__)->parent->child('zurich_attachments.txt')->slurp; - - my $REPORT_ID = $report->id; - $expected_email_content =~ s{Subject: (.*?)\r?\n}{ - my $subj = Encode::decode('MIME-Header', $1); - $subj =~ s{REPORT_ID}{$REPORT_ID}g; - 'Subject: ' . Email::MIME::Encode::mime_encode($subj, "utf-8") . "\n"; - }eg; - $expected_email_content =~ s{REPORT_ID}{$REPORT_ID}g; - $expected_email_content =~ s{BOUNDARY}{$boundary}g; - my $expected_email = Email::MIME->new($expected_email_content); - - my @email_parts; - $email->walk_parts(sub { - my ($part) = @_; - push @email_parts, [ { $part->header_pairs }, $part->body ]; - }); - my @expected_email_parts; - $expected_email->walk_parts(sub { - my ($part) = @_; - push @expected_email_parts, [ { $part->header_pairs }, $part->body ]; - }); - is_deeply \@email_parts, \@expected_email_parts, 'MIME email text ok' - or do { - (my $test_name = $0) =~ s{/}{_}g; - my $path = path("test-output-$test_name.tmp"); - $path->spew($email_as_string); - diag "Saved output in $path"; - }; + my @emails = $mech->get_email; + my $email_as_string = $mech->get_first_email(@emails); + my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms; + my $email = Email::MIME->new($email_as_string); + + my $expected_email_content = path(__FILE__)->parent->child('zurich_attachments.txt')->slurp; + + my $REPORT_ID = $report->id; + $expected_email_content =~ s{Subject: (.*?)\r?\n}{ + my $subj = Encode::decode('MIME-Header', $1); + $subj =~ s{REPORT_ID}{$REPORT_ID}g; + 'Subject: ' . Email::MIME::Encode::mime_encode($subj, "utf-8", 9) . "\n"; + }eg; + $expected_email_content =~ s{REPORT_ID}{$REPORT_ID}g; + $expected_email_content =~ s{BOUNDARY}{$boundary}g; + my $expected_email = Email::MIME->new($expected_email_content); + + my @email_parts; + $email->walk_parts(sub { + my ($part) = @_; + push @email_parts, [ { $part->header_pairs }, $part->body ]; + }); + my @expected_email_parts; + $expected_email->walk_parts(sub { + my ($part) = @_; + push @expected_email_parts, [ { $part->header_pairs }, $part->body ]; + }); + is_deeply \@email_parts, \@expected_email_parts, 'MIME email text ok' + or do { + (my $test_name = $0) =~ s{/}{_}g; + my $path = path("test-output-$test_name.tmp"); + $path->spew($email_as_string); + diag "Saved output in $path"; }; }; subtest 'Status update shown as appropriate' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - # ALL closed states must hide the public_response edit, and public ones - # must show the answer in blue. - for (['feedback pending', 1, 0, 0], - ['fixed - council', 0, 1, 0], - ['external', 0, 1, 0], - ['hidden', 0, 0, 1]) - { - my ($state, $update, $public, $user_response) = @$_; - $report->update({ state => $state }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->contains_or_lacks($update, "name='status_update'"); - $mech->contains_or_lacks($public || $user_response, '<div class="admin-official-answer">'); - - if ($public) { - $mech->get_ok( '/report/' . $report->id ); - $mech->content_contains('Antwort</h4>'); - } - } - }; + # ALL closed states must hide the public_response edit, and public ones + # must show the answer in blue. + for (['feedback pending', 1, 0, 0], + ['fixed - council', 0, 1, 0], + ['external', 0, 1, 0], + ['hidden', 0, 0, 1]) + { + my ($state, $update, $public, $user_response) = @$_; + $report->update({ state => $state }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->contains_or_lacks($update, "name='status_update'"); + $mech->contains_or_lacks($public || $user_response, '<div class="admin-official-answer">'); + + if ($public) { + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Antwort</h4>'); + } + } }; subtest 'time_spent' => sub { - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAP_TYPE => 'Zurich,OSM', - }, sub { - my $report = $reports[0]; - - is $report->get_time_spent, 0, '0 minutes spent'; - $report->update({ state => 'in progress' }); - $mech->get_ok( '/admin/report_edit/' . $report->id ); - $mech->form_with_fields( 'time_spent' ); - $mech->submit_form_ok( { - with_fields => { - time_spent => 10, - } }); - is $report->get_time_spent, 10, '10 minutes spent'; - }; + my $report = $reports[0]; + + is $report->get_time_spent, 0, '0 minutes spent'; + $report->update({ state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'time_spent' ); + $mech->submit_form_ok( { + with_fields => { + time_spent => 10, + } }); + is $report->get_time_spent, 10, '10 minutes spent'; }; $mech->log_out_ok; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], - MAPIT_URL => 'http://mapit.zurich/', - MAPIT_TYPES => [ 'ZZZ' ], -}, sub { - subtest 'users at the top level can be edited' => sub { - $mech->log_in_ok( $superuser->email ); - $mech->get_ok('/admin/users/' . $superuser->id ); - }; +subtest 'users at the top level can be edited' => sub { + $mech->log_in_ok( $superuser->email ); + $mech->get_ok('/admin/users/' . $superuser->id ); }; -FixMyStreet::override_config { - ALLOWED_COBRANDS => [ 'zurich' ], -}, sub { - subtest 'A visit to /reports is okay' => sub { - $mech->get_ok('/reports'); - }; +subtest 'A visit to /reports is okay' => sub { + $mech->get_ok('/reports'); }; -END { - ok $mech->host("www.fixmystreet.com"), "change host back"; - done_testing(); -} +}; -1; +done_testing(); diff --git a/t/cobrand/zurich_attachments.txt b/t/cobrand/zurich_attachments.txt index 25a1bacf0..e9b717618 100644 --- a/t/cobrand/zurich_attachments.txt +++ b/t/cobrand/zurich_attachments.txt @@ -3,7 +3,7 @@ Subject: =?iso-8859-1?Q?Z=FCri?= wie neu: Weitergeleitete Meldung #REPORT_ID Content-Type: multipart/mixed; boundary="BOUNDARY"
To: "External Body" <external_body@example.net>
Content-Transfer-Encoding: 7bit
-From: "FixMyStreet" <division@example.org>
+From: FixMyStreet <division@example.org>
--BOUNDARY
@@ -12,7 +12,7 @@ Content-Transfer-Encoding: quoted-printable Gr=C3=BCezi External Body,
-=C3=96ffentliche URL: http://www.example.org/report/REPORT_ID
+=C3=96ffentliche URL: https://www.zurich/report/REPORT_ID
Bei Fragen zu "Z=C3=BCri wie neu" wenden Sie sich bitte an =
gis-zentrum@zuerich.ch.=
|