diff options
Diffstat (limited to 't/app/controller')
30 files changed, 1410 insertions, 284 deletions
diff --git a/t/app/controller/admin/bodies.t b/t/app/controller/admin/bodies.t index c73a90da1..811ac4362 100644 --- a/t/app/controller/admin/bodies.t +++ b/t/app/controller/admin/bodies.t @@ -1,3 +1,13 @@ +package FixMyStreet::Cobrand::AnonAllowedByCategory; +use parent 'FixMyStreet::Cobrand::UKCouncils'; +sub council_url { 'anonbycategory' } +sub council_name { 'Aberdeen City Council' } +sub council_area { 'Aberdeen' } +sub council_area_id { 2650 } +sub anonymous_account { { email => 'anoncategory@example.org', name => 'Anonymous Category' } } + +package main; + use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; @@ -5,6 +15,10 @@ my $mech = FixMyStreet::TestMech->new; my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); $mech->log_in_ok( $superuser->email ); my $body = $mech->create_body_ok(2650, 'Aberdeen City Council'); +my $body2 = $mech->create_body_ok(2237, 'Oxfordshire County Council'); + +my $user = $mech->create_user_ok('user@example.com', name => 'OCC User', from_body => $body2); +$user->user_body_permissions->create({ body => $body2, permission_type => 'category_edit' }); # This override is wrapped around ALL the /admin/body tests FixMyStreet::override_config { @@ -101,11 +115,14 @@ subtest 'check contact renaming' => sub { $mech->get('/admin/body/' . $body->id . '/test%20category'); is $mech->res->code, 404; $mech->get_ok('/admin/body/' . $body->id . '/testing%20category'); + $mech->content_contains('<td><strong>test2@example.com</strong></td>'); $report->discard_changes; is $report->category, 'testing category'; $mech->submit_form_ok( { with_fields => { category => 'test category' } } ); }; + + subtest 'check contact updating' => sub { $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); $mech->content_like(qr{test2\@example.com</strong>[^<]*</td>[^<]*<td>unconfirmed}s); @@ -210,6 +227,7 @@ subtest 'check open311 configuring' => sub { subtest 'check open311 devolved editing' => sub { $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->content_contains("name=\"category\"\n size=\"30\" value=\"test category\"\n readonly>", 'Cannot edit Open311 category name'); $mech->submit_form_ok( { with_fields => { send_method => 'Email', email => 'testing@example.org', @@ -217,11 +235,13 @@ subtest 'check open311 devolved editing' => sub { } } ); $mech->content_contains('Values updated'); $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->content_contains("name=\"category\"\n size=\"30\" value=\"test category\"\n required>", 'Can edit as now devolved'); $mech->submit_form_ok( { with_fields => { send_method => '', - email => 'open311-code', + email => 'open311 code', note => 'Removing email send method', } } ); + $mech->content_contains('open311 code'); $mech->content_contains('Values updated'); }; @@ -261,8 +281,64 @@ subtest 'open311 protection editing' => sub { is $contact->get_extra_metadata('open311_protect'), 1, 'Open311 protect flag set'; }; +subtest 'test assigned_users_only setting' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->submit_form_ok( { with_fields => { + assigned_users_only => 1, + } } ); + $mech->content_contains('Values updated'); + my $contact = $body->contacts->find({ category => 'test category' }); + is $contact->get_extra_metadata('assigned_users_only'), 1; +}; + +subtest 'updates disabling' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->submit_form_ok( { with_fields => { + updates_disallowed => 1, + note => 'Disabling updates', + } } ); + $mech->content_contains('Values updated'); + my $contact = $body->contacts->find({ category => 'test category' }); + is $contact->get_extra_metadata('updates_disallowed'), 1, 'Updates disallowed flag set'; +}; + +subtest 'reopen disabling' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->submit_form_ok( { with_fields => { + reopening_disallowed => 1, + note => 'Disabling reopening', + } } ); + $mech->content_contains('Values updated'); + my $contact = $body->contacts->find({ category => 'test category' }); + is $contact->get_extra_metadata('reopening_disallowed'), 1, 'Reopening disallowed flag set'; +}; + +subtest 'allow anonymous reporting' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->content_lacks('Allow anonymous reports'); +}; }; # END of override wrap +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + MAPIT_TYPES => [ 'UTA' ], + BASE_URL => 'http://www.example.org', + ALLOWED_COBRANDS => [ "fixmystreet", "anonallowedbycategory" ], +}, sub { + +subtest 'allow anonymous reporting' => sub { + $mech->get_ok('/admin/body/' . $body->id . '/test%20category'); + $mech->submit_form_ok( { with_fields => { + anonymous_allowed => 1, + note => 'Anonymous Allowed', + } } ); + $mech->content_contains('Values updated'); + my $contact = $body->contacts->find({ category => 'test category' }); + is $contact->get_extra_metadata('anonymous_allowed'), 1, 'Anonymous reports allowed flag set'; +}; + +}; + FixMyStreet::override_config { MAPIT_URL => 'http://mapit.uk/', @@ -345,4 +421,90 @@ subtest 'check log of the above' => sub { $mech->content_contains('Edited body <a href="/admin/body/' . $body->id . '">Aberdeen City Council</a>'); }; +subtest 'check update disallowed message' => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'bathnes', + COBRAND_FEATURES => { updates_allowed => { bathnes => 'open' } } + }, sub { + $mech->get_ok('/admin/body/' . $body->id .'/test%20category'); + $mech->content_contains('even if this is unticked, only open reports can have updates left on them.'); + }; + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'bathnes', + COBRAND_FEATURES => { updates_allowed => { bathnes => 'staff' } } + }, sub { + $mech->get_ok('/admin/body/' . $body->id .'/test%20category'); + $mech->content_contains('even if this is unticked, only staff will be able to leave updates.'); + }; + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'bathnes', + COBRAND_FEATURES => { updates_allowed => { bathnes => 'reporter' } } + }, sub { + $mech->get_ok('/admin/body/' . $body->id .'/test%20category'); + $mech->content_contains('even if this is unticked, only the problem reporter will be able to leave updates'); + }; +}; + +subtest 'check hardcoded contact renaming' => sub { + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + 'ALLOWED_COBRANDS' => [ 'oxfordshire' ], + }, sub { + my $contact = FixMyStreet::DB->resultset('Contact')->create( + { + body_id => $body2->id, + category => 'protected category', + state => 'confirmed', + editor => $0, + whenedited => \'current_timestamp', + note => 'protected contact', + email => 'protected@example.org', + } + ); + $contact->set_extra_metadata( 'hardcoded', 1 ); + $contact->update; + $mech->get_ok('/admin/body/' . $body2->id .'/protected%20category'); + $mech->content_contains( 'name="hardcoded"' ); + $mech->content_like( qr'value="protected category"[^>]*readonly's ); + $mech->submit_form_ok( { with_fields => { category => 'non protected category', note => 'rename category' } } ); + $mech->content_contains( 'protected category' ); + $mech->content_lacks( 'non protected category' ); + $mech->get('/admin/body/' . $body2->id . '/non%20protected%20category'); + is $mech->res->code, 404; + + $mech->get_ok('/admin/body/' . $body2->id .'/protected%20category'); + $mech->submit_form_ok( { with_fields => { hardcoded => 0, note => 'remove hardcoding' } } ); + $mech->get_ok('/admin/body/' . $body2->id .'/protected%20category'); + $mech->content_unlike( qr'value="protected category"[^>]*readonly's ); + $mech->submit_form_ok( { with_fields => { category => 'non protected category', note => 'rename category' } } ); + $mech->content_contains( 'non protected category' ); + $mech->get_ok('/admin/body/' . $body2->id . '/non%20protected%20category'); + $mech->get('/admin/body/' . $body2->id . '/protected%20category'); + is $mech->res->code, 404; + + $contact->discard_changes; + $contact->set_extra_metadata( 'hardcoded', 1 ); + $contact->update; + + $mech->log_out_ok( $superuser->email ); + $mech->log_in_ok( $user->email ); + $mech->get_ok('/admin/body/' . $body2->id . '/non%20protected%20category'); + $mech->content_lacks( 'name="hardcoded"' ); + $user->update( { is_superuser => 1 } ); + $mech->get_ok('/admin/body/' . $body2->id . '/non%20protected%20category'); + $mech->content_contains('name="hardcoded"' ); + $user->update( { is_superuser => 0 } ); + $mech->submit_form_ok( { with_fields => { hardcoded => 0, note => 'remove hardcoding' } } ); + $mech->content_lacks( 'name="hardcoded"' ); + + $contact->discard_changes; + is $contact->get_extra_metadata('hardcoded'), 1, "non superuser can't remove hardcoding"; + + $mech->log_out_ok( $user->email ); + }; +}; + done_testing(); diff --git a/t/app/controller/admin/report_edit.t b/t/app/controller/admin/report_edit.t index 438bcc241..e041154db 100644 --- a/t/app/controller/admin/report_edit.t +++ b/t/app/controller/admin/report_edit.t @@ -9,6 +9,7 @@ my $user2 = $mech->create_user_ok('test2@example.com', name => 'Test User 2'); my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); my $oxfordshire = $mech->create_body_ok(2237, 'Oxfordshire County Council'); +my $user3 = $mech->create_user_ok('body_user@example.com', name => 'Body User', from_body => $oxfordshire); my $oxfordshirecontact = $mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Potholes', email => 'potholes@example.com' ); $mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Traffic lights', email => 'lights@example.com' ); @@ -328,7 +329,6 @@ foreach my $test ( closed_updates => undef, }, expect_comment => 1, - user_body => $oxfordshire, changes => { state => 'investigating' }, log_entries => [ qw/edit state_change edit edit resend edit state_change edit state_change edit state_change edit state_change edit state_change edit edit edit edit edit/ @@ -350,7 +350,6 @@ foreach my $test ( }, expect_comment => 1, expected_text => '*Category changed from ‘Other’ to ‘Potholes’*', - user_body => $oxfordshire, changes => { state => 'in progress', category => 'Potholes' }, log_entries => [ qw/edit state_change category_change edit state_change edit edit resend edit state_change edit state_change edit state_change edit state_change edit state_change edit edit edit edit edit/ @@ -363,11 +362,6 @@ foreach my $test ( $report->comments->delete; $log_entries->reset; - if ( $test->{user_body} ) { - $superuser->from_body( $test->{user_body}->id ); - $superuser->update; - } - $mech->get_ok("/admin/report_edit/$report_id"); @{$test->{fields}}{'external_id', 'external_body', 'external_team', 'category'} = (13, "", "", "Other"); @@ -439,21 +433,12 @@ foreach my $test ( } else { is $comment->text, '', 'comment has no text'; } - if ( $test->{user_body} ) { - ok $comment->get_extra_metadata('is_body_user'), 'body user metadata set'; - ok !$comment->get_extra_metadata('is_superuser'), 'superuser metadata not set'; - is $comment->name, $test->{user_body}->name, 'comment name is body name'; - } else { - ok !$comment->get_extra_metadata('is_body_user'), 'body user metadata not set'; - ok $comment->get_extra_metadata('is_superuser'), 'superuser metadata set'; - is $comment->name, _('an administrator'), 'comment name is admin'; - } + ok !$comment->get_extra_metadata('is_body_user'), 'body user metadata not set'; + ok $comment->get_extra_metadata('is_superuser'), 'superuser metadata set'; + is $comment->name, _('an administrator'), 'comment name is admin'; } else { is $report->comments->count, 0, 'report has no comments'; } - - $superuser->from_body(undef); - $superuser->update; }; } @@ -685,16 +670,28 @@ subtest "Test display of fields extra data" => sub { $mech->get_ok("/admin/report_edit/$report_id"); $mech->content_contains('Extra data: No'); - $report->push_extra_fields( { - name => 'report_url', - value => 'http://example.com', - }); + $report->push_extra_fields( + { + name => 'report_url', + value => 'http://example.com', + }, + { + name => 'sent_to', + value => [ 'onerecipient@example.org' ], + }, + { + name => 'sent_too', + value => [ 'onemorerecipient@example.org', 'another@example.org' ], + }, + ); $report->update; $report->discard_changes; $mech->get_ok("/admin/report_edit/$report_id"); $mech->content_contains('report_url</strong>: http://example.com'); + $mech->content_contains('sent_to</strong>: onerecipient@example.org'); + $mech->content_contains('sent_too</strong>: onemorerecipient@example.org, another@example.org'); $report->set_extra_fields( { description => 'Report URL', @@ -707,4 +704,20 @@ subtest "Test display of fields extra data" => sub { $mech->content_contains('Report URL (report_url)</strong>: http://example.com'); }; +subtest "Test display of contributed_as data" => sub { + $report->update( { extra => undef } ); + $mech->get_ok("/admin/report_edit/$report_id"); + $mech->content_contains('Extra data: No'); + + $report->set_extra_metadata( contributed_as => 'another_user' ); + $report->set_extra_metadata( contributed_by => $user3->id ); + $report->update; + + $report->discard_changes; + + $mech->get_ok("/admin/report_edit/$report_id"); + $mech->content_like(qr!Created By</strong>: <a[^>]*>Body User \(@{[ $user3->email ]}!); + $mech->content_contains('Created Body</strong>: Oxfordshire County Council'); +}; + done_testing(); diff --git a/t/app/controller/admin/update_edit.t b/t/app/controller/admin/update_edit.t index 57c8973d4..8650e7771 100644 --- a/t/app/controller/admin/update_edit.t +++ b/t/app/controller/admin/update_edit.t @@ -81,7 +81,7 @@ for my $test ( fields => { text => 'this is an update', state => 'confirmed', - name => '', + name => 'Test User', anonymous => 1, username => $update->user->email, }, @@ -96,7 +96,7 @@ for my $test ( fields => { text => 'this is a changed update', state => 'confirmed', - name => '', + name => 'Test User', anonymous => 1, username => $update->user->email, }, diff --git a/t/app/controller/admin/users.t b/t/app/controller/admin/users.t index 4f0298103..6f3971149 100644 --- a/t/app/controller/admin/users.t +++ b/t/app/controller/admin/users.t @@ -6,6 +6,8 @@ my $user = $mech->create_user_ok('test@example.com', name => 'Test User'); my $original_user_id = $user->id; # For log later my $user2 = $mech->create_user_ok('test2@example.com', name => 'Test User 2'); my $user3 = $mech->create_user_ok('test3@example.com', name => 'Test User 3'); +my $user4 = $mech->create_user_ok('test4@example.com', name => 'Test User 4'); +my $user5 = $mech->create_user_ok('test5@example.com', name => 'Test User 5'); my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); @@ -13,6 +15,21 @@ my $oxfordshire = $mech->create_body_ok(2237, 'Oxfordshire County Council'); my $haringey = $mech->create_body_ok(2509, 'Haringey Borough Council'); my $southend = $mech->create_body_ok(2607, 'Southend-on-Sea Borough Council'); +$user4->from_body( $oxfordshire->id ); +$user4->update; +$user4->user_body_permissions->create( { + body => $oxfordshire, + permission_type => 'user_edit', +} ); +$user5->from_body( $oxfordshire->id ); +$user5->update; +my $occ_role = $user5->roles->create({ + body => $oxfordshire, + name => 'Role A', + permissions => ['moderate', 'user_edit'], +}); +$user5->add_to_roles($occ_role); + $mech->log_in_ok( $superuser->email ); subtest 'search abuse' => sub { @@ -84,8 +101,6 @@ subtest 'user search' => sub { permissions => ['moderate', 'user_edit'], }); $user->add_to_roles($role); - $mech->get_ok('/admin/users?search=' . $haringey->id ); - $mech->content_contains('test@example.com'); $mech->get_ok('/admin/users?role=' . $role->id); $mech->content_contains('selected>Role A'); $mech->content_contains('test@example.com'); @@ -99,6 +114,38 @@ subtest 'user assign role' => sub { is $user->roles->count, 1; }; +subtest 'remove users from staff' => sub { + is $user4->from_body->id, $oxfordshire->id, 'user4 has a body'; + is $user4->email_verified, 1, 'user4 email is verified'; + is $user4->user_body_permissions->count, 1, 'user4 has permissions'; + is $user5->from_body->id, $oxfordshire->id, 'user5 has a body'; + is $user5->email_verified, 1, 'user5 email is verified'; + is $user5->user_roles->count, 1, 'user5 has a role'; + + $mech->get_ok('/admin/users'); + $mech->content_contains($user4->email); + $mech->content_contains($user5->email); + + $mech->submit_form_ok({ with_fields => { uid => $user4->id, 'remove-staff' => 'remove-staff'} }); + $mech->content_lacks($user4->email); + $mech->content_contains($user5->email); + $user4->discard_changes; + $user5->discard_changes; + is $user4->from_body, undef, 'user4 removed from body'; + is $user4->email_verified, 0, 'user4 email unverified'; + is $user4->user_body_permissions->count, 0, 'no user4 permissions'; + is $user5->from_body->id, $oxfordshire->id, 'user5 has a body'; + is $user5->email_verified, 1, 'user5 email is verified'; + is $user5->user_roles->count, 1, 'user5 has a role'; + + $mech->submit_form_ok({ with_fields => { uid => $user5->id, 'remove-staff' => 'remove-staff'} }); + $mech->content_lacks($user5->email); + $user5->discard_changes; + is $user5->from_body, undef, 'user5 has no body'; + is $user5->email_verified, 0, 'user5 email unverified'; + is $user5->user_roles->count, 0, 'no user5 roles'; +}; + subtest 'search does not show user from another council' => sub { FixMyStreet::override_config { ALLOWED_COBRANDS => [ 'oxfordshire' ], @@ -299,6 +346,7 @@ FixMyStreet::override_config { flagged => undef, is_superuser => undef, area_ids => undef, + assigned_categories_only => undef, %default_perms, roles => $role->id, }, @@ -320,6 +368,7 @@ FixMyStreet::override_config { flagged => undef, is_superuser => undef, area_ids => undef, + assigned_categories_only => undef, %default_perms, roles => $role->id, }, @@ -341,6 +390,7 @@ FixMyStreet::override_config { flagged => undef, is_superuser => undef, area_ids => undef, + assigned_categories_only => undef, %default_perms, roles => $role->id, }, @@ -365,6 +415,7 @@ FixMyStreet::override_config { flagged => undef, is_superuser => undef, area_ids => undef, + assigned_categories_only => undef, %default_perms, }, changes => { @@ -385,6 +436,7 @@ FixMyStreet::override_config { flagged => 'on', is_superuser => undef, area_ids => undef, + assigned_categories_only => undef, %default_perms, }, changes => { @@ -394,7 +446,7 @@ FixMyStreet::override_config { log_entries => [qw/edit edit edit edit/], }, { - desc => 'edit user add is_superuser', + desc => 'edit user add is_superuser and assigned_categories_only', fields => { name => 'Changed User', email => 'changed@example.com', @@ -405,10 +457,12 @@ FixMyStreet::override_config { flagged => undef, is_superuser => undef, area_ids => undef, + assigned_categories_only => undef, %default_perms, }, changes => { is_superuser => 'on', + assigned_categories_only => 'on', }, removed => [ keys %default_perms, @@ -428,6 +482,7 @@ FixMyStreet::override_config { flagged => undef, is_superuser => 'on', area_ids => undef, + assigned_categories_only => 'on', }, changes => { is_superuser => undef, diff --git a/t/app/controller/alert.t b/t/app/controller/alert.t index 41aee5bbc..34e68177c 100644 --- a/t/app/controller/alert.t +++ b/t/app/controller/alert.t @@ -1,6 +1,7 @@ use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; +use Test::MockModule; use t::Mock::Nominatim; # check that we can get the page @@ -73,4 +74,25 @@ FixMyStreet::override_config { is $mech->uri->path, '/rss/reports/Cheltenham/Lansdown'; }; +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'fixmystreet', + MAPIT_URL => 'http://mapit.uk/', + GEOCODER => '', + RECAPTCHA => { secret => 'secret', site_key => 'site_key' }, +}, sub { + subtest 'recaptcha' => sub { + $mech->get_ok('/alert/list?pc=EH11BB'); + $mech->content_lacks('g-recaptcha'); # GB is default test country + + my $mod_app = Test::MockModule->new('FixMyStreet::App'); + $mod_app->mock('user_country', sub { 'FR' }); + my $mod_lwp = Test::MockModule->new('LWP::UserAgent'); + $mod_lwp->mock('post', sub { HTTP::Response->new(200, 'OK', [], '{ "success": true }') }); + + $mech->get_ok('/alert/list?pc=EH11BB'); + $mech->content_contains('g-recaptcha'); + $mech->submit_form_ok({ with_fields => { rznvy => 'someone@example.org' } }); + }; +}; + done_testing(); diff --git a/t/app/controller/alert_new.t b/t/app/controller/alert_new.t index 7eba90530..562b173c8 100644 --- a/t/app/controller/alert_new.t +++ b/t/app/controller/alert_new.t @@ -1,3 +1,4 @@ +use utf8; use FixMyStreet::TestMech; use FixMyStreet::Script::Alerts; @@ -523,6 +524,8 @@ subtest "Test alerts are not sent for no-text updates" => sub { }; $mech->email_count_is(1); + $user2->discard_changes; + isnt $user2->last_active, undef, 'Last active has been set'; $mech->delete_user($user1); $mech->delete_user($user2); @@ -864,4 +867,48 @@ subtest 'check setting include dates in new updates cobrand option' => sub { $include_date_in_alert_override->restore(); }; +subtest 'check staff updates can include sanitized HTML' => sub { + my $user1 = $mech->create_user_ok('reporter@example.com', name => 'Reporter User'); + my $user2 = $mech->create_user_ok('staff@example.com', name => 'Staff User', from_body => $body); + my $user3 = $mech->create_user_ok('updater@example.com', name => 'Another User'); + + my $dt = DateTime->now->add( minutes => -30 ); + my $r_dt = $dt->clone->add( minutes => 20 ); + + my ($report) = $mech->create_problems_for_body(1, $body->id, 'Testing', { + user => $user1, + }); + + my $update1 = $mech->create_comment_for_problem($report, $user2, 'Staff User', '<p>This is some update text with <strong>HTML</strong> and *italics*.</p> <ul><li>Even a list</li><li>Which might work</li><li>In the <a href="https://www.fixmystreet.com/">text</a> part</li></ul> <script>not allowed</script>', 't', 'confirmed', undef, { confirmed => $r_dt->clone->add( minutes => 8 ) }); + $update1->set_extra_metadata(is_body_user => $user2->from_body->id); + $update1->set_extra_metadata(something_unicodey => "The cafɇ is here"); + $update1->update; + + $mech->create_comment_for_problem($report, $user3, 'Updater User', 'Public users <i>cannot</i> use HTML. <script>not allowed</script>', 't', 'confirmed', undef, { confirmed => $r_dt->clone->add( minutes => 9 ) }); + + my $alert_user1 = FixMyStreet::DB->resultset('Alert')->create( { + user => $user1, + alert_type => 'new_updates', + parameter => $report->id, + confirmed => 1, + whensubscribed => $dt, + } ); + ok $alert_user1, "alert created"; + + FixMyStreet::DB->resultset('AlertType')->email_alerts(); + my $email = $mech->get_email; + my $plain = $mech->get_text_body_from_email($email); + like $plain, qr/This is some update text with \*HTML\* and \*italics\*\.\r\n\r\n\* Even a list\r\n\r\n\* Which might work\r\n\r\n\* In the text \[https:\/\/www.fixmystreet.com\/\] part/, 'plain text part contains no HTML tags from staff update'; + like $plain, qr/Public users <i>cannot<\/i> use HTML\./, 'plain text part contains exactly what was entered'; + + my $html = $mech->get_html_body_from_email($email); + like $html, qr{This is some update text with <strong>HTML</strong> and <i>italics</i>\.}, 'HTML part contains HTML tags'; + unlike $html, qr/<script>/, 'HTML part contains no script tags'; + + $mech->delete_user( $user1 ); + $mech->delete_user( $user2 ); + $mech->delete_user( $user3 ); +}; + + done_testing(); diff --git a/t/app/controller/around.t b/t/app/controller/around.t index 186b833fd..3f5d31c02 100644 --- a/t/app/controller/around.t +++ b/t/app/controller/around.t @@ -9,6 +9,7 @@ use constant MIN_ZOOM_LEVEL => 88; package main; use Test::MockModule; +use t::Mock::Nominatim; use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; @@ -53,6 +54,11 @@ foreach my $test ( }; } +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'fixmystreet', + MAPIT_URL => 'http://mapit.uk/', +}, sub { + # check that exact queries result in the correct lat,lng foreach my $test ( { @@ -69,19 +75,45 @@ foreach my $test ( { subtest "check lat/lng for '$test->{pc}'" => sub { $mech->get_ok('/'); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->submit_form_ok( { with_fields => { pc => $test->{pc} } }, - "good location" ); - }; + $mech->submit_form_ok( { with_fields => { pc => $test->{pc} } }, + "good location" ); is_deeply $mech->page_errors, [], "no errors for pc '$test->{pc}'"; is_deeply $mech->extract_location, $test, "got expected location for pc '$test->{pc}'"; + $mech->get_ok('/'); + my $pc = "$test->{latitude},$test->{longitude}"; + $mech->submit_form_ok( { with_fields => { pc => $pc } }, + "good location" ); + is_deeply $mech->page_errors, [], "no errors for pc '$pc'"; + is_deeply $mech->extract_location, { %$test, pc => $pc }, + "got expected location for pc '$pc'"; }; } +subtest "check lat/lng for full plus code" => sub { + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => "9C7RXR26+R5" } } ); + is_deeply $mech->page_errors, [], "no errors for plus code"; + is_deeply $mech->extract_location, { + pc => "9C7RXR26+R5", + latitude => 55.952063, + longitude => -3.189562, + }, + "got expected location for full plus code"; +}; + +subtest "check lat/lng for short plus code" => sub { + $mech->get_ok('/'); + $mech->submit_form_ok( { with_fields => { pc => "XR26+R5 Edinburgh" } } ); + is_deeply $mech->page_errors, [], "no errors for plus code"; + is_deeply $mech->extract_location, { + pc => "XR26+R5 Edinburgh", + latitude => 55.952063, + longitude => -3.189562, + }, + "got expected location for short plus code"; +}; + my $body_edin_id = $mech->create_body_ok(2651, 'City of Edinburgh Council')->id; my $body_west_id = $mech->create_body_ok(2504, 'Westminster City Council')->id; @@ -93,10 +125,10 @@ my @edinburgh_problems = $mech->create_problems_for_body( 5, $body_edin_id, 'Aro subtest 'check lookup by reference' => sub { $mech->get_ok('/'); - $mech->submit_form_ok( { with_fields => { pc => 'ref:12345' } }, 'bad ref'); + $mech->submit_form_ok( { with_fields => { pc => '12345' } }, 'bad ref'); $mech->content_contains('Searching found no reports'); my $id = $edinburgh_problems[0]->id; - $mech->submit_form_ok( { with_fields => { pc => "ref:$id" } }, 'good ref'); + $mech->submit_form_ok( { with_fields => { pc => $id } }, 'good ref'); is $mech->uri->path, "/report/$id", "redirected to report page"; }; @@ -106,19 +138,14 @@ subtest 'check lookup by reference does not show non_public reports' => sub { }); my $id = $edinburgh_problems[0]->id; $mech->get_ok('/'); - $mech->submit_form_ok( { with_fields => { pc => "ref:$id" } }, 'non_public ref'); + $mech->submit_form_ok( { with_fields => { pc => $id } }, 'non_public ref'); $mech->content_contains('Searching found no reports'); }; subtest 'check non public reports are not displayed on around page' => sub { $mech->get_ok('/'); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, - "good location" ); - }; + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, + "good location" ); $mech->content_contains( "Around page Test 3 for $body_edin_id", 'problem to be marked non public visible' ); @@ -126,31 +153,21 @@ subtest 'check non public reports are not displayed on around page' => sub { ok $private->update( { non_public => 1 } ), 'problem marked non public'; $mech->get_ok('/'); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, - "good location" ); - }; + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, + "good location" ); $mech->content_lacks( "Around page Test 3 for $body_edin_id", 'problem marked non public is not visible' ); }; subtest 'check missing body message not shown when it does not need to be' => sub { $mech->get_ok('/'); - FixMyStreet::override_config { - ALLOWED_COBRANDS => 'fixmystreet', - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, - "good location" ); - }; + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, + "good location" ); $mech->content_lacks('yet have details for the other councils that cover this location'); }; for my $permission ( qw/ report_inspect report_mark_private/ ) { - subtest 'check non public reports are displayed on around page with $permission permission' => sub { + subtest "check non public reports are displayed on around page with $permission permission" => sub { my $body = FixMyStreet::DB->resultset('Body')->find( $body_edin_id ); my $body2 = FixMyStreet::DB->resultset('Body')->find( $body_west_id ); my $user = $mech->log_in_ok( 'test@example.com' ); @@ -162,24 +179,14 @@ for my $permission ( qw/ report_inspect report_mark_private/ ) { }); $mech->get_ok('/'); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, - "good location" ); - }; + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, + "good location" ); $mech->content_contains( "Around page Test 3 for $body_edin_id", 'problem marked non public is visible' ); $mech->content_contains( "Around page Test 2 for $body_edin_id", 'problem marked public is visible' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->get_ok('/around?pc=EH1+1BB&status=non_public'); - }; + $mech->get_ok('/around?pc=EH1+1BB&status=non_public'); $mech->content_contains( "Around page Test 3 for $body_edin_id", 'problem marked non public is visible' ); $mech->content_lacks( "Around page Test 2 for $body_edin_id", @@ -193,24 +200,14 @@ for my $permission ( qw/ report_inspect report_mark_private/ ) { }); $mech->get_ok('/'); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, - "good location" ); - }; + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB' } }, + "good location" ); $mech->content_lacks( "Around page Test 3 for $body_edin_id", 'problem marked non public is not visible' ); $mech->content_contains( "Around page Test 2 for $body_edin_id", 'problem marked public is visible' ); - FixMyStreet::override_config { - ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], - MAPIT_URL => 'http://mapit.uk/', - }, sub { - $mech->get_ok('/around?pc=EH1+1BB&status=non_public'); - }; + $mech->get_ok('/around?pc=EH1+1BB&status=non_public'); $mech->content_lacks( "Around page Test 3 for $body_edin_id", 'problem marked non public is not visible' ); $mech->content_lacks( "Around page Test 2 for $body_edin_id", @@ -218,6 +215,26 @@ for my $permission ( qw/ report_inspect report_mark_private/ ) { }; } +subtest 'check assigned-only list items do not display shortlist buttons' => sub { + my $body = FixMyStreet::DB->resultset('Body')->find( $body_edin_id ); + my $contact = $mech->create_contact_ok( category => 'Horses & Ponies', body_id => $body->id, email => "horses\@example.org" ); + $edinburgh_problems[4]->update({ category => 'Horses & Ponies' }); + + my $user = $mech->log_in_ok( 'test@example.com' ); + $user->set_extra_metadata(assigned_categories_only => 1); + $user->user_body_permissions->delete(); + $user->set_extra_metadata(categories => [ $contact->id ]); + $user->update({ from_body => $body }); + $user->user_body_permissions->find_or_create({ body => $body, permission_type => 'planned_reports' }); + + $mech->get_ok('/around?pc=EH1+1BB'); + $mech->content_contains('shortlist-add-' . $edinburgh_problems[4]->id); + $mech->content_lacks('shortlist-add-' . $edinburgh_problems[3]->id); + $mech->content_lacks('shortlist-add-' . $edinburgh_problems[1]->id); +}; + +}; # End big override_config + my $body = $mech->create_body_ok(2237, "Oxfordshire"); subtest 'check category, status and extra filtering works on /around' => sub { @@ -233,7 +250,10 @@ subtest 'check category, status and extra filtering works on /around' => sub { # Create one open and one fixed report in each category foreach my $category ( @$categories ) { my $contact = $mech->create_contact_ok( category => $category, body_id => $body->id, email => "$category\@example.org" ); - if ($category ne 'Pothole') { + if ($category eq 'Vegetation') { + $contact->set_extra_metadata(group => ['Environment', 'Green']); + $contact->update; + } elsif ($category eq 'Flytipping') { $contact->set_extra_metadata(group => ['Environment']); $contact->update; } @@ -264,6 +284,9 @@ subtest 'check category, status and extra filtering works on /around' => sub { $mech->get_ok( '/around?filter_group=Environment&bbox=' . $bbox ); $mech->content_contains('<option value="Flytipping" selected>'); + + $mech->get_ok( '/around?filter_group=Environment&filter_category=Vegetation&bbox=' . $bbox ); + $mech->content_like(qr/<optgroup label="Environment">.*?<option value="Vegetation" selected>.*?<optgroup label="Green">.*?<option value="Vegetation">/s); }; $json = $mech->get_ok_json( '/around?ajax=1&filter_category=Pothole&bbox=' . $bbox ); @@ -286,6 +309,37 @@ subtest 'check category, status and extra filtering works on /around' => sub { is scalar @$pins, 1, 'correct number of external_body reports'; }; +subtest 'check categories with same name are only shown once in filters' => sub { + my $params = { + postcode => 'OX20 1SZ', + latitude => 51.754926, + longitude => -1.256179, + }; + my $bbox = ($params->{longitude} - 0.01) . ',' . ($params->{latitude} - 0.01) + . ',' . ($params->{longitude} + 0.01) . ',' . ($params->{latitude} + 0.01); + + my $district = $mech->create_body_ok(2421, "Oxford City"); + # Identically-named categories should be combined even if their extra metadata is different + my $contact2 = $mech->create_contact_ok( category => "Pothole", body_id => $district->id, email => 'pothole@district-example.org' ); + $contact2->set_extra_metadata(some_extra_field => "dummy"); + $contact2->update; + # And categories with the same display name should be combined too + my $contact3 = $mech->create_contact_ok( category => "Pothole (alternative)", body_id => $district->id, email => 'pothole-alternative@district-example.org' ); + $contact3->set_extra_metadata(display_name => "Pothole"); + $contact3->update; + + FixMyStreet::override_config { + ALLOWED_COBRANDS => 'fixmystreet', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { category_groups => { fixmystreet => 1 } }, + }, sub { + $mech->get_ok( '/around?bbox=' . $bbox ); + $mech->content_contains('<option value="Pothole">'); + $mech->content_unlike(qr{Pothole</option>.*<option value="Pothole">\s*Pothole</option>}s, "Pothole category only appears once"); + $mech->content_lacks('<option value="Pothole (alternative)">'); + }; +}; + subtest 'check old problems not shown by default on around page' => sub { my $params = { postcode => 'OX20 1SZ', @@ -390,7 +444,7 @@ subtest 'check map zoom level customisation' => sub { MAP_TYPE => 'OSM', }, sub { $mech->get('/around?latitude=51.754926&longitude=-1.256179'); - $mech->content_contains('data-numZoomLevels=6'); + $mech->content_contains('data-numZoomLevels=7'); $mech->content_contains('data-zoomOffset=13'); }; diff --git a/t/app/controller/auth.t b/t/app/controller/auth.t index 24deb8cab..0326bbacd 100644 --- a/t/app/controller/auth.t +++ b/t/app/controller/auth.t @@ -245,19 +245,20 @@ subtest "check logging in with token" => sub { my $user = FixMyStreet::DB->resultset('User')->find( { email => $test_email } ); # token needs to be 18 characters - $user->set_extra_metadata('access_token', '1234567890abcdefgh'); + my $u = FixMyStreet::DB->resultset("User")->new({ password => '1234567890abcdefgh' }); + $user->set_extra_metadata('access_token', $u->password); $user->update(); - $mech->add_header('Authorization', 'Bearer 1234567890abcdefgh'); + $mech->add_header('Authorization', 'Bearer ' . $user->id . '-1234567890abcdefgh'); $mech->logged_in_ok; $mech->delete_header('Authorization'); $mech->not_logged_in_ok; - $mech->get_ok('/auth/check_auth?access_token=1234567890abcdefgh'); + $mech->get_ok('/auth/check_auth?access_token=' . $user->id . '-1234567890abcdefgh'); - $mech->add_header('Authorization', 'Bearer 1234567890abcdefgh'); - $user->set_extra_metadata('access_token', 'XXXXXXXXXXXXXXXXXX'); + $mech->add_header('Authorization', 'Bearer ' . $user->id . '-1234567890abcdefgh'); + $user->set_extra_metadata('access_token', '$2a$08$HNslSx7Uic7q6Ti5WYT5JOT6npYPwrwLnDMJMJoD22LIqG5TfDIKf'); $user->update(); $mech->not_logged_in_ok; @@ -287,6 +288,23 @@ subtest 'check common password AJAX call' => sub { $mech->content_contains("true"); }; +subtest 'check hibp password call' => sub { + FixMyStreet::override_config { + CHECK_HAVEIBEENPWNED => 1, + }, sub { + my $lwp = Test::MockModule->new('LWP::Simple'); + # Switch mock round from live site, so we know we're not testing live site by mistake + $lwp->mock(get => sub($) { + return '9958D0F0EE6744E7CCAFC84515FCFAD7B1B:10' if $_[0] =~ /6EF4D$/; # squirblewirble + return ''; + }); + $mech->post_ok('/auth/common_password', { password_register => 'p@ssword2' }); + $mech->content_contains("true"); + $mech->post_ok('/auth/common_password', { password_register => 'squirblewirble' }); + $mech->content_contains("That password has appeared in a known"); + }; +}; + subtest 'test forgotten password page' => sub { $mech->get_ok('/auth/forgot'); $mech->content_contains('Forgot password'); diff --git a/t/app/controller/auth_profile.t b/t/app/controller/auth_profile.t index e5dfe2764..230e02d2b 100644 --- a/t/app/controller/auth_profile.t +++ b/t/app/controller/auth_profile.t @@ -417,16 +417,16 @@ subtest "Test generate token page" => sub { "submit generate token form" ); $mech->content_contains( 'Your token has been generated', "token generated" ); + my ($token) = $mech->content =~ /<span>(.*?)<\/span>/; + my @parts = split /-/, $token, 2; + is $parts[0], $user->id, 'token has user ID at start'; $user->discard_changes(); - my $token = $user->get_extra_metadata('access_token'); - ok $token, 'access token set'; - - $mech->content_contains($token, 'access token displayed'); + $user->password($user->get_extra_metadata('access_token'), 1); + ok $user->check_password($parts[1]), 'access token set'; $mech->get_ok('/auth/generate_token'); - $mech->content_contains('Current token:'); - $mech->content_contains($token, 'access token displayed'); + $mech->content_lacks($parts[1], 'access token not displayed'); $mech->content_contains('If you generate a new token'); $mech->log_out_ok; diff --git a/t/app/controller/auth_social.t b/t/app/controller/auth_social.t index 200863029..9d1ea836f 100644 --- a/t/app/controller/auth_social.t +++ b/t/app/controller/auth_social.t @@ -15,9 +15,12 @@ FixMyStreet::App->log->disable('info'); END { FixMyStreet::App->log->enable('info'); } my $body = $mech->create_body_ok(2504, 'Westminster City Council'); +my $body2 = $mech->create_body_ok(2508, 'Hackney Council'); my ($report) = $mech->create_problems_for_body(1, $body->id, 'My Test Report'); my $test_email = $report->user->email; +my ($report2) = $mech->create_problems_for_body(1, $body2->id, 'My Test Report'); +my $test_email2 = $report->user->email; my $contact = $mech->create_contact_ok( body_id => $body->id, category => 'Damaged bin', email => 'BIN', @@ -26,11 +29,21 @@ my $contact = $mech->create_contact_ok( { code => 'bin_service', description => 'Service needed', required => 'False' }, ] ); +$mech->create_contact_ok( + body_id => $body2->id, category => 'Damaged bin', email => 'BIN', + extra => [ + { code => 'bin_type', description => 'Type of bin', required => 'True' }, + { code => 'bin_service', description => 'Service needed', required => 'False' }, + ] +); # Two options, incidentally, so that the template "Only one option, select it" # code doesn't kick in and make the tests pass my $contact2 = $mech->create_contact_ok( body_id => $body->id, category => 'Whatever', email => 'WHATEVER', ); +$mech->create_contact_ok( + body_id => $body2->id, category => 'Whatever', email => 'WHATEVER', +); my $resolver = Test::MockModule->new('Email::Valid'); my $social = Test::MockModule->new('FixMyStreet::App::Controller::Auth::Social'); @@ -88,6 +101,44 @@ for my $test ( user_extras => [ [westminster_account_id => "1c304134-ef12-c128-9212-123908123901"], ], +}, { + type => 'oidc', + config => { + ALLOWED_COBRANDS => 'hackney', + MAPIT_URL => 'http://mapit.uk/', + COBRAND_FEATURES => { + anonymous_account => { + hackney => 'test', + }, + oidc_login => { + hackney => { + client_id => 'example_client_id', + secret => 'example_secret_key', + auth_uri => 'http://oidc.example.org/oauth2/v2.0/authorize_google', + token_uri => 'http://oidc.example.org/oauth2/v2.0/token_google', + allowed_domains => [ 'example.org' ], + } + }, + do_not_reply_email => { + hackney => 'fms-hackney-DO-NOT-REPLY@hackney-example.com', + }, + verp_email_domain => { + hackney => 'hackney-example.com', + }, + } + }, + email => $mech->uniquify_email('oidc_google@example.org'), + uid => "hackney:example_client_id:my_google_user_id", + mock => 't::Mock::OpenIDConnect', + mock_hosts => ['oidc.example.org'], + host => 'oidc.example.org', + error_callback => '/auth/OIDC?error=ERROR', + success_callback => '/auth/OIDC?code=response-code&state=login', + redirect_pattern => qr{oidc\.example\.org/oauth2/v2\.0/authorize_google}, + pc => 'E8 1DY', + # Need to use a different report that's within Hackney + report => $report2, + report_email => $test_email2, } ) { @@ -100,6 +151,7 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) { next if $page eq 'update' && !$test->{update}; subtest "test $test->{type} '$state' login for page '$page'" => sub { + my $test_report = $test->{report} || $report; # Lots of user changes happening here, make sure we don't confuse # Catalyst with a cookie session user that no longer exists $mech->log_out_ok; @@ -115,9 +167,9 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) { $mech->delete_user($test->{email}); } if ($page eq 'my' && $state eq 'existing UID') { - $report->update({ user_id => FixMyStreet::DB->resultset( 'User' )->find( { email => $test->{email} } )->id }); + $test_report->update({ user_id => FixMyStreet::DB->resultset( 'User' )->find( { email => $test->{email} } )->id }); } else { - $report->update({ user_id => FixMyStreet::DB->resultset( 'User' )->find( { email => $test_email } )->id }); + $test_report->update({ user_id => FixMyStreet::DB->resultset( 'User' )->find( { email => ($report->{test_email} || $test_email) } )->id }); } # Set up a mock to catch (most, see below) requests to the OAuth API @@ -139,7 +191,7 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) { $mech->get_ok('/my'); } elsif ($page eq 'report') { $mech->get_ok('/'); - $mech->submit_form_ok( { with_fields => { pc => 'SW1A1AA' } }, "submit location" ); + $mech->submit_form_ok( { with_fields => { pc => $test->{pc} || 'SW1A1AA' } }, "submit location" ); $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); $mech->submit_form(with_fields => { category => 'Damaged bin', @@ -150,7 +202,7 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) { bin_type => 'Salt bin', }; } else { - $mech->get_ok('/report/' . $report->id); + $mech->get_ok('/report/' . $test_report->id); $fields = { update => 'Test update', }; @@ -189,7 +241,8 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) { $mech->content_contains('We need your email address, please give it below.'); # We don't have an email, so check that we can still submit it, # and the ID carries through the confirmation - $fields->{username} = $test->{email}; + $fields->{username} = $test->{email} if $page eq 'my'; + $fields->{username_register} = $test->{email} unless $page eq 'my'; $fields->{name} = 'Ffion Tester' unless $page eq 'my'; $mech->submit_form(with_fields => $fields, $page eq 'my' ? (button => 'sign_in_by_code') : ()); $mech->content_contains('Nearly done! Now check your email'); @@ -243,17 +296,17 @@ for my $state ( 'refused', 'no email', 'existing UID', 'okay' ) { } } if ($state eq 'existing UID') { - my $report_id = $report->id; - $mech->content_contains( $report->title ); + my $report_id = $test_report->id; + $mech->content_contains( $test_report->title ); $mech->content_contains( "/report/$report_id" ); } - if ($test->{type} eq 'oidc') { + if ($test->{type} eq 'oidc' && $test->{password_change_pattern}) { ok $mech->find_link( text => 'Change password', url_regex => $test->{password_change_pattern} ); } } $mech->get('/auth/sign_out'); - if ($test->{type} eq 'oidc' && $state ne 'refused' && $state ne 'no email') { + if ($test->{type} eq 'oidc' && $test->{logout_redirect_pattern} && $state ne 'refused' && $state ne 'no email') { # XXX the 'no email' situation is skipped because of some confusion # with the hosts/sessions that I've not been able to get to the bottom of. # The code does behave as expected when testing manually, however. @@ -356,7 +409,8 @@ for my $tw_state ( 'refused', 'existing UID', 'no email' ) { $mech->content_contains('We need your email address, please give it below.'); # We don't have an email, so check that we can still submit it, # and the ID carries through the confirmation - $fields->{username} = $tw_email; + $fields->{username_register} = $tw_email unless $page eq 'my'; + $fields->{username} = $tw_email if $page eq 'my'; $fields->{name} = 'Ffion Tester' unless $page eq 'my'; $mech->submit_form(with_fields => $fields, $page eq 'my' ? (button => 'sign_in_by_code') : ()); $mech->content_contains('Nearly done! Now check your email'); diff --git a/t/app/controller/contact.t b/t/app/controller/contact.t index d6e56e7cc..01e8b0886 100644 --- a/t/app/controller/contact.t +++ b/t/app/controller/contact.t @@ -382,7 +382,7 @@ for my $test ( $mech->clear_emails_ok; $mech->get_ok('/contact'); - $test->{fields}{em} = $user->email; + $test->{fields}{em} = ucfirst $user->email; # Check case $mech->submit_form_ok( { with_fields => $test->{fields} } ); my $email = $mech->get_email; diff --git a/t/app/controller/contact_enquiry.t b/t/app/controller/contact_enquiry.t index af249ec6c..f1b5b15cd 100644 --- a/t/app/controller/contact_enquiry.t +++ b/t/app/controller/contact_enquiry.t @@ -40,9 +40,18 @@ my $contact4 = $mech->create_contact_ok( category => 'Carriageway Defect', email => 'potholes@example.com', ); +my $contact5 = $mech->create_contact_ok( + body_id => $body->id, + category => 'Other (disabled)', + email => 'other@example.com', +); $contact->update( { extra => { group => 'General Enquiries' } } ); $contact2->update( { extra => { group => 'General Enquiries' } } ); $contact3->update( { extra => { group => 'Other' } } ); +$contact5->update( { extra => { group => 'Other' } } ); + +$contact5->push_extra_fields({ code => '_fms_disable_', 'disable_form' => 'true', description => 'form_disabled' }); +$contact5->update; FixMyStreet::override_config { ALLOWED_COBRANDS => ['bromley'], }, sub { subtest 'redirected to / if general enquiries not enabled' => sub { @@ -60,6 +69,7 @@ FixMyStreet::override_config { subtest 'Non-general enquiries category not shown' => sub { $mech->get_ok( '/contact/enquiry' ); $mech->content_lacks('Carriageway Defect'); + $mech->content_lacks('Other (disabled)'); $mech->content_contains('FOI Request'); }; @@ -70,7 +80,7 @@ FixMyStreet::override_config { $mech->submit_form_ok( { with_fields => { name => 'Test User', - username => 'testuser@example.org', + username_register => 'testuser@example.org', category => 'Other', detail => 'This is a general enquiry', } @@ -139,7 +149,7 @@ FixMyStreet::override_config { $mech->submit_form_ok( { with_fields => { name => 'Simon Neil', - username => $user->email, + username_register => $user->email, category => 'General Enquiry', detail => 'This is a general enquiry', } @@ -202,7 +212,7 @@ FixMyStreet::override_config { submit_problem => 1, token => $csrf, name => 'Test User', - username => 'testuser@example.org', + username_register => 'testuser@example.org', category => 'Other', detail => encode_utf8('This is a general enquiry‽'), photo1 => [ $sample_jpeg, undef, Content_Type => 'image/jpeg' ], diff --git a/t/app/controller/dashboard.t b/t/app/controller/dashboard.t index 72fc00128..fd491b540 100644 --- a/t/app/controller/dashboard.t +++ b/t/app/controller/dashboard.t @@ -20,6 +20,8 @@ use strict; use warnings; use FixMyStreet::TestMech; +use File::Temp 'tempdir'; +use Path::Tiny; use Web::Scraper; set_absolute_time('2014-02-01T12:00:00'); @@ -70,6 +72,7 @@ foreach my $problem (@fixed_problems) { foreach my $problem (@closed_problems) { $problem->update({ state => 'closed' }); + $mech->create_comment_for_problem($problem, $counciluser, 'Name', 'in progress text', 0, 'confirmed', 'in progress'); $mech->create_comment_for_problem($problem, $counciluser, 'Title', 'text', 0, 'confirmed', 'closed'); } @@ -80,9 +83,15 @@ my $categories = scraper { }, }; +my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); + FixMyStreet::override_config { ALLOWED_COBRANDS => 'no2fa', + COBRAND_FEATURES => { category_groups => { no2fa => 1 } }, MAPIT_URL => 'http://mapit.uk/', + PHOTO_STORAGE_OPTIONS => { + UPLOAD_DIR => $UPLOAD_DIR, + }, }, sub { subtest 'not logged in, redirected to login' => sub { @@ -173,13 +182,14 @@ FixMyStreet::override_config { subtest 'export as csv' => sub { $mech->create_problems_for_body(1, $body->id, 'Title', { detail => "this report\nis split across\nseveral lines", + category => 'Problem one', areas => ",$alt_area_id,2651,", }); $mech->get_ok('/dashboard?export=1'); my @rows = $mech->content_as_csv; is scalar @rows, 19, '1 (header) + 18 (reports) = 19 lines'; - is scalar @{$rows[0]}, 20, '20 columns present'; + is scalar @{$rows[0]}, 21, '21 columns present'; is_deeply $rows[0], [ @@ -188,6 +198,7 @@ FixMyStreet::override_config { 'Detail', 'User Name', 'Category', + 'Subcategory', 'Created', 'Confirmed', 'Acknowledged', @@ -206,15 +217,15 @@ FixMyStreet::override_config { ], 'Column headers look correct'; - is $rows[5]->[14], 'Trowbridge', 'Ward column is name not ID'; - is $rows[5]->[15], '529025', 'Correct Easting conversion'; - is $rows[5]->[16], '179716', 'Correct Northing conversion'; + is $rows[5]->[15], 'Trowbridge', 'Ward column is name not ID'; + is $rows[5]->[16], '529025', 'Correct Easting conversion'; + is $rows[5]->[17], '179716', 'Correct Northing conversion'; }; subtest 'export updates as csv' => sub { $mech->get_ok('/dashboard?updates=1&export=1'); my @rows = $mech->content_as_csv; - is scalar @rows, 15, '1 (header) + 14 (updates) = 15 lines'; + is scalar @rows, 18, '1 (header) + 17 (updates) = 18 lines'; is scalar @{$rows[0]}, 8, '8 columns present'; is_deeply $rows[0], @@ -235,19 +246,50 @@ FixMyStreet::override_config { subtest 'export as csv using token' => sub { $mech->log_out_ok; - $counciluser->set_extra_metadata('access_token', '1234567890abcdefgh'); + my $u = FixMyStreet::DB->resultset("User")->new({ password => '1234567890abcdefgh' }); + $counciluser->set_extra_metadata('access_token', $u->password); $counciluser->update(); $mech->get_ok('/dashboard?export=1'); like $mech->res->header('Content-type'), qr'text/html'; $mech->content_lacks('Report ID'); - $mech->add_header('Authorization', 'Bearer 1234567890abcdefgh'); + $mech->add_header('Authorization', 'Bearer ' . $counciluser->id . '-1234567890abcdefgh'); $mech->get_ok('/dashboard?export=1'); like $mech->res->header('Content-type'), qr'text/csv'; $mech->content_contains('Report ID'); $mech->delete_header('Authorization'); + + my $token = 'access_token=' . $counciluser->id . '-1234567890abcdefgh'; + $mech->get_ok("/dashboard?export=2&$token"); + is $mech->res->code, 202; + my $loc = $mech->res->header('Location'); + like $loc, qr{/dashboard/csv/.*\.csv$}; + $mech->get_ok("$loc?$token"); + like $mech->res->header('Content-type'), qr'text/csv'; + $mech->content_contains('Report ID'); }; + + subtest 'view status page' => sub { + # Simulate a partly done file + my $f = Path::Tiny->tempfile(SUFFIX => '.csv-part', DIR => path($UPLOAD_DIR, 'dashboard_csv', $counciluser->id)); + (my $name = $f->basename) =~ s/-part$//;; + + my $token = 'access_token=' . $counciluser->id . '-1234567890abcdefgh'; + $mech->get_ok("/dashboard/csv/$name?$token"); + is $mech->res->code, 202; + + $mech->log_in_ok( $counciluser->email ); + $mech->get_ok('/dashboard/status'); + $mech->content_contains('/dashboard/csv/www.example.org-body-' . $body->id . '-start_date-2014-01-02.csv'); + $mech->content_like(qr/$name\s*<br>0KB\s*<i>In progress/); + + $f->remove; + $mech->get_ok('/dashboard/status'); + $mech->content_contains('/dashboard/csv/www.example.org-body-' . $body->id . '-start_date-2014-01-02.csv'); + $mech->content_lacks('In progress'); + $mech->content_lacks('setTimeout'); + } }; FixMyStreet::override_config { diff --git a/t/app/controller/moderate.t b/t/app/controller/moderate.t index 8e84bd392..43ae1c980 100644 --- a/t/app/controller/moderate.t +++ b/t/app/controller/moderate.t @@ -51,7 +51,7 @@ sub create_report { longitude => '0.007831', user_id => $user2->id, photo => '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg', - extra => { moon => 'waxing full' }, + extra => { moon => 'waxing full', sent_to => [ 'authority@example.org' ] }, }); } my $report = create_report(); @@ -115,6 +115,7 @@ subtest 'Problem moderation' => sub { }}); $mech->base_like( qr{\Q$REPORT_URL\E} ); $mech->content_like(qr/Moderated by Bromley Council/); + $mech->content_lacks('sent_to = ARRAY(0x'); $report->discard_changes; is $report->title, 'Good good'; diff --git a/t/app/controller/my.t b/t/app/controller/my.t index 673addf0c..85902ae1a 100644 --- a/t/app/controller/my.t +++ b/t/app/controller/my.t @@ -14,17 +14,12 @@ my $other_user = FixMyStreet::DB->resultset('User')->find_or_create({ email => ' my @other = $mech->create_problems_for_body(1, 1234, 'Another Title', { user => $other_user }); my $user = $mech->log_in_ok( 'test@example.com' ); -$mech->get_ok('/my'); -is $mech->uri->path, '/my', "stayed on '/my' page"; - -$mech->content_contains('Test Title'); -$mech->content_lacks('Another Title'); - my @update; my $i = 0; +my $staff_text = '<p>this is <script>how did this happen</script> <strong>an update</strong></p><ul><li>With</li><li>A</li><li>List</li></ul>'; foreach ($user, $user, $other_user) { $update[$i] = FixMyStreet::DB->resultset('Comment')->create({ - text => 'this is an update', + text => $staff_text, user => $_, state => 'confirmed', problem => $problems[0], @@ -35,6 +30,20 @@ foreach ($user, $user, $other_user) { $i++; } +subtest 'Check loading of /my page' => sub { + $mech->get_ok('/my'); + is $mech->uri->path, '/my', "stayed on '/my' page"; + + $mech->content_contains('Test Title'); + $mech->content_lacks('Another Title'); + $mech->content_contains('<p>this is'); + $mech->content_lacks('<p>this is <strong>an update</strong></p><ul><li>With'); + + $update[0]->update({ extra => { is_superuser => 1 } }); + $mech->get_ok('/my'); + $mech->content_contains('<p>this is <strong>an update</strong></p><ul><li>With'); +}; + foreach ( { type => 'problem', id => 0, result => 404, desc => 'nothing' }, { type => 'problem', obj => $problems[0], result => 200, desc => 'own report' }, diff --git a/t/app/controller/offline.t b/t/app/controller/offline.t index 876475264..d48af676f 100644 --- a/t/app/controller/offline.t +++ b/t/app/controller/offline.t @@ -54,6 +54,7 @@ FixMyStreet::override_config { subtest 'service worker' => sub { $mech->get_ok('/service-worker.js'); + is $mech->res->header('Cache-Control'), 'max-age=0', 'service worker is not cached'; $mech->content_contains('translation_strings'); $mech->content_contains('offline/fallback'); }; diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t index b561b271a..592507288 100644 --- a/t/app/controller/questionnaire.t +++ b/t/app/controller/questionnaire.t @@ -351,7 +351,7 @@ my $comment = FixMyStreet::DB->resultset('Comment')->find_or_create( user_id => $user->id, name => 'A User', mark_fixed => 'false', - text => 'This is some update text', + text => 'This is some <strong>update</strong> text', state => 'confirmed', confirmed => $sent_time, anonymous => 'f', @@ -360,7 +360,12 @@ my $comment = FixMyStreet::DB->resultset('Comment')->find_or_create( subtest 'Check updates are shown correctly on questionnaire page' => sub { $mech->get_ok("/Q/" . $token->token); $mech->content_contains( 'Show all updates' ); - $mech->content_contains( 'This is some update text' ); + $mech->content_contains( 'This is some <strong>update</strong> text' ); +}; +subtest 'Check staff update is shown correctly on questionnaire page' => sub { + $comment->update({ extra => { is_superuser => 1 } }); + $mech->get_ok("/Q/" . $token->token); + $mech->content_contains( 'This is some <strong>update</strong> text' ); }; for my $test ( diff --git a/t/app/controller/report_display.t b/t/app/controller/report_display.t index 4bd0fc991..00c7bf19b 100644 --- a/t/app/controller/report_display.t +++ b/t/app/controller/report_display.t @@ -109,7 +109,7 @@ subtest "test a good report" => sub { my %fields = ( name => '', - username => '', + username_register => '', update => '', add_alert => 1, # defaults to true fixed => undef diff --git a/t/app/controller/report_import.t b/t/app/controller/report_import.t index b2e15330a..7b5ede7a9 100644 --- a/t/app/controller/report_import.t +++ b/t/app/controller/report_import.t @@ -376,7 +376,7 @@ subtest "Submit a correct entry (with location) to cobrand" => sub { photo2 => '', photo3 => '', phone => '', - username => 'test-ll@example.com', + username_register => 'test-ll@example.com', }, "check imported fields are shown" or diag Dumper( $mech->visible_form_values ); use Data::Dumper; diff --git a/t/app/controller/report_inspect.t b/t/app/controller/report_inspect.t index 8deb2667e..3f267a086 100644 --- a/t/app/controller/report_inspect.t +++ b/t/app/controller/report_inspect.t @@ -1,5 +1,6 @@ use FixMyStreet::TestMech; use Test::MockModule; +use Path::Class; my $mech = FixMyStreet::TestMech->new; @@ -7,7 +8,7 @@ my $brum = $mech->create_body_ok(2514, 'Birmingham City Council'); my $oxon = $mech->create_body_ok(2237, 'Oxfordshire County Council', { can_be_devolved => 1 } ); my $contact = $mech->create_contact_ok( body_id => $oxon->id, category => 'Cows', email => 'cows@example.net' ); my $contact2 = $mech->create_contact_ok( body_id => $oxon->id, category => 'Sheep', email => 'SHEEP', send_method => 'Open311' ); -my $contact3 = $mech->create_contact_ok( body_id => $oxon->id, category => 'Badgers', email => 'badgers@example.net' ); +my $contact3 = $mech->create_contact_ok( body_id => $oxon->id, category => 'Badgers & Voles', email => 'badgers@example.net' ); my $rp = FixMyStreet::DB->resultset("ResponsePriority")->create({ body => $oxon, name => 'High Priority', @@ -16,6 +17,11 @@ my $rp2 = FixMyStreet::DB->resultset("ResponsePriority")->create({ body => $oxon, name => 'Low Priority', }); +my $rp3 = FixMyStreet::DB->resultset("ResponsePriority")->create({ + body => $oxon, + name => 'Deleted Priority', + deleted => 1, +}); FixMyStreet::DB->resultset("ContactResponsePriority")->create({ contact => $contact, response_priority => $rp, @@ -42,6 +48,9 @@ my $user = $mech->log_in_ok('body@example.com'); $user->set_extra_metadata('categories', [ $contact->id ]); $user->update( { from_body => $oxon } ); +my $sample_file = file(__FILE__)->parent->file("sample.jpg")->stringify; +ok -e $sample_file, "sample file $sample_file exists"; + FixMyStreet::override_config { MAPIT_URL => 'http://mapit.uk/', ALLOWED_COBRANDS => 'fixmystreet', @@ -51,15 +60,15 @@ FixMyStreet::override_config { $mech->content_lacks('Save changes'); $mech->content_lacks('Private'); $mech->content_lacks('Priority'); - $mech->content_lacks('Traffic management'); + $mech->content_lacks('Change asset'); $mech->content_lacks('/admin/report_edit/'.$report_id.'">admin</a>)'); $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_mark_private' }); $mech->get_ok("/report/$report_id"); $mech->content_contains('Private'); $mech->content_contains('Save changes'); + $mech->content_lacks('Change asset'); $mech->content_lacks('Priority'); - $mech->content_lacks('Traffic management'); $mech->content_lacks('/admin/report_edit/'.$report_id.'">admin</a>)'); $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit_priority' }); @@ -67,7 +76,7 @@ FixMyStreet::override_config { $mech->content_contains('Private'); $mech->content_contains('Save changes'); $mech->content_contains('Priority'); - $mech->content_lacks('Traffic management'); + $mech->content_lacks('Change asset'); $mech->content_lacks('/admin/report_edit/'.$report_id.'">admin</a>)'); $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_inspect' }); @@ -75,7 +84,7 @@ FixMyStreet::override_config { $mech->content_contains('Save changes'); $mech->content_contains('Private'); $mech->content_contains('Priority'); - $mech->content_contains('Traffic management'); + $mech->content_contains('Change asset'); $mech->content_lacks('/admin/report_edit/'.$report_id.'">admin</a>)'); }; @@ -197,14 +206,14 @@ FixMyStreet::override_config { $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_inspect' }); $mech->get_ok("/report/$report_id"); - $mech->submit_form_ok({ button => 'save', with_fields => { traffic_information => 'Yes', state => 'Action scheduled', include_update => undef } }); + $mech->submit_form_ok({ button => 'save', with_fields => { detailed_information => 'Info', state => 'Action scheduled', include_update => undef } }); $report->discard_changes; my $alert = FixMyStreet::DB->resultset('Alert')->find( { user => $user, alert_type => 'new_updates', confirmed => 1, } ); is $report->state, 'action scheduled', 'report state changed'; - is $report->get_extra_metadata('traffic_information'), 'Yes', 'report data changed'; + is $report->get_extra_metadata('detailed_information'), 'Info', 'report data changed'; ok defined( $alert ) , 'sign up for alerts'; }; @@ -233,7 +242,7 @@ FixMyStreet::override_config { $user->update; }; - subtest "test update is required when instructing" => sub { + subtest "test public update is required if include_update is checked" => sub { $report->update; $report->comments->delete_all; $mech->get_ok("/report/$report_id"); @@ -439,6 +448,7 @@ FixMyStreet::override_config { subtest "default response priorities display correctly" => sub { $mech->get_ok("/report/$report_id"); $mech->content_contains('Priority</label', 'report priority list present'); + $mech->content_lacks('Deleted Priority'); like $mech->content, qr/<select name="priority" id="problem_priority" class="form-control">[^<]*<option value="" selecte/s, 'blank priority option is selected'; $mech->content_lacks('value="' . $rp->id . '" selected>High', 'non default priority not selected'); @@ -448,6 +458,12 @@ FixMyStreet::override_config { $mech->content_contains('value="' . $rp->id . '" selected>High', 'default priority selected'); }; + subtest "check when report has deleted priority" => sub { + $report->update({ response_priority => $rp3 }); + $mech->get_ok("/report/$report_id"); + $mech->content_contains('value="' . $rp3->id . '" selected>Deleted Priority'); + }; + foreach my $test ( { type => 'report_edit_priority', priority => 1 }, { type => 'report_edit_category', category => 1 }, @@ -589,7 +605,27 @@ FixMyStreet::override_config { $mech->get_ok("/report/$report_id"); $mech->content_contains('Nearest calculated address', 'Address displayed'); $mech->content_contains('Constitution Hill, London, SW1A', 'Correct address displayed'); - } + }; + + subtest "test upload photo with public updates" => sub { + $user->user_body_permissions->delete; + $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_inspect' }); + + $report->state('confirmed'); + $report->update; + $mech->get_ok("/report/$report_id"); + $mech->submit_form_ok({ button => 'save', with_fields => { + public_update => "This is a public update.", include_update => "1", + state => 'action scheduled', + photo1 => [ [ $sample_file, undef, Content_Type => 'image/jpeg' ], 1 ], + } }); + $report->discard_changes; + my $comment = $report->comments(undef, { rows => 1, order_by => { -desc => "id" }})->first; + is $comment->photo, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg', 'photo added to comment'; + $mech->get_ok("/report/$report_id"); + $mech->content_contains("/photo/c/" . $comment->id . ".0.jpeg"); + }; + }; foreach my $test ( @@ -663,15 +699,6 @@ FixMyStreet::override_config { return $perms; }); - subtest "Oxfordshire-specific traffic management options are shown" => sub { - $report->update({ state => 'confirmed' }); - $mech->get_ok("/report/$report_id"); - $mech->submit_form_ok({ button => 'save', with_fields => { traffic_information => 'Signs and Cones', state => 'Action scheduled', include_update => undef } }); - $report->discard_changes; - is $report->state, 'action scheduled', 'report state changed'; - is $report->get_extra_metadata('traffic_information'), 'Signs and Cones', 'report data changed'; - }; - subtest "admin link present on inspect page on cobrand" => sub { my $report_edit_permission = $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_edit' }); @@ -683,19 +710,20 @@ FixMyStreet::override_config { FixMyStreet::override_config { MAPIT_URL => 'http://mapit.uk/', - ALLOWED_COBRANDS => 'fixmystreet', + ALLOWED_COBRANDS => 'oxfordshire', }, sub { subtest "test category not updated if fail to include public update" => sub { $mech->get_ok("/report/$report_id"); - $mech->submit_form(button => 'save', with_fields => { category => 'Badgers' }); + $mech->submit_form(button => 'save', with_fields => { category => 'Badgers & Voles' }); $report->discard_changes; is $report->category, "Cows", "Report in correct category"; - $mech->content_contains('Badgers" selected', 'Changed category still selected'); + $mech->content_contains('Badgers & Voles" selected', 'Changed category still selected'); }; subtest "test invalid form maintains Category and priority" => sub { $mech->get_ok("/report/$report_id"); + $mech->content_like(qr/data-priorities='[^']*?Low Priority/); my $expected_fields = { state => 'action scheduled', category => 'Cows', @@ -704,14 +732,16 @@ FixMyStreet::override_config { priority => $rp->id, include_update => '1', detailed_information => 'XXX164XXXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', - traffic_information => '' + photo1 => '', + photo2 => '', + photo3 => '', }; my $values = $mech->visible_form_values('report_inspect_form'); is_deeply $values, $expected_fields, 'correct form fields present'; - $mech->submit_form(button => 'save', with_fields => { category => 'Badgers', priority => $rp2->id }); + $mech->submit_form(button => 'save', with_fields => { category => 'Badgers & Voles', priority => $rp2->id }); - $expected_fields->{category} = 'Badgers'; + $expected_fields->{category} = 'Badgers & Voles'; $expected_fields->{priority} = $rp2->id; my $new_values = $mech->visible_form_values('report_inspect_form'); @@ -724,15 +754,15 @@ FixMyStreet::override_config { $mech->submit_form( button => 'save', with_fields => { - category => 'Badgers', + category => 'Badgers & Voles', include_update => 1, public_update => 'This is a public update', }); $report->discard_changes; - is $report->category, "Badgers", "Report in correct category"; + is $report->category, "Badgers & Voles", "Report in correct category"; is $report->comments->count, 1, "Only leaves one update"; - like $report->comments->first->text, qr/Category changed.*Badgers/, 'update text included category change'; + like $report->comments->first->text, qr/Category changed.*Badgers & Voles/, 'update text included category change'; }; subtest "test non-public changing" => sub { @@ -779,10 +809,10 @@ FixMyStreet::override_config { }); subtest "test report not resent when category changes if send_method doesn't change" => sub { $mech->get_ok("/report/$report3_id"); - $mech->submit_form(button => 'save', with_fields => { category => 'Badgers', include_update => undef, }); + $mech->submit_form(button => 'save', with_fields => { category => 'Badgers & Voles', include_update => undef, }); $report3->discard_changes; - is $report3->category, "Badgers", "Report in correct category"; + is $report3->category, "Badgers & Voles", "Report in correct category"; isnt $report3->whensent, undef, "Report not marked as unsent"; is $report3->bodies_str, $oxon->id, "Reported to OCC"; }; @@ -822,7 +852,91 @@ FixMyStreet::override_config { }; }; +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + ALLOWED_COBRANDS => 'oxfordshire', +}, sub { + subtest 'test relevant staff user display' => sub { + $user->user_body_permissions->create({ body => $oxon, permission_type => 'planned_reports' }); + $user->user_body_permissions->create({ body => $oxon, permission_type => 'moderate' }); + $mech->log_in_ok('body@example.com'); -END { - done_testing(); -} + # First, check user can see staff things on reports 2 and 3 + $mech->get_ok("/report/$report2_id"); + $mech->content_contains('<select class="form-control" name="state" id="state">'); + $mech->content_contains('<div class="inspect-section">'); + $mech->get_ok("/report/$report3_id"); + $mech->content_contains('<select class="form-control" name="state" id="state">'); + $mech->content_contains('<div class="inspect-section">'); + + # User's categories are ["Cows"], which is currently report 2 + # So should be able to see staff things on 2, but no longer on 3 + $user->set_extra_metadata(assigned_categories_only => 1); + $user->update; + $mech->get_ok("/report/$report2_id"); + $mech->content_contains('<select class="form-control" name="state" id="state">'); + $mech->content_contains('<div class="inspect-section">'); + $mech->get_ok("/report/$report3_id"); + $mech->content_lacks('<select class="form-control" name="state" id="state">'); + $mech->content_lacks('<div class="inspect-section">'); + $mech->content_lacks('Moderate this report'); + $mech->content_lacks('shortlist'); + $user->unset_extra_metadata('assigned_categories_only'); + $user->update; + + # Contact 2 is "Sheep", which is currently report 3 + # So again, should be able to see staff things on 2, but no longer on 3 + $contact2->set_extra_metadata(assigned_users_only => 1); + $contact2->update; + $mech->get_ok("/report/$report2_id"); + $mech->content_contains('<select class="form-control" name="state" id="state">'); + $mech->content_contains('<div class="inspect-section">'); + $mech->get_ok("/report/$report3_id"); + $mech->content_lacks('<select class="form-control" name="state" id="state">'); + $mech->content_lacks('<div class="inspect-section">'); + $mech->content_lacks('Moderate this report'); + $mech->content_lacks('shortlist'); + $contact2->unset_extra_metadata('assigned_users_only'); + $contact2->update; + }; + + subtest 'instruct defect' => sub { + $user->user_body_permissions->create({ body => $oxon, permission_type => 'report_instruct' }); + $mech->get_ok("/report/$report2_id"); + $mech->submit_form_ok({ button => 'save', with_fields => { + public_update => "This is a public update.", include_update => "1", + traffic_information => 'Signs and cones', + state => 'action scheduled', raise_defect => 1, + defect_item_category => 'Kerbing', + } }); + $report2->discard_changes; + is $report2->get_extra_metadata('inspected'), 1, 'report marked as inspected'; + $mech->get_ok("/report/$report2_id"); + $mech->content_like(qr/Defect category<\/dt>\s*<dd>Kerbing/); + my $meta = $mech->extract_update_metas; + like $meta->[0], qr/State changed to: Action scheduled/, 'First update mentions action scheduled'; + like $meta->[1], qr/Posted by .*defect raised/, 'Update mentions defect raised'; + my $log_entry = $report2->inspection_log_entry; + is $log_entry->object_id, $report2_id, 'Log entry has correct ID'; + is $log_entry->object_type, 'problem', 'Log entry has correct type'; + is $log_entry->action, 'inspected', 'Log entry has correct action'; + }; + + subtest "test update is required when instructing defect" => sub { + $report2->unset_extra_metadata('inspected'); + $report2->update; + $report2->inspection_log_entry->delete; + $report2->comments->delete_all; + $mech->get_ok("/report/$report2_id"); + $mech->submit_form_ok({ button => 'save', with_fields => { + public_update => "", include_update => "0", + state => 'action scheduled', raise_defect => 1, + } }); + is_deeply $mech->page_errors, [ "Please provide a public update for this report." ], 'errors match'; + $report2->discard_changes; + is $report2->comments->count, 0, "Update wasn't created"; + is $report2->get_extra_metadata('inspected'), undef, 'report not marked as inspected'; + }; +}; + +done_testing(); diff --git a/t/app/controller/report_new.t b/t/app/controller/report_new.t index d2da75f2c..77eb4fefb 100644 --- a/t/app/controller/report_new.t +++ b/t/app/controller/report_new.t @@ -149,14 +149,14 @@ foreach my $test ( $mech->submit_form_ok( { - button => 'submit_register', + button => 'submit_register_mobile', with_fields => { title => 'Test Report', detail => 'Test report details.', photo1 => '', name => 'Joe Bloggs', may_show_name => '1', - username => 'test-1@example.com', + username_register => 'test-1@example.com', phone => '07903 123 456', category => 'Street lighting', password_register => $test->{password} ? 'secret' : '', @@ -641,10 +641,10 @@ subtest "category groups" => sub { } }, sub { $contact2->update( { extra => { group => ['Roads','Pavements'] } } ); - $contact9->update( { extra => { group => 'Roads' } } ); + $contact9->update( { extra => { group => 'Pavements' } } ); $contact10->update( { extra => { group => 'Roads' } } ); $mech->get_ok("/report/new?lat=$saved_lat&lon=$saved_lon"); - $mech->content_like(qr{<optgroup label="Pavements">\s*<option value='Potholes'>Potholes</option></optgroup>}); + $mech->content_like(qr{<optgroup label="Pavements">\s*<option value='Potholes'>Potholes</option>\s*<option value='Street lighting'>Street lighting</option></optgroup>}); $mech->content_like(qr{<optgroup label="Roads">\s*<option value='Potholes'>Potholes</option>\s*<option value='Street lighting'>Street lighting</option></optgroup>}); }; }; @@ -680,7 +680,7 @@ subtest "test report creation for a category that is non public" => sub { title => 'Test Report', detail => 'Test report details.', photo1 => '', - username => $user->email, + username_register => $user->email, name => 'Joe Bloggs', category => 'Street lighting', } @@ -940,7 +940,7 @@ for my $test ( title => "Test Report", detail => 'Test report details.', photo1 => '', - username => 'firstlast@example.com', + username_register => 'firstlast@example.com', may_show_name => '1', phone => '07903 123 456', category => 'Trees', @@ -1085,7 +1085,7 @@ subtest "test Hart" => sub { $mech->submit_form_ok( { with_fields => { pc => 'GU51 4AE' } }, "submit location" ); $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); my %optional_fields = $test->{confirm} ? () : - ( username => $test_email, phone => '07903 123 456' ); + ( username_register => $test_email, phone => '07903 123 456' ); # we do this as otherwise test::www::mechanize::catalyst # goes to the value set in ->host above irregardless and @@ -1279,7 +1279,7 @@ subtest "extra google analytics code displayed on email confirmation problem cre title => "Test Report", detail => 'Test report details.', photo1 => '', - username => 'firstlast@example.com', + username_register => 'firstlast@example.com', name => 'Test User', may_show_name => '1', phone => '07903 123 456', diff --git a/t/app/controller/report_new_anon.t b/t/app/controller/report_new_anon.t index d86bc8134..cba360f05 100644 --- a/t/app/controller/report_new_anon.t +++ b/t/app/controller/report_new_anon.t @@ -17,6 +17,14 @@ sub allow_anonymous_reports { } sub anonymous_account { { email => 'anoncategory@example.org', name => 'Anonymous Category' } } +package FixMyStreet::Cobrand::AnonAllowedByCategory; +use parent 'FixMyStreet::Cobrand::UKCouncils'; +sub council_url { 'anonbycategory' } +sub council_name { 'Edinburgh City Council' } +sub council_area { 'Edinburgh' } +sub council_area_id { 2651 } +sub anonymous_account { { email => 'anoncategory@example.org', name => 'Anonymous Category' } } + package main; use FixMyStreet::TestMech; @@ -269,4 +277,71 @@ subtest "test report creation anonymously by button, per category" => sub { }; +$contact2->set_extra_metadata( anonymous_allowed => 1 ); +$contact2->update; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'anonallowedbycategory', + MAPIT_URL => 'http://mapit.uk/', +}, sub { + +subtest "test report creation anonymously by button, per category from metadata" => sub { + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB', } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok({ + button => 'submit_category_part_only', + with_fields => { + category => 'Street lighting', + } + }, "submit category with no anonymous reporting"); + $mech->content_lacks('<button name="report_anonymously" value="yes" class="btn btn--block">'); # non-JS button, JS button always there + $mech->submit_form_ok({ + button => 'submit_register', + with_fields => { + category => 'Trees', + } + }, "submit category with anonymous reporting"); + + $mech->submit_form_ok({ + button => 'report_anonymously', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + } + }, "submit good details"); + $mech->content_contains('Your issue is on its way to the council'); + + my $report = FixMyStreet::DB->resultset("Problem")->search({}, { order_by => { -desc => 'id' } })->first; + ok $report, "Found the report"; + + is $report->state, 'confirmed', "report confirmed"; + is $report->bodies_str, $body->id; + is $report->name, 'Anonymous Category'; + 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'; +}; + +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { fixmystreet => '.' } ], + BASE_URL => 'https://www.fixmystreet.com', + MAPIT_URL => 'http://mapit.uk/', +}, sub { +subtest "test anonymously by button, per category from metadata limited to cobrand" => sub { + $mech->get_ok('/around'); + $mech->submit_form_ok( { with_fields => { pc => 'EH1 1BB', } }, "submit location" ); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->submit_form_ok({ + button => 'submit_category_part_only', + with_fields => { + category => 'Trees', + } + }, "submit category with no anonymous reporting"); + $mech->content_lacks('<button name="report_anonymously" value="yes" class="btn btn--block">'); # non-JS button, JS button always there +}; + +}; + done_testing(); diff --git a/t/app/controller/report_new_errors.t b/t/app/controller/report_new_errors.t index f45f13c1e..470cb7d79 100644 --- a/t/app/controller/report_new_errors.t +++ b/t/app/controller/report_new_errors.t @@ -112,6 +112,7 @@ foreach my $test ( photo3 => '', name => '', may_show_name => '1', + username_register => '', username => '', phone => '', password_sign_in => '', @@ -137,6 +138,7 @@ foreach my $test ( photo3 => '', name => '', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Something bad', @@ -165,6 +167,7 @@ foreach my $test ( photo3 => '', name => '', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -190,6 +193,7 @@ foreach my $test ( photo3 => '', name => '', may_show_name => undef, + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -215,6 +219,7 @@ foreach my $test ( photo3 => '', name => 'Bob Jones', may_show_name => undef, + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -239,6 +244,7 @@ foreach my $test ( photo3 => '', name => 'Bob Jones', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -263,6 +269,7 @@ foreach my $test ( photo3 => '', name => 'Bob Jones', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -287,6 +294,7 @@ foreach my $test ( photo3 => '', name => 'DUDE', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -310,6 +318,7 @@ foreach my $test ( photo3 => '', name => 'anonymous', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -333,13 +342,14 @@ foreach my $test ( photo3 => '', name => 'Joe Smith', may_show_name => '1', - username => 'not an email', + username_register => 'not an email', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', password_register => '', }, - changes => { username => 'notanemail' }, + changes => {}, errors => [ 'Please enter a valid email', ], }, { @@ -353,6 +363,7 @@ foreach my $test ( photo3 => '', name => '', may_show_name => '1', + username_register => '', username => '', phone => '', category => 'Street lighting', @@ -379,7 +390,8 @@ foreach my $test ( photo3 => '', name => ' Bob Jones ', may_show_name => '1', - username => ' BOB @ExAmplE.COM ', + username_register => ' BOB @ExAmplE.COM ', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', @@ -387,7 +399,6 @@ foreach my $test ( }, changes => { name => 'Bob Jones', - username => 'bob@example.com', }, errors => [ 'Please enter a subject', 'Please enter some details', ], }, @@ -402,7 +413,8 @@ foreach my $test ( photo3 => '', name => 'Bob Jones', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', @@ -424,7 +436,8 @@ foreach my $test ( photo3 => '', name => 'Bob Jones', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', @@ -446,7 +459,8 @@ foreach my $test ( photo3 => '', name => 'Bob Jones', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', @@ -468,14 +482,14 @@ foreach my $test ( photo3 => '', name => 'Joe Smith', may_show_name => '1', - username => 'user@example.com', + username_register => 'user@example.com', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', password_register => '', }, changes => { - username => 'user@example.com', title => 'User@example.com' }, errors => [ 'Please make sure you are not including an email address', ], @@ -492,7 +506,8 @@ foreach my $test ( photo3 => '', name => 'Bob Example', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Trees', password_sign_in => '', @@ -512,7 +527,8 @@ foreach my $test ( photo3 => '', name => 'Bob Example', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Trees', password_sign_in => '', @@ -532,7 +548,8 @@ foreach my $test ( photo3 => '', name => 'Bob Example', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '123456789 12345678910', category => 'Trees', password_sign_in => '', @@ -552,7 +569,8 @@ foreach my $test ( photo3 => '', name => 'This is a very long name that should fail validation', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Street lighting', password_sign_in => '', @@ -572,7 +590,8 @@ foreach my $test ( photo3 => '', name => 'This is a very long name that should fail validation', may_show_name => '1', - username => 'bob@example.com', + username_register => 'bob@example.com', + username => '', phone => '', category => 'Trees', password_sign_in => '', @@ -592,7 +611,8 @@ foreach my $test ( photo3 => '', name => 'This is a really extraordinarily long name that definitely should fail validation', may_show_name => '1', - username => 'bob.has.a.very.long.email@thisisalonghostname.example.com', + username_register => 'bob.has.a.very.long.email@thisisalonghostname.example.com', + username => '', phone => '01234 5678910 09876 54321 ext 203', category => 'Trees', password_sign_in => '', @@ -612,7 +632,8 @@ foreach my $test ( photo3 => '', name => 'A User', may_show_name => '1', - username => 'user@example.org', + username_register => 'user@example.org', + username => '', phone => '', category => 'Trees', password_sign_in => '', @@ -632,7 +653,8 @@ foreach my $test ( photo3 => '', name => 'A User', may_show_name => '1', - username => 'user@example.org', + username_register => 'user@example.org', + username => '', phone => '', category => 'Trees', password_sign_in => '', @@ -702,6 +724,26 @@ subtest "test password errors for a user who is signing in as they report" => su title => 'Test Report', detail => 'Test report details.', photo1 => '', + username => 'test-2', + password_sign_in => 'secret1', + category => 'Street lighting', + } + }, + "submit with wrong password" + ); + + is_deeply $mech->page_errors, [ + "Please enter a valid email", + "There was a problem with your login information. If you cannot remember your password, or do not have one, please fill in the \x{2018}No\x{2019} section of the form.", + ], "check there were errors"; + + $mech->submit_form_ok( + { + button => 'submit_sign_in', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + photo1 => '', username => 'test-2@example.com', password_sign_in => 'secret1', category => 'Street lighting', diff --git a/t/app/controller/report_new_open311.t b/t/app/controller/report_new_open311.t index 08435fb2b..ebbb06567 100644 --- a/t/app/controller/report_new_open311.t +++ b/t/app/controller/report_new_open311.t @@ -108,7 +108,8 @@ my $empty_form = { photo3 => '', name => '', may_show_name => '1', - username => '', + username_register => '', + username => '', phone => '', category => '', password_sign_in => '', @@ -130,14 +131,14 @@ foreach my $test ( 'This information is required', 'Please enter a subject', 'Please enter some details', - 'Please enter your email', 'Please enter your name', + 'Please enter your email', ], submit_with => { title => 'test', detail => 'test detail', name => 'Test User', - username => 'testopen311@example.com', + username_register => 'testopen311@example.com', category => 'Street lighting', number => 27, type => 'old', @@ -170,14 +171,14 @@ foreach my $test ( 'This information is required', 'Please enter a subject', 'Please enter some details', - 'Please enter your email', 'Please enter your name', + 'Please enter your email', ], submit_with => { title => 'test', detail => 'test detail', name => 'Test User', - username => 'testopen311@example.com', + username_register => 'testopen311@example.com', size => 'big', colour => 'red', }, @@ -201,7 +202,7 @@ foreach my $test ( $mech->clear_emails_ok; # check that the user does not exist - my $test_email = $test->{submit_with}->{username}; + my $test_email = $test->{submit_with}->{username_register}; my $user = FixMyStreet::DB->resultset('User')->find( { email => $test_email } ); if ( $user ) { $user->problems->delete; @@ -394,6 +395,14 @@ subtest "Category extras includes form disabling string" => sub { $contact4->push_extra_fields({ datatype_description => 'Please please ring', description => 'Is it dangerous?', code => 'dangerous', variable => 'true', order => '0', values => [ { name => 'Yes', key => 'yes', disable => 1 }, { name => 'No', key => 'no' } ] }); + $contact4->push_extra_fields({ datatype_description => 'Please ring different numbers', description => 'What sort of dangerous?', code => 'danger_type', + variable => 'true', order => '0', values => [ + { name => 'slightly', key => 'slightly', disable => 1, disable_message => 'Ring the slightly number' }, + { name => 'very', key => 'very', disable => 1, disable_message => 'Ring the very number' }, + { name => 'extremely', key => 'extremely', disable => 1, disable_message => 'Ring the very number' }, + { name => 'No', key => 'no' } + ] + }); $contact4->update; for ( { url => '/report/new/ajax?' }, @@ -401,6 +410,7 @@ subtest "Category extras includes form disabling string" => sub { ) { my $json = $mech->get_ok_json($_->{url} . '&latitude=55.952055&longitude=-3.189579'); my $output = $json->{by_category} ? $json->{by_category}{Pothole}{disable_form} : $json->{disable_form}; + $output->{questions} = [ sort { $a->{message} cmp $b->{message} } @{ $output->{questions} } ]; is_deeply $output, { all => 'Please ring us!', questions => [ @@ -409,6 +419,16 @@ subtest "Category extras includes form disabling string" => sub { code => 'dangerous', answers => [ 'yes' ], }, + { + message => 'Ring the slightly number', + code => 'danger_type', + answers => [ 'slightly' ], + }, + { + message => 'Ring the very number', + code => 'danger_type', + answers => [ 'very', 'extremely' ], + }, ], }; } @@ -433,7 +453,7 @@ subtest "Category extras includes form disabling string" => sub { # Test submission of whole form, switching back to a blocked category at the same time $mech->submit_form_ok({ with_fields => { category => 'Pothole', title => 'Title', detail => 'Detail', - username => 'testing@example.org', name => 'Testing Example', + username_register => 'testing@example.org', name => 'Testing Example', } }); $mech->content_contains('<div id="js-category-stopper" class="box-warning" role="alert" aria-live="assertive">'); $mech->content_contains('Please ring us!'); diff --git a/t/app/controller/report_new_text.t b/t/app/controller/report_new_text.t index 852cdac76..fa012c6ae 100644 --- a/t/app/controller/report_new_text.t +++ b/t/app/controller/report_new_text.t @@ -15,20 +15,46 @@ $mech->create_contact_ok( body_id => $body->id, category => 'Street lighting', e $mech->create_contact_ok( body_id => $body->id, category => 'Trees', email => 'trees@example.com' ); # test that phone number validation works okay +my %defaults = ( + title => 'Title', detail => 'Detail', name => 'Bob Jones', + category => 'Street lighting', may_show_name => 1, + photo1 => '', photo2 => '', photo3 => '', + password_register => '', password_sign_in => '', +); foreach my $test ( { + msg => 'missing update method', + pc => 'EH1 1BB', + fields => { + update_method => undef, phone => '', email => '', + %defaults, + }, + changes => { + username => '', + }, + errors => [ 'Please enter your email', 'Please pick your update preference' ], + }, + { + msg => 'email method', + pc => 'EH1 1BB', + fields => { + update_method => 'email', phone => '', email => 'bademail', + %defaults, + }, + changes => { + username => '', + }, + errors => [ 'Please enter a valid email' ], + }, + { msg => 'invalid number', pc => 'EH1 1BB', fields => { - username => '0121 4960000000', email => '', phone => '', - title => 'Title', detail => 'Detail', name => 'Bob Jones', - category => 'Street lighting', - may_show_name => '1', - photo1 => '', photo2 => '', photo3 => '', - password_register => '', password_sign_in => '', + update_method => 'phone', phone => '0121 4960000000', email => '', + %defaults, }, changes => { - username => '01214960000000', + username => '', phone => '01214960000000', }, errors => [ 'Please check your phone number is correct' ], @@ -37,19 +63,28 @@ foreach my $test ( msg => 'landline number', pc => 'EH1 1BB', fields => { - username => '0121 4960000', email => '', phone => '', - title => 'Title', detail => 'Detail', name => 'Bob Jones', - category => 'Street lighting', - may_show_name => '1', - photo1 => '', photo2 => '', photo3 => '', - password_register => '', password_sign_in => '', + update_method => 'phone', phone => '0121 4960000', email => '', + %defaults, }, changes => { - username => '0121 496 0000', + username => '', phone => '0121 496 0000', }, errors => [ 'Please enter a mobile number', ], }, + { + msg => 'number that fails', + pc => 'EH1 1BB', + fields => { + update_method => 'phone', phone => '+18165550101', email => '', + %defaults, + }, + changes => { + username => '', + phone => '+1 816-555-0101', + }, + errors => [ 'Sending a confirmation text failed: "Unable to send (21408)"' ], + }, ) { subtest "check form errors where $test->{msg}" => sub { @@ -60,6 +95,7 @@ foreach my $test ( MAPIT_URL => 'http://mapit.uk/', SMS_AUTHENTICATION => 1, PHONE_COUNTRY => 'GB', + TWILIO_ACCOUNT_SID => 'AC123', }, sub { $mech->submit_form_ok( { with_fields => { pc => $test->{pc} } }, "submit location" ); @@ -142,7 +178,8 @@ foreach my $test ( title => 'Test Report', detail => 'Test report details.', photo1 => '', name => 'Joe Bloggs', may_show_name => '1', - username => $test_phone, + update_method => 'phone', + phone => $test_phone, category => 'Street lighting', password_register => $test->{password} ? 'secret' : '', } diff --git a/t/app/controller/report_new_unresponsive.t b/t/app/controller/report_new_unresponsive.t index 033475c25..211f7198d 100644 --- a/t/app/controller/report_new_unresponsive.t +++ b/t/app/controller/report_new_unresponsive.t @@ -107,7 +107,7 @@ sub make_report { detail => 'Test report details.', photo1 => '', name => 'Joe Bloggs', - username => $user->email, + username_register => $user->email, may_show_name => '1', phone => '07903 123 456', category => 'Trees', diff --git a/t/app/controller/report_new_update.t b/t/app/controller/report_new_update.t index cbb31cea4..e20975c3a 100644 --- a/t/app/controller/report_new_update.t +++ b/t/app/controller/report_new_update.t @@ -1,4 +1,5 @@ use FixMyStreet::TestMech; +use FixMyStreet::Script::Alerts; # disable info logs for this test run FixMyStreet::App->log->disable('info'); @@ -43,6 +44,9 @@ subtest "test report creation with initial auto-update" => sub { is $comment->user->id, $comment_user->id; is $comment->external_id, 'auto-internal'; is $comment->name, 'Glos Council'; + + FixMyStreet::Script::Alerts::send(); + my $email = $mech->get_email; }; done_testing; diff --git a/t/app/controller/report_update_text.t b/t/app/controller/report_update_text.t index 52f221264..fbf5ca0c6 100644 --- a/t/app/controller/report_update_text.t +++ b/t/app/controller/report_update_text.t @@ -58,21 +58,25 @@ my $comment = FixMyStreet::DB->resultset('Comment')->find_or_create( { my $comment_id = $comment->id; ok $comment, "created test update - $comment_id"; +my %defaults = ( + username => '', + update => 'Update', + name => 'Name', + photo1 => '', + photo2 => '', + photo3 => '', + fixed => undef, + add_alert => 1, + may_show_name => undef, + password_sign_in => '', + password_register => '', +); for my $test ( { desc => 'Invalid phone', fields => { - username => '01214960000000', - update => 'Update', - name => 'Name', - photo1 => '', - photo2 => '', - photo3 => '', - fixed => undef, - add_alert => 1, - may_show_name => undef, - password_sign_in => '', - password_register => '', + username_register => '01214960000000', + %defaults, }, changes => {}, field_errors => [ 'Please check your phone number is correct' ] @@ -80,23 +84,21 @@ for my $test ( { desc => 'landline number', fields => { - username => '01214960000', - update => 'Update', - name => 'Name', - photo1 => '', - photo2 => '', - photo3 => '', - fixed => undef, - add_alert => 1, - may_show_name => undef, - password_register => '', - password_sign_in => '', - }, - changes => { - username => '0121 496 0000', + username_register => '01214960000', + %defaults, }, + changes => {}, field_errors => [ 'Please enter a mobile number' ] }, + { + desc => 'fails to send', + fields => { + username_register => '+18165550101', + %defaults, + }, + changes => {}, + field_errors => [ 'Sending a confirmation text failed: "Unable to send (21408)"' ] + }, ) { subtest "submit an update - $test->{desc}" => sub { @@ -104,6 +106,7 @@ for my $test ( FixMyStreet::override_config { SMS_AUTHENTICATION => 1, + TWILIO_ACCOUNT_SID => 'AC123', PHONE_COUNTRY => 'GB', }, sub { $mech->submit_form_ok( { with_fields => $test->{fields} }, 'submit update' ); @@ -126,7 +129,7 @@ for my $test ( desc => 'submit an update, unregistered, logged out', form_values => { submit_update => 1, - username => $test_phone, + username_register => $test_phone, update => 'Update from an unregistered user', add_alert => undef, name => 'Unreg User', @@ -137,7 +140,7 @@ for my $test ( desc => 'submit an update, unregistered, logged out, sign up for alerts', form_values => { submit_update => 1, - username => $test_phone, + username_register => $test_phone, update => 'Update from an unregistered user', add_alert => 1, name => 'Unreg User', @@ -149,7 +152,7 @@ for my $test ( registered => 1, form_values => { submit_update => 1, - username => $test_phone, + username_register => $test_phone, update => 'Update from a registered user', add_alert => undef, name => 'Reg User', @@ -194,7 +197,7 @@ for my $test ( ok $update, 'found update in database'; is $update->state, 'unconfirmed', 'update unconfirmed'; my $details = $test->{form_values}; - is $update->user->phone, $details->{username}, 'update phone'; + is $update->user->phone, $details->{username_register}, 'update phone'; is $update->user->phone_verified, 1; is $update->text, $details->{update}, 'update text'; is $add_alerts, $details->{add_alert} ? 1 : 0, 'do not sign up for alerts'; @@ -211,7 +214,7 @@ for my $test ( ok $user->check_password( 'new_secret' ), 'password changed'; is $user->name, 'Reg User', 'name changed'; } else { - $user = FixMyStreet::DB->resultset( 'User' )->find( { phone => $details->{username} } ); + $user = FixMyStreet::DB->resultset( 'User' )->find( { phone => $details->{username_register} } ); ok $user, 'found user'; } diff --git a/t/app/controller/report_updates.t b/t/app/controller/report_updates.t index 07ee48587..2b60867b8 100644 --- a/t/app/controller/report_updates.t +++ b/t/app/controller/report_updates.t @@ -22,6 +22,8 @@ my $user2 = $mech->create_user_ok('commenter@example.com', name => 'Commenter'); my $body = $mech->create_body_ok(2504, 'Westminster City Council'); +my $contact = $mech->create_contact_ok( body_id => $body->id, category => 'Other', email => 'other' ); + my $dt = DateTime->new( year => 2011, month => 04, @@ -270,7 +272,8 @@ for my $test ( { desc => 'No email, no message', fields => { - username => '', + username_register => '', + username => '', update => '', name => '', photo1 => '', @@ -283,12 +286,13 @@ for my $test ( password_sign_in => '', }, changes => {}, - field_errors => [ 'Please enter a message', 'Please enter your email', 'Please enter your name' ] + field_errors => [ 'Please enter a message', 'Please enter your name', 'Please enter your email' ] }, { desc => 'Invalid email, no message', fields => { - username => 'test', + username_register => 'test', + username => '', update => '', name => '', photo1 => '', @@ -301,12 +305,13 @@ for my $test ( password_register => '', }, changes => {}, - field_errors => [ 'Please enter a message', 'Please enter a valid email', 'Please enter your name' ] + field_errors => [ 'Please enter a message', 'Please enter your name', 'Please enter a valid email' ] }, { desc => 'email with spaces, no message', fields => { - username => 'test @ example. com', + username_register => 'test @ example. com', + username => '', update => '', name => '', photo1 => '', @@ -318,15 +323,14 @@ for my $test ( password_register => '', password_sign_in => '', }, - changes => { - username => 'test@example.com', - }, + changes => {}, field_errors => [ 'Please enter a message', 'Please enter your name' ] }, { desc => 'email with uppercase, no message', fields => { - username => 'test@EXAMPLE.COM', + username_register => 'test@EXAMPLE.COM', + username => '', update => '', name => '', photo1 => '', @@ -338,9 +342,7 @@ for my $test ( password_register => '', password_sign_in => '', }, - changes => { - username => 'test@example.com', - }, + changes => {}, field_errors => [ 'Please enter a message', 'Please enter your name' ] }, ) @@ -367,6 +369,7 @@ for my $test ( desc => 'submit an update for a non registered user', initial_values => { name => '', + username_register => '', username => '', may_show_name => undef, add_alert => 1, @@ -380,7 +383,7 @@ for my $test ( }, form_values => { submit_update => 1, - username => 'unregistered@example.com', + username_register => 'unregistered@example.com', update => 'Update from an unregistered user', add_alert => undef, name => 'Unreg User', @@ -392,6 +395,7 @@ for my $test ( desc => 'submit an update for a non registered user and sign up', initial_values => { name => '', + username_register => '', username => '', may_show_name => undef, add_alert => 1, @@ -405,7 +409,7 @@ for my $test ( }, form_values => { submit_update => 1, - username => 'unregistered@example.com', + username_register => 'unregistered@example.com', update => "update from an\r\n\r\nunregistered user", add_alert => 1, name => 'Unreg User', @@ -463,14 +467,14 @@ for my $test ( ok $update, 'found update in database'; is $update->state, 'unconfirmed', 'update unconfirmed'; - is $update->user->email, $details->{username}, 'update email'; + is $update->user->email, $details->{username_register}, 'update email'; is $update->text, $details->{update}, 'update text'; is $add_alerts, $details->{add_alert} ? 1 : 0, 'do not sign up for alerts'; $mech->get_ok( $url ); $mech->content_contains("/report/$report_id#update_$update_id"); - my $unreg_user = FixMyStreet::DB->resultset( 'User' )->find( { email => $details->{username} } ); + my $unreg_user = FixMyStreet::DB->resultset( 'User' )->find( { email => $details->{username_register} } ); ok $unreg_user, 'found user'; @@ -495,6 +499,7 @@ for my $test ( desc => 'overriding email confirmation allows report confirmation with no email sent', initial_values => { name => '', + username_register => '', username => '', may_show_name => undef, add_alert => 1, @@ -508,7 +513,7 @@ for my $test ( }, form_values => { submit_update => 1, - username => 'unregistered@example.com', + username_register => 'unregistered@example.com', update => "update no email confirm", add_alert => 1, name => 'Unreg User', @@ -560,10 +565,10 @@ for my $test ( ok $update, 'found update in database'; is $update->state, 'confirmed', 'update confirmed'; - is $update->user->email, $details->{username}, 'update email'; + is $update->user->email, $details->{username_register}, 'update email'; is $update->text, $details->{update}, 'update text'; - my $unreg_user = FixMyStreet::DB->resultset( 'User' )->find( { email => $details->{username} } ); + my $unreg_user = FixMyStreet::DB->resultset( 'User' )->find( { email => $details->{username_register} } ); ok $unreg_user, 'found user'; @@ -842,8 +847,9 @@ subtest "check comment with no status change has not status in meta" => sub { $user->from_body( undef ); $user->update; + $report->update( { state => 'fixed - user' } ); my $comment = $report->comments->first; - $comment->update( { mark_fixed => 1, problem_state => 'fixed - council' } ); + $comment->update( { mark_fixed => 1, problem_state => 'fixed - user' } ); $mech->get_ok("/report/$report_id"); @@ -869,8 +875,8 @@ subtest "check comment with no status change has not status in meta" => sub { my $update = pop @updates; - is $report->state, 'fixed - council', 'correct report state'; - is $update->problem_state, 'fixed - council', 'correct update state'; + is $report->state, 'fixed - user', 'correct report state'; + is $update->problem_state, 'fixed - user', 'correct update state'; my $update_meta = $mech->extract_update_metas; unlike $update_meta->[1], qr/State changed to/, 'update meta does not include state change'; @@ -905,6 +911,7 @@ subtest "check comment with no status change has not status in meta" => sub { is $report->state, 'investigating', 'correct report state'; is $update->problem_state, 'investigating', 'correct update state'; + is $update->get_extra_metadata('is_body_user'), $body->id, 'correct metadata'; $update_meta = $mech->extract_update_metas; like $update_meta->[0], qr/fixed/i, 'first update meta says fixed'; unlike $update_meta->[2], qr/State changed to/, 'second update meta does not include state change'; @@ -1094,10 +1101,10 @@ subtest $test->{desc} => sub { unlike $update_meta->[1], qr/Commenter/, 'commenter name not included'; like $update_meta->[0], qr/investigating/i, 'update meta includes state change'; - if ($test->{body} || $test->{bodyuser}) { - like $update_meta->[1], qr/Westminster/, 'body user update uses body name'; - } elsif ($test->{superuser}) { + if ($test->{superuser}) { like $update_meta->[1], qr/an administrator/, 'superuser update says an administrator'; + } elsif ($test->{body} || $test->{bodyuser}) { + like $update_meta->[1], qr/Westminster/, 'body user update uses body name'; } ok $user->user_body_permissions->create({ @@ -1219,6 +1226,21 @@ $report->comments->delete; for my $test ( { + desc => 'submit an update with bad email and password', + form_values => { + submit_update => 1, + username => 'registered@', + update => 'Update from a user', + add_alert => undef, + password_sign_in => 'secret', + }, + field_errors => [ + 'Please enter a valid email', + "There was a problem with your login information. If you cannot remember your password, or do not have one, please fill in the \x{2018}No\x{2019} section of the form.", + 'Please enter your name', # FIXME Not really necessary error + ], + }, + { desc => 'submit an update for a registered user, signing in with wrong password', form_values => { submit_update => 1, @@ -1304,7 +1326,7 @@ subtest 'submit an update for a registered user, creating update by email' => su $mech->submit_form_ok( { with_fields => { submit_update => 1, - username => $user->email, + username_register => $user->email, update => 'Update from a user', add_alert => undef, name => 'New Name', @@ -1753,7 +1775,7 @@ for my $test ( fields => { submit_update => 1, name => 'Test User', - username => $report->user->email, + username_register => $report->user->email, may_show_name => 1, update => 'update from owner', add_alert => undef, @@ -1775,7 +1797,7 @@ for my $test ( submit_update => 1, name => 'Test User', may_show_name => 1, - username => $report->user->email, + username_register => $report->user->email, update => 'update from owner', add_alert => undef, fixed => 1, @@ -1840,7 +1862,7 @@ for my $test ( my $update = $report->comments->first; ok $update, 'found update'; is $update->text, $results->{update}, 'update text'; - is $update->user->email, $test->{fields}->{username}, 'update user'; + is $update->user->email, $test->{fields}->{username_register}, 'update user'; is $update->state, 'unconfirmed', 'update confirmed'; is $update->anonymous, $test->{anonymous}, 'user anonymous'; @@ -1893,6 +1915,18 @@ for my $test ( }; } +$mech->log_in_ok( $report->user->email ); + +my %standard_fields = ( + name => $report->user->name, + update => 'update text', + photo1 => '', + photo2 => '', + photo3 => '', + may_show_name => 1, + add_alert => 1, +); + for my $test ( { desc => 'update confirmed without marking as fixed leaves state unchanged', @@ -2094,18 +2128,6 @@ for my $test ( }, ) { subtest $test->{desc} => sub { - $mech->log_in_ok( $report->user->email ); - - my %standard_fields = ( - name => $report->user->name, - update => 'update text', - photo1 => '', - photo2 => '', - photo3 => '', - may_show_name => 1, - add_alert => 1, - ); - my %expected_fields = ( %standard_fields, %{ $test->{expected_form_fields} }, @@ -2143,6 +2165,17 @@ for my $test ( }; } +subtest 'check disabling of reopening' => sub { + $report->state('fixed - council'); + $report->update; + $mech->get_ok("/report/$report_id"); + $mech->content_contains('This problem has not been fixed'); + $contact->set_extra_metadata( reopening_disallowed => 1 ); + $contact->update; + $mech->get_ok("/report/$report_id"); + $mech->content_lacks('This problem has not been fixed'); +}; + subtest 'check have to be logged in for creator fixed questionnaire' => sub { $mech->log_out_ok(); @@ -2178,4 +2211,98 @@ FixMyStreet::override_config { }; }; +subtest 'check disabling of updates per category' => sub { + $contact->set_extra_metadata( updates_disallowed => 1 ); + $contact->update; + $mech->get_ok("/report/$report_id"); + $mech->content_lacks('Provide an update'); +}; + +subtest 'check that only staff can display HTML in updates' => sub { + $report->comments->delete; + $user->update({ from_body => undef, is_superuser => 0 }); + + my @lines = ( + "This update contains:", + "1. <strong>some staff-allowed HTML</strong>", + "2. *some Markdown-style italics*", + "3. <script>some disallowed HTML</script>", + "4. An automatic link: https://myfancylink.fixmystreet.com/", + "5. A block-level element: <p>This is its own para</p>", + "" + ); + my $comment = FixMyStreet::DB->resultset('Comment')->create( + { + user => $user, + problem_id => $report->id, + text => join("\n\n", @lines), + confirmed => DateTime->now( time_zone => 'local'), + problem_state => 'confirmed', + anonymous => 0, + mark_open => 0, + mark_fixed => 0, + state => 'confirmed', + } + ); + + # First check that comments from a public user don't receive special treatment + $mech->get_ok( "/report/" . $report->id ); + + $mech->content_contains("1. <strong>some staff-allowed HTML</strong>"); + $mech->content_lacks("<strong>some staff-allowed HTML</strong>"); + + $mech->content_contains("2. *some Markdown-style italics*"); + $mech->content_lacks("<i>some Markdown-style italics</i>"); + $mech->content_lacks("<i>some Markdown-style italics</i>"); + + $mech->content_contains("3. <script>some disallowed HTML</script>"); + $mech->content_lacks("<script>some disallowed HTML</script>"); + + $mech->content_contains('4. An automatic link: <a href="https://myfancylink.fixmystreet.com/">https://myfancylink.fixmystreet.com/</a>') or diag $mech->content; + + $mech->content_contains("5. A block-level element: <p>This is its own para</p>"); + $mech->content_lacks("5. A block-level element: <p>This is its own para</p>"); + + # Now check that comments from a member of staff user do allow HTML/italic markup + $comment->set_extra_metadata(is_body_user => $body->id); + $comment->update; + $mech->get_ok( "/report/" . $report->id ); + + $mech->content_contains("1. <strong>some staff-allowed HTML</strong>"); + $mech->content_lacks("<strong>some staff-allowed HTML</strong>"); + + $mech->content_contains("2. <i>some Markdown-style italics</i>"); + $mech->content_lacks("*some Markdown-style italics*"); + $mech->content_lacks("<i>some Markdown-style italics</i>"); + + $mech->content_lacks("some disallowed HTML"); + + $mech->content_contains('4. An automatic link: <a href="https://myfancylink.fixmystreet.com/">https://myfancylink.fixmystreet.com/</a>'); + + $mech->content_contains("5. A block-level element: <p>This is its own para</p>"); + $mech->content_lacks("<p>\n5. A block-level element: <p>This is its own para</p></p>"); + + # and the same for superusers + $comment->unset_extra_metadata('is_body_user'); + $comment->set_extra_metadata(is_superuser => 1); + $comment->update; + $mech->get_ok( "/report/" . $report->id ); + + $mech->content_contains("1. <strong>some staff-allowed HTML</strong>"); + $mech->content_lacks("<strong>some staff-allowed HTML</strong>"); + + $mech->content_contains("2. <i>some Markdown-style italics</i>"); + $mech->content_lacks("*some Markdown-style italics*"); + $mech->content_lacks("<i>some Markdown-style italics</i>"); + + $mech->content_lacks("some disallowed HTML"); + + $mech->content_contains('4. An automatic link: <a href="https://myfancylink.fixmystreet.com/">https://myfancylink.fixmystreet.com/</a>'); + + $mech->content_contains("5. A block-level element: <p>This is its own para</p>"); + $mech->content_lacks("<p>\n5. A block-level element: <p>This is its own para</p></p>"); + +}; + + done_testing(); diff --git a/t/app/controller/waste.t b/t/app/controller/waste.t new file mode 100644 index 000000000..748904995 --- /dev/null +++ b/t/app/controller/waste.t @@ -0,0 +1,211 @@ +use utf8; +use Test::MockModule; +use Test::MockTime qw(:all); +use FixMyStreet::TestMech; +use FixMyStreet::Script::Reports; + +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +# Mock fetching bank holidays +my $uk = Test::MockModule->new('FixMyStreet::Cobrand::UK'); +$uk->mock('_fetch_url', sub { '{}' }); + +my $mech = FixMyStreet::TestMech->new; + +my $body = $mech->create_body_ok(2482, 'Bromley Council'); +my $user = $mech->create_user_ok('test@example.net', name => 'Normal User'); +my $staff_user = $mech->create_user_ok('staff@example.org', from_body => $body, name => 'Staff User'); +$staff_user->user_body_permissions->create({ body => $body, permission_type => 'contribute_as_another_user' }); +$staff_user->user_body_permissions->create({ body => $body, permission_type => 'report_mark_private' }); + +sub create_contact { + my ($params, @extra) = @_; + my $contact = $mech->create_contact_ok(body => $body, %$params); + $contact->set_extra_metadata(group => ['Waste']); + $contact->set_extra_fields( + { code => 'uprn', required => 1, automated => 'hidden_field' }, + { code => 'property_id', required => 1, automated => 'hidden_field' }, + { code => 'service_id', required => 0, automated => 'hidden_field' }, + @extra, + ); + $contact->update; +} + +create_contact({ category => 'Report missed collection', email => 'missed@example.org' }); +create_contact({ category => 'Request new container', email => 'request@example.org' }, + { code => 'Quantity', required => 1, automated => 'hidden_field' }, + { code => 'Container_Type', required => 1, automated => 'hidden_field' }, +); +create_contact({ category => 'General enquiry', email => 'general@example.org' }, + { code => 'Notes', description => 'Notes', required => 1, datatype => 'text' }); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => ['bromley', 'fixmystreet'], + COBRAND_FEATURES => { echo => { bromley => { sample_data => 1 } }, waste => { bromley => 1 } }, + MAPIT_URL => 'http://mapit.uk/', +}, sub { + $mech->host('bromley.fixmystreet.com'); + subtest 'Missing address lookup' => sub { + $mech->get_ok('/waste'); + $mech->submit_form_ok({ with_fields => { postcode => 'BR1 1AA' } }); + $mech->submit_form_ok({ with_fields => { address => 'missing' } }); + $mech->content_contains('can’t find your address'); + }; + subtest 'Address lookup' => sub { + set_fixed_time('2020-05-28T17:00:00Z'); # After sample data collection + $mech->get_ok('/waste'); + $mech->submit_form_ok({ with_fields => { postcode => 'BR1 1AA' } }); + $mech->submit_form_ok({ with_fields => { address => '12345' } }); + $mech->content_contains('2 Example Street'); + $mech->content_contains('Food Waste'); + }; + subtest 'Thing already requested' => sub { + $mech->content_contains('A food waste collection has been reported as missed'); + $mech->content_contains('A paper & cardboard collection has been reported as missed'); # as part of service unit, not property + }; + subtest 'Report a missed bin' => sub { + $mech->content_contains('service-101', 'Can report, last collection was 27th'); + $mech->content_lacks('service-537', 'Cannot report, last collection was 27th but the service unit has a report'); + $mech->content_lacks('service-535', 'Cannot report, last collection was 20th'); + $mech->content_lacks('service-542', 'Cannot report, last collection was 18th'); + $mech->follow_link_ok({ text => 'Report a missed collection' }); + $mech->content_contains('service-101', 'Checkbox, last collection was 27th'); + $mech->content_lacks('service-537', 'No checkbox, last collection was 27th but the service unit has a report'); + $mech->content_lacks('service-535', 'No checkbox, last collection was 20th'); + $mech->content_lacks('service-542', 'No checkbox, last collection was 18th'); + $mech->submit_form_ok({ form_number => 2 }); + $mech->content_contains('Please specify what was missed'); + $mech->submit_form_ok({ with_fields => { 'service-101' => 1 } }); + $mech->submit_form_ok({ with_fields => { name => "Test" } }); + $mech->content_contains('Please enter your full name'); + $mech->content_contains('Please specify at least one of phone or email'); + $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => 'test@example.org' } }); + $mech->content_contains('Refuse collection'); + $mech->content_contains('Test McTest'); + $mech->content_contains('test@example.org'); + $mech->submit_form_ok({ form_number => 3 }); + $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => $user->email } }); + $mech->content_contains($user->email); + $mech->submit_form_ok({ with_fields => { process => 'summary' } }); + $mech->content_contains('Your report has been sent'); + FixMyStreet::Script::Reports::send(); + my @emails = $mech->get_email; + is $emails[0]->header('To'), '"Bromley Council" <missed@example.org>'; + is $emails[1]->header('To'), $user->email; + my $body = $mech->get_text_body_from_email($emails[1]); + like $body, qr/Your report to Bromley Council has been logged/; + + is $user->alerts->count, 1; + }; + subtest 'Check report visibility' => sub { + my $report = FixMyStreet::DB->resultset("Problem")->first; + my $res = $mech->get('/report/' . $report->id); + is $res->code, 403; + $mech->log_in_ok($user->email); + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('Provide an update'); + $report->update({ state => 'fixed - council' }); + $mech->log_in_ok($staff_user->email); + $mech->get_ok('/report/' . $report->id); + $mech->content_lacks('Provide an update'); + $mech->content_contains( '<a href="/waste/12345">See your bin collections</a>' ); + + $mech->host('www.fixmystreet.com'); + $res = $mech->get('/report/' . $report->id); + is $res->code, 404; + $mech->log_in_ok($user->email); + $res = $mech->get('/report/' . $report->id); + is $res->code, 404; + $mech->log_in_ok($staff_user->email); + $res = $mech->get('/report/' . $report->id); + is $res->code, 404; + $mech->host('bromley.fixmystreet.com'); + }; + subtest 'Request a new container' => sub { + $mech->get_ok('/waste/12345/request'); + $mech->submit_form_ok({ form_number => 2 }); + $mech->content_contains('Please specify what you need'); + $mech->submit_form_ok({ with_fields => { 'container-1' => 1 } }); + $mech->content_contains('Quantity field is required'); + $mech->submit_form_ok({ with_fields => { 'container-1' => 1, 'quantity-1' => 2 } }); + $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => $user->email } }); + $mech->content_contains('Green Box'); + $mech->content_contains('Test McTest'); + $mech->content_contains($user->email); + $mech->submit_form_ok({ with_fields => { process => 'summary' } }); + $mech->content_contains('Your request has been sent'); + my $report = FixMyStreet::DB->resultset("Problem")->search(undef, { order_by => { -desc => 'id' } })->first; + is $report->get_extra_field_value('uprn'), 1000000002; + is $report->get_extra_field_value('Quantity'), 2; + is $report->get_extra_field_value('Container_Type'), 1; + }; + subtest 'Thing already requested' => sub { + $mech->get_ok('/waste/12345'); + $mech->content_contains('A new paper & cardboard container request has been made'); + }; + subtest 'General enquiry, bad data' => sub { + $mech->get_ok('/waste/12345/enquiry'); + is $mech->uri->path, '/waste/12345'; + $mech->get_ok('/waste/12345/enquiry?category=Bad'); + is $mech->uri->path, '/waste/12345'; + $mech->get_ok('/waste/12345/enquiry?service=1'); + is $mech->uri->path, '/waste/12345'; + }; + subtest 'Checking calendar' => sub { + $mech->follow_link_ok({ text => 'Add to your calendar (.ics file)' }); + $mech->content_contains('BEGIN:VCALENDAR'); + my @events = split /BEGIN:VEVENT/, $mech->encoded_content; + shift @events; # Header + my $i = 0; + foreach (@events) { + $i++ if /DTSTART;VALUE=DATE:20200701/ && /SUMMARY:Refuse collection/; + $i++ if /DTSTART;VALUE=DATE:20200708/ && /SUMMARY:Paper & Cardboard/; + } + is $i, 2, 'Two events from the sample data in the calendar'; + }; + subtest 'General enquiry, on behalf of someone else' => sub { + $mech->log_in_ok($staff_user->email); + $mech->get_ok('/waste/12345/enquiry?category=General+enquiry&service_id=537'); + $mech->submit_form_ok({ with_fields => { extra_Notes => 'Some notes' } }); + $mech->submit_form_ok({ with_fields => { name => "Test McTest", email => $user->email } }); + $mech->content_contains('Some notes'); + $mech->content_contains('Test McTest'); + $mech->content_contains($user->email); + $mech->submit_form_ok({ with_fields => { process => 'summary' } }); + $mech->content_contains('Your enquiry has been sent'); + my $report = FixMyStreet::DB->resultset("Problem")->search(undef, { order_by => { -desc => 'id' } })->first; + is $report->get_extra_field_value('Notes'), 'Some notes'; + is $report->user->email, $user->email; + is $report->get_extra_metadata('contributed_by'), $staff_user->id; + }; +}; + +package SOAP::Result; +sub result { return $_[0]->{result}; } +sub new { my $c = shift; bless { @_ }, $c; } + +package main; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => 'bromley', + COBRAND_FEATURES => { echo => { bromley => { url => 'http://example.org' } }, waste => { bromley => 1 } }, +}, sub { + subtest 'Address lookup, mocking SOAP call' => sub { + my $integ = Test::MockModule->new('SOAP::Lite'); + $integ->mock(call => sub { + return SOAP::Result->new(result => { + PointInfo => [ + { Description => '1 Example Street', Id => '11345', SharedRef => { Value => { anyType => 1000000001 } } }, + { Description => '2 Example Street', Id => '12345', SharedRef => { Value => { anyType => 1000000002 } } }, + ], + }); + }); + + $mech->get_ok('/waste'); + $mech->submit_form_ok({ with_fields => { postcode => 'BR1 1AA' } }); + $mech->content_contains('2 Example Street'); + }; +}; + +done_testing; |