diff options
Diffstat (limited to 't/cobrand')
-rw-r--r-- | t/cobrand/bromley.t | 138 | ||||
-rw-r--r-- | t/cobrand/closest.t | 12 | ||||
-rw-r--r-- | t/cobrand/councils.t | 12 | ||||
-rw-r--r-- | t/cobrand/fixamingata.t | 121 | ||||
-rw-r--r-- | t/cobrand/form_extras.t | 72 | ||||
-rw-r--r-- | t/cobrand/form_extras/templates/report/new/after_photo.html | 12 | ||||
-rw-r--r-- | t/cobrand/get_body_sender.t | 42 | ||||
-rw-r--r-- | t/cobrand/get_council_sender.t | 30 | ||||
-rw-r--r-- | t/cobrand/hart.t | 16 | ||||
-rw-r--r-- | t/cobrand/loading.t | 111 | ||||
-rw-r--r-- | t/cobrand/oxfordshire.t | 73 | ||||
-rw-r--r-- | t/cobrand/restriction.t | 55 | ||||
-rw-r--r-- | t/cobrand/two_tier.t | 27 | ||||
-rw-r--r-- | t/cobrand/zurich-logo_portal.x.jpg | bin | 0 -> 365 bytes | |||
-rw-r--r-- | t/cobrand/zurich.t | 995 | ||||
-rw-r--r-- | t/cobrand/zurich_attachments.txt | 33 |
16 files changed, 1674 insertions, 75 deletions
diff --git a/t/cobrand/bromley.t b/t/cobrand/bromley.t new file mode 100644 index 000000000..a7cc563dc --- /dev/null +++ b/t/cobrand/bromley.t @@ -0,0 +1,138 @@ +use strict; +use warnings; +use Test::More; + +use CGI::Simple; +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +# Create test data +my $user = $mech->create_user_ok( 'bromley@example.com' ); +my $body = $mech->create_body_ok( 2482, 'Bromley Council', id => 2482 ); +my $contact = $mech->create_contact_ok( + body_id => $body->id, + category => 'Other', + email => 'LIGHT', +); +$contact->set_extra_metadata(id_field => 'service_request_id_ext'); +$contact->set_extra_fields( + { code => 'easting', datatype => 'number', }, + { code => 'northing', datatype => 'number', }, + { code => 'service_request_id_ext', datatype => 'number', }, +); +$contact->update; + +my @reports = $mech->create_problems_for_body( 1, $body->id, 'Test', { + cobrand => 'bromley', + user => $user, +}); +my $report = $reports[0]; + +for my $update ('in progress', 'unable to fix') { + FixMyStreet::DB->resultset('Comment')->find_or_create( { + problem_state => $update, + problem_id => $report->id, + user_id => $user->id, + name => 'User', + mark_fixed => 'f', + text => "This update marks it as $update", + state => 'confirmed', + confirmed => 'now()', + anonymous => 'f', + } ); +} + +# Test Bromley special casing of 'unable to fix' +$mech->get_ok( '/report/' . $report->id ); +$mech->content_contains( 'marks it as in progress' ); +$mech->content_contains( 'marked as in progress' ); +$mech->content_contains( 'marks it as unable to fix' ); +$mech->content_contains( 'marked as no further action' ); + +subtest 'testing special Open311 behaviour', sub { + $report->set_extra_fields(); + $report->update; + $body->update( { send_method => 'Open311', endpoint => 'http://bromley.endpoint.example.com', jurisdiction => 'FMS', api_key => 'test' } ); + my $test_data; + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => [ 'fixmystreet', 'bromley' ], + }, sub { + $test_data = FixMyStreet::DB->resultset('Problem')->send_reports(); + }; + $report->discard_changes; + ok $report->whensent, 'Report marked as sent'; + is $report->send_method_used, 'Open311', 'Report sent via Open311'; + is $report->external_id, 248, 'Report has right external ID'; + + my $req = $test_data->{test_req_used}; + my $c = CGI::Simple->new($req->content); + is $c->param('attribute[easting]'), 529025, 'Request had easting'; + is $c->param('attribute[northing]'), 179716, 'Request had northing'; + is $c->param('attribute[service_request_id_ext]'), $report->id, 'Request had correct ID'; + is $c->param('jurisdiction_id'), 'FMS', 'Request had correct jurisdiction'; +}; + +for my $test ( + { + cobrand => 'bromley', + fields => { + submit_update => 1, + rznvy => 'unregistered@example.com', + update => 'Update from an unregistered user', + add_alert => undef, + first_name => 'Unreg', + last_name => 'User', + fms_extra_title => 'DR', + may_show_name => undef, + } + }, + { + cobrand => 'fixmystreet', + fields => { + submit_update => 1, + rznvy => 'unregistered@example.com', + update => 'Update from an unregistered user', + add_alert => undef, + name => 'Unreg User', + fms_extra_title => 'DR', + may_show_name => undef, + } + }, +) +{ + subtest 'check Bromley update emails via ' . $test->{cobrand} . ' cobrand are correct' => sub { + $mech->log_out_ok(); + $mech->clear_emails_ok(); + + my $report_id = $report->id; + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ $test->{cobrand} ], + }, sub { + $mech->get_ok("/report/$report_id"); + $mech->submit_form_ok( + { + with_fields => $test->{fields} + }, + 'submit update' + ); + }; + $mech->content_contains('Nearly done! Now check your email'); + + my $body = $mech->get_text_body_from_email; + like $body, qr/This update will be sent to Bromley Council/i, "Email indicates problem will be sent to Bromley"; + unlike $body, qr/Note that we do not send updates to/i, "Email does not say updates aren't sent to Bromley"; + + my $unreg_user = FixMyStreet::App->model( 'DB::User' )->find( { email => 'unregistered@example.com' } ); + + ok $unreg_user, 'found user'; + + $mech->delete_user( $unreg_user ); + }; +} + +# Clean up +$mech->delete_user($user); +$mech->delete_body($body); +done_testing(); diff --git a/t/cobrand/closest.t b/t/cobrand/closest.t index 464c95e67..43b36f608 100644 --- a/t/cobrand/closest.t +++ b/t/cobrand/closest.t @@ -4,7 +4,10 @@ use warnings; use Test::More; use mySociety::Locale; -use FixMyStreet::App; +use FixMyStreet::DB; +use FixMyStreet::TestMech; + +my $mech = FixMyStreet::TestMech->new; use_ok 'FixMyStreet::Cobrand'; @@ -13,7 +16,7 @@ mySociety::Locale::gettext_domain( 'FixMyStreet' ); my $c = FixMyStreet::Cobrand::UK->new(); my $user = - FixMyStreet::App->model('DB::User') + FixMyStreet::DB->resultset('User') ->find_or_create( { email => 'test@example.com', name => 'Test User' } ); ok $user, "created test user"; @@ -26,10 +29,10 @@ my $dt = DateTime->new( second => 23 ); -my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( +my $report = FixMyStreet::DB->resultset('Problem')->find_or_create( { postcode => 'SW1A 1AA', - council => '2504', + bodies_str => '2504', areas => ',105255,11806,11828,2247,2504,', category => 'Other', title => 'Test 2', @@ -81,4 +84,5 @@ SKIP: { } # all done +$mech->delete_user( $user ); done_testing(); diff --git a/t/cobrand/councils.t b/t/cobrand/councils.t index 8fb10cfbe..0e8b71f04 100644 --- a/t/cobrand/councils.t +++ b/t/cobrand/councils.t @@ -5,14 +5,14 @@ use Test::More; use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; -foreach my $council (qw/southampton reading bromley/) { - SKIP: { - skip( "Need '$council' in ALLOWED_COBRANDS config", 3 ) - unless FixMyStreet::Cobrand->exists($council); +foreach my $council (qw/oxfordshire bromley/) { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ $council ], + }, sub { ok $mech->host("$council.fixmystreet.com"), "change host to $council"; $mech->get_ok('/'); - $mech->content_like( qr/$council/i ); - } + $mech->content_like( qr/\u$council/ ); + }; } done_testing(); diff --git a/t/cobrand/fixamingata.t b/t/cobrand/fixamingata.t new file mode 100644 index 000000000..d6a1c2b34 --- /dev/null +++ b/t/cobrand/fixamingata.t @@ -0,0 +1,121 @@ +use strict; +use warnings; +use Test::More; +use Test::MockModule; + +BEGIN { + use FixMyStreet; + FixMyStreet->test_mode(1); +} + +use mySociety::Locale; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +# Closest road reverse geocode mock +my $resolver = Test::MockModule->new('LWP::Simple'); +$resolver->mock('get', sub($) { "<result></result>" }); + +# Front page test + +ok $mech->host("www.fixamingata.se"), "change host to FixaMinGata"; +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fixamingata' ], +}, sub { + $mech->get_ok('/'); +}; +$mech->content_like( qr/FixaMinGata/ ); + +my $body = $mech->create_body_ok( 1, 'Body' ); +$mech->create_contact_ok( + body => $body, + category => "Other", + email => "other\@example.org", +); + +my @reports = $mech->create_problems_for_body( 1, $body->id, 'Test', { + cobrand => 'fixamingata', + latitude => '55.605833', + longitude => '13.035833', +}); +my $report = $reports[0]; +$mech->get_ok( '/report/' . $report->id ); + +$mech->email_count_is(0); +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fixamingata' ], +}, sub { + FixMyStreet::DB->resultset('Problem')->send_reports(); +}; +my $email = $mech->get_email; +my $plain = $mech->get_text_body_from_email($email, 1); +like $plain->header('Content-Type'), qr/utf-8/, 'encoding looks okay'; +like $email->header('Subject'), qr/Ny rapport: Test Test/, 'subject looks okay'; +like $email->header('To'), qr/other\@example.org/, 'to line looks correct'; +like $plain->body_str, qr/V\xe4nligen,/, 'signature looks correct'; +$mech->clear_emails_ok; + +my $user = + FixMyStreet::DB->resultset('User') + ->find_or_create( { email => 'test@example.com', name => 'Test User' } ); +ok $user, "created test user"; + +my $user2 = + FixMyStreet::DB->resultset('User') + ->find_or_create( { email => 'commenter@example.com', name => 'Commenter' } ); +ok $user2, "created comment user"; + +my $comment = FixMyStreet::DB->resultset('Comment')->find_or_create({ + problem_id => $report->id, + user_id => $user2->id, + name => 'Other User', + mark_fixed => 'false', + text => 'This is some update text', + state => 'confirmed', + anonymous => 'f', +}); +$comment->confirmed( \"current_timestamp - '3 days'::interval" ); +$comment->update; + +my $alert = FixMyStreet::DB->resultset('Alert')->find_or_create({ + user => $user, + parameter => $report->id, + alert_type => 'new_updates', + whensubscribed => '2014-01-01 10:00:00', + confirmed => 1, + cobrand => 'fixamingata', +}); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fixamingata' ], +}, sub { + FixMyStreet::DB->resultset('AlertType')->email_alerts(); +}; + +$email = $mech->get_email; +$plain = $mech->get_text_body_from_email($email, 1); +like $plain->header('Content-Type'), qr/utf-8/, 'encoding looks okay'; +like $plain->body_str, qr/V\xe4nligen,/, 'signature looks correct'; +$mech->clear_emails_ok; + +subtest "Test ajax decimal points" => sub { + # The following line is so we are definitely not in Swedish before + # requesting the page, so that the code performs a full switch to Swedish + mySociety::Locale::push('en-gb'); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fixamingata' ], + MAPIT_URL => 'http://mapit.uk/' + }, sub { + $mech->get_ok('/ajax/lookup_location?term=12345'); + # We want an actual decimal point in a JSON response... + $mech->content_contains('51.5'); + }; +}; + +END { + $mech->delete_body($body); + ok $mech->host("www.fixmystreet.com"), "change host back"; + done_testing(); +} diff --git a/t/cobrand/form_extras.t b/t/cobrand/form_extras.t new file mode 100644 index 000000000..22a86ef21 --- /dev/null +++ b/t/cobrand/form_extras.t @@ -0,0 +1,72 @@ +use strict; +use warnings; + +package FixMyStreet::Cobrand::Tester; +use parent 'FixMyStreet::Cobrand::FixMyStreet'; + +sub report_form_extras { + ( { name => 'address', required => 1 }, { name => 'passport', required => 0 } ) +} + +# To allow a testing template override +sub path_to_web_templates { + my $self = shift; + return [ + FixMyStreet->path_to( 't/cobrand/form_extras/templates' )->stringify, + ]; +} + +package main; + +use Test::More; +use FixMyStreet::TestMech; + +# disable info logs for this test run +FixMyStreet::App->log->disable('info'); +END { FixMyStreet::App->log->enable('info'); } + +my $mech = FixMyStreet::TestMech->new; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { tester => '.' } ], + MAPIT_URL => 'http://mapit.uk/', +}, 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_register', + with_fields => { + title => 'Test Report', + detail => 'Test report details.', + name => 'Joe Bloggs', + may_show_name => '1', + email => 'test-1@example.com', + passport => '123456', + password_register => '', + } + }, + "submit details without address, with passport", + ); + $mech->content_like(qr{<label for="form_address">Address</label>\s*<p class='form-error'>This information is required</p>}, 'Address is required'); + $mech->content_contains('value="123456" name="passport"', 'Passport number reshown'); + + $mech->submit_form_ok( { + button => 'submit_register', + with_fields => { + address => 'My address', + } + }, + "submit details, now with address", + ); + $mech->content_contains('Now check your email'); + + my $problem = FixMyStreet::DB->resultset('Problem')->search({}, { order_by => '-id' })->first; + is $problem->get_extra_metadata('address'), 'My address', 'Address is stored'; + is $problem->get_extra_metadata('passport'), '123456', 'Passport number is stored'; +}; + +END { + $mech->delete_problems_for_body(undef); + done_testing(); +} diff --git a/t/cobrand/form_extras/templates/report/new/after_photo.html b/t/cobrand/form_extras/templates/report/new/after_photo.html new file mode 100644 index 000000000..89ab0b20c --- /dev/null +++ b/t/cobrand/form_extras/templates/report/new/after_photo.html @@ -0,0 +1,12 @@ +<label for="form_address">Address</label> +[% IF field_errors.address %] +<p class='form-error'>[% field_errors.address %]</p> +[% END %] +<input class="form-control" type="text" value="[% report.get_extra_metadata('address') | html %]" name="address" id="form_address" required> + +<label for="form_passport">Passport number (optional)</label> +[% IF field_errors.passport %] +<p class='form-error'>[% field_errors.passport %]</p> +[% END %] +<input class="form-control" type="text" value="[% report.get_extra_metadata('passport') | html %]" name="passport" id="form_passport"> + diff --git a/t/cobrand/get_body_sender.t b/t/cobrand/get_body_sender.t new file mode 100644 index 000000000..fbdfbffa7 --- /dev/null +++ b/t/cobrand/get_body_sender.t @@ -0,0 +1,42 @@ +use strict; +use warnings; + +use Test::More; + +use mySociety::Locale; +use FixMyStreet::DB; + +use_ok 'FixMyStreet::Cobrand'; + +mySociety::Locale::gettext_domain( 'FixMyStreet' ); + +my $c = FixMyStreet::Cobrand::FixMyStreet->new(); + +FixMyStreet::DB->resultset('BodyArea')->search( { body_id => 1000 } )->delete; +FixMyStreet::DB->resultset('Body')->search( { name => 'Body of a Thousand' } )->delete; + +my $body = FixMyStreet::DB->resultset('Body')->find_or_create({ + id => 1000, + name => 'Body of a Thousand', +}); +my $body_area = $body->body_areas->find_or_create({ area_id => 1000 }); + +FixMyStreet::override_config { + MAPIT_TYPES => [ 'LBO' ], + MAPIT_URL => 'http://mapit.mysociety.org/', +}, sub { + is_deeply $c->get_body_sender( $body ), { method => 'Email', contact => undef }, 'defaults to email'; + $body_area->update({ area_id => 2481 }); # Croydon LBO + is_deeply $c->get_body_sender( $body ), { method => 'Email', contact => undef }, 'still email if London borough'; +}; + +$body->send_method( 'TestMethod' ); +is $c->get_body_sender( $body )->{ method }, 'TestMethod', 'uses send_method in preference to London'; + +$body_area->update({ area_id => 1000 }); # Nothing +is $c->get_body_sender( $body )->{ method }, 'TestMethod', 'uses send_method in preference to Email'; + +$body_area->delete; +$body->delete; + +done_testing(); diff --git a/t/cobrand/get_council_sender.t b/t/cobrand/get_council_sender.t deleted file mode 100644 index c05864d8a..000000000 --- a/t/cobrand/get_council_sender.t +++ /dev/null @@ -1,30 +0,0 @@ -use strict; -use warnings; - -use Test::More; - -use mySociety::Locale; -use FixMyStreet::App; - -use_ok 'FixMyStreet::Cobrand'; - -mySociety::Locale::gettext_domain( 'FixMyStreet' ); - -my $c = FixMyStreet::Cobrand::FixMyStreet->new(); - - -is_deeply $c->get_council_sender( '1000', { type => 'DIS' } ), { method => 'Email' }, 'defaults to email'; -is_deeply $c->get_council_sender( '1000', { type => 'LBO' } ), { method=> 'London' }, 'returns london report it if London borough'; - -my $conf = FixMyStreet::App->model('DB::Body')->find_or_create( - area_id => 1000, - endpoint => '', - send_method => 'TestMethod' -); - -is $c->get_council_sender( '1000', { type => 'LBO' } )->{ method }, 'TestMethod', 'uses send_method in preference to London'; -is $c->get_council_sender( '1000', { type => 'DIS' } )->{ method }, 'TestMethod', 'uses send_method in preference to Email'; - -$conf->delete; - -done_testing(); diff --git a/t/cobrand/hart.t b/t/cobrand/hart.t new file mode 100644 index 000000000..f4a2473eb --- /dev/null +++ b/t/cobrand/hart.t @@ -0,0 +1,16 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'hart' ], +}, sub { + ok $mech->host("hart.fixmystreet.com"), "change host to hart"; + $mech->get_ok('/'); + $mech->content_like( qr/Hart\b/ ); +}; + +done_testing(); diff --git a/t/cobrand/loading.t b/t/cobrand/loading.t index bd83da07f..b4738fb63 100644 --- a/t/cobrand/loading.t +++ b/t/cobrand/loading.t @@ -9,61 +9,102 @@ use FixMyStreet; use_ok 'FixMyStreet::Cobrand'; # check that the allowed cobrands is correctly loaded from config -{ +sub check_allowed_cobrands { + my $should = shift; + $should = [ map { { moniker => $_, host => $_ } } @$should ]; my $allowed = FixMyStreet::Cobrand->get_allowed_cobrands; - ok $allowed, "got the allowed_cobrands"; + ok $allowed, "got the allowed_cobrands"; isa_ok $allowed, "ARRAY"; - cmp_ok scalar @$allowed, '>', 1, "got more than one"; + is_deeply $allowed, $should, "allowed_cobrands matched"; } -# fake the allowed cobrands for testing -my $override = Sub::Override->new( # - 'FixMyStreet::Cobrand::_get_allowed_cobrands' => - sub { return ['emptyhomes'] } -); -is_deeply FixMyStreet::Cobrand->get_allowed_cobrands, [ { moniker => 'emptyhomes', host => 'emptyhomes' } ], - 'overidden get_allowed_cobrands'; +FixMyStreet::override_config { ALLOWED_COBRANDS => 'fixmyhouse' }, + sub { check_allowed_cobrands([ 'fixmyhouse' ]); }; +FixMyStreet::override_config { ALLOWED_COBRANDS => [ 'fixmyhouse' ] }, + sub { check_allowed_cobrands([ 'fixmyhouse' ]); }; +FixMyStreet::override_config { ALLOWED_COBRANDS => [ 'fixmyhouse', 'fixmyshed' ] }, + sub { check_allowed_cobrands([ 'fixmyhouse', 'fixmyshed' ]); }; sub run_host_tests { my %host_tests = @_; for my $host ( sort keys %host_tests ) { - is FixMyStreet::Cobrand->get_class_for_host($host), - "FixMyStreet::Cobrand::$host_tests{$host}", - "does $host -> F::C::$host_tests{$host}"; + # get the cobrand class by host + my $cobrand = FixMyStreet::Cobrand->get_class_for_host($host); + my $test_class = $host_tests{$host}; + my $test_moniker = lc $test_class; + is $cobrand, "FixMyStreet::Cobrand::$test_class", "does $host -> F::C::$test_class"; + my $c = $cobrand->new(); + is $c->moniker, $test_moniker; } } -# get the cobrand class by host -run_host_tests( - 'www.fixmystreet.com' => 'Default', - 'reportemptyhomes.com' => 'EmptyHomes', - 'barnet.fixmystreet.com' => 'Default', # not in the allowed_cobrands list - 'some.odd.site.com' => 'Default', -); +# Only one cobrand, always use it +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fixmystreet' ], +}, sub { + run_host_tests( + 'www.fixmystreet.com' => 'FixMyStreet', + 'fiksgatami.example.org' => 'FixMyStreet', + 'oxfordshire.fixmystreet.com' => 'FixMyStreet', + 'some.odd.site.com' => 'FixMyStreet', + ); +}; -# now enable barnet too and check that it works -$override->replace( # - 'FixMyStreet::Cobrand::_get_allowed_cobrands' => - sub { return [ 'emptyhomes', 'barnet' ] } -); +# Only one cobrand, no .pm file, should still work +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'nopmfile' ], +}, sub { + run_host_tests( + 'www.fixmystreet.com' => 'nopmfile', + 'some.odd.site.com' => 'nopmfile', + ); +}; -# get the cobrand class by host -run_host_tests( - 'www.fixmystreet.com' => 'Default', - 'reportemptyhomes.com' => 'EmptyHomes', - 'barnet.fixmystreet.com' => 'Barnet', # found now it is in allowed_cobrands - 'some.odd.site.com' => 'Default', -); +# Couple of cobrands, hostname checking and default fallback +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fiksgatami', 'fixmystreet' ], +}, sub { + run_host_tests( + 'www.fixmystreet.com' => 'FixMyStreet', + 'fiksgatami.example.org' => 'FiksGataMi', + 'oxfordshire.fixmystreet.com' => 'FixMyStreet', # not in the allowed_cobrands list + 'some.odd.site.com' => 'Default', + ); +}; + +# now enable oxfordshire too and check that it works +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fiksgatami', 'oxfordshire', 'fixmystreet' ], +}, sub { + run_host_tests( + 'www.fixmystreet.com' => 'FixMyStreet', + 'fiksgatami.example.org' => 'FiksGataMi', + 'oxfordshire.fixmystreet.com' => 'Oxfordshire', # found now it is in allowed_cobrands + 'some.odd.site.com' => 'Default', + ); +}; + +# And a check with some regex matching +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { 'fixmystreet' => 'example' }, 'oxfordshire', { 'testing' => 'fixmystreet' } ], +}, sub { + run_host_tests( + 'www.fixmystreet.com' => 'testing', + 'fiksgatami.example.org' => 'FixMyStreet', + 'oxfordshire.fixmystreet.com' => 'Oxfordshire', + 'some.odd.site.com' => 'Default', + ); +}; # check that the moniker works as expected both on class and object. -is FixMyStreet::Cobrand::EmptyHomes->moniker, 'emptyhomes', +is FixMyStreet::Cobrand::FiksGataMi->moniker, 'fiksgatami', 'class->moniker works'; -is FixMyStreet::Cobrand::EmptyHomes->new->moniker, 'emptyhomes', +is FixMyStreet::Cobrand::FiksGataMi->new->moniker, 'fiksgatami', 'object->moniker works'; # check is_default works ok FixMyStreet::Cobrand::Default->is_default, '::Default is default'; -ok !FixMyStreet::Cobrand::EmptyHomes->is_default, '::Emptyhomes is not default'; +ok !FixMyStreet::Cobrand::FiksGataMi->is_default, '::FiksGataMi is not default'; # all done done_testing(); diff --git a/t/cobrand/oxfordshire.t b/t/cobrand/oxfordshire.t new file mode 100644 index 000000000..b0fad3b56 --- /dev/null +++ b/t/cobrand/oxfordshire.t @@ -0,0 +1,73 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +subtest 'check /ajax defaults to open reports only' => sub { + my $categories = [ 'Bridges', 'Fences', 'Manhole' ]; + my $params = { + postcode => 'OX28 4DS', + latitude => 51.7847208192, + longitude => -1.49445264029, + }; + my $bbox = ($params->{longitude} - 0.01) . ',' . ($params->{latitude} - 0.01) + . ',' . ($params->{longitude} + 0.01) . ',' . ($params->{latitude} + 0.01); + + # Create one open and one fixed report in each category + foreach my $category ( @$categories ) { + foreach my $state ( 'confirmed', 'fixed' ) { + my %report_params = ( + %$params, + category => $category, + state => $state, + ); + $mech->create_problems_for_body( 1, 2237, 'Around page', \%report_params ); + } + } + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { 'oxfordshire' => '.' } ], + MAPIT_URL => 'http://mapit.mysociety.org/', + }, sub { + my $json = $mech->get_ok_json( '/ajax?status=all&bbox=' . $bbox ); + my $pins = $json->{pins}; + is scalar @$pins, 6, 'correct number of reports created'; + + $json = $mech->get_ok_json( '/ajax?bbox=' . $bbox ); + $pins = $json->{pins}; + is scalar @$pins, 3, 'correct number of reports returned with no filters'; + + $json = $mech->get_ok_json( '/ajax?filter_category=Fences&bbox=' . $bbox ); + $pins = $json->{pins}; + is scalar @$pins, 1, 'only one Fences report by default'; + } +}; + +my $superuser = $mech->create_user_ok('superuser@example.com', name => 'Super User', is_superuser => 1); + +subtest 'Exor RDI download appears on Oxfordshire cobrand admin' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { 'oxfordshire' => '.' } ], + }, sub { + $mech->log_in_ok( $superuser->email ); + $mech->get_ok('/admin'); + $mech->content_contains("Download Exor RDI"); + } +}; + +subtest 'Exor RDI download doesn’t appear outside of Oxfordshire cobrand admin' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { 'fixmystreet' => '.' } ], + }, sub { + $mech->log_in_ok( $superuser->email ); + $mech->get_ok('/admin'); + $mech->content_lacks("Download Exor RDI"); + } +}; + +# Clean up +$mech->delete_user( $superuser ); +$mech->delete_problems_for_body( 2237 ); +done_testing(); diff --git a/t/cobrand/restriction.t b/t/cobrand/restriction.t new file mode 100644 index 000000000..873a396b7 --- /dev/null +++ b/t/cobrand/restriction.t @@ -0,0 +1,55 @@ +use strict; +use warnings; + +package FixMyStreet::Cobrand::Tester; + +use parent 'FixMyStreet::Cobrand::Default'; + +sub problems_restriction { + my ($self, $rs) = @_; + return $rs->search({ cobrand => 'tester' }); +} + +sub updates_restriction { + my ($self, $rs) = @_; + return $rs->search({ 'problem.cobrand' => 'tester' }, { join => 'problem' }); +} + +package main; + +use Test::More; +use FixMyStreet::TestMech; + +my $c = FixMyStreet::App->new; +my $cobrand = FixMyStreet::Cobrand::Tester->new({c => $c}); +$c->stash->{cobrand} = $cobrand; + +my $mech = FixMyStreet::TestMech->new; + +my ($prob1) = $mech->create_problems_for_body(1, 1234, 'Title'); +my ($prob2) = $mech->create_problems_for_body(1, 1234, 'Title', { cobrand => 'tester' }); +$mech->create_problems_for_body(1, 1234, 'Title', { latitude => 0, longitude => 0 }); +$mech->create_problems_for_body(1, 1234, 'Title', { cobrand => 'tester', latitude => 0, longitude => 0 }); + +for (1..2) { + $c->model('DB::Comment')->create({ + problem_id => $_ == 1 ? $prob1->id : $prob2->id, + user_id => $prob2->user_id, + name => 'User', + mark_fixed => 'false', + text => 'This is some update text', + state => 'confirmed', + cobrand => 'tester', + anonymous => 'f', + }); +} + +is($c->model('DB::Problem')->count, 4, 'Four reports in database'); +is($cobrand->problems->count, 2, 'Two reports in the right cobrand'); +is($cobrand->updates->count, 1, 'One update in the right cobrand'); + +my $nearby = $c->model('DB::Nearby')->nearby($c, 5, [], 10, 0.003, 0.004); +is(@$nearby, 1, 'One report close to the origin point'); + +$mech->delete_problems_for_body(1234); +done_testing(); diff --git a/t/cobrand/two_tier.t b/t/cobrand/two_tier.t new file mode 100644 index 000000000..97bbccc01 --- /dev/null +++ b/t/cobrand/two_tier.t @@ -0,0 +1,27 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet; +use FixMyStreet::Cobrand; + +my @cobrands = ( + [ hart => 2333 ], + [ oxfordshire => 2237 ], + [ stevenage => 2347 ], + [ warwickshire => 2243 ], +); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ map $_->[0], @cobrands ], +}, sub { + + for my $c (@cobrands) { + my ($m, $id) = @$c; + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($m); + my $council_id = $cobrand->council_id; + is $council_id, $id, "council_id for $m"; + } +}; + +done_testing; diff --git a/t/cobrand/zurich-logo_portal.x.jpg b/t/cobrand/zurich-logo_portal.x.jpg Binary files differnew file mode 100644 index 000000000..c0cfef240 --- /dev/null +++ b/t/cobrand/zurich-logo_portal.x.jpg diff --git a/t/cobrand/zurich.t b/t/cobrand/zurich.t new file mode 100644 index 000000000..0a84d2d03 --- /dev/null +++ b/t/cobrand/zurich.t @@ -0,0 +1,995 @@ +# TODO +# Overdue alerts + +use strict; +use warnings; +use DateTime; +use Email::MIME; +use LWP::Protocol::PSGI; +use Test::More; +use Test::LongString; +use Path::Tiny; +use t::Mock::MapItZurich; + +# Check that you have the required locale installed - the following +# should return a line with de_CH.utf8 in. If not install that locale. +# +# locale -a | grep de_CH +# +# To generate the translations use: +# +# commonlib/bin/gettext-makemo FixMyStreet + +use FixMyStreet; +my $cobrand = FixMyStreet::Cobrand::Zurich->new(); + +my $sample_file = path(__FILE__)->parent->parent->child("app/controller/sample.jpg"); +ok $sample_file->exists, "sample file $sample_file exists"; +my $sample_photo = $sample_file->slurp_raw; + +# This is a helper method that will send the reports but with the config +# correctly set - notably STAGING_FLAGS send_reports needs to be true, and +# zurich must be allowed cobrand if we want to be able to call cobrand +# methods on it. +sub send_reports_for_zurich { + FixMyStreet::override_config { + STAGING_FLAGS => { send_reports => 1 }, + ALLOWED_COBRANDS => ['zurich'] + }, sub { + # Actually send the report + FixMyStreet::DB->resultset('Problem')->send_reports('zurich'); + }; +} +sub reset_report_state { + my ($report, $created) = @_; + $report->discard_changes; + $report->unset_extra_metadata('moderated_overdue'); + $report->unset_extra_metadata('subdiv_overdue'); + $report->unset_extra_metadata('closed_overdue'); + $report->unset_extra_metadata('closure_status'); + $report->whensent(undef); + $report->state('unconfirmed'); + $report->created($created) if $created; + $report->update; +} + +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +# Front page test +ok $mech->host("zurich.example.com"), "change host to Zurich"; +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], +}, sub { + $mech->get_ok('/'); +}; +$mech->content_like( qr/zurich/i ); + +# Set up bodies +my $zurich = $mech->create_body_ok( 1, 'Zurich' ); +$zurich->parent( undef ); +$zurich->update; +my $division = $mech->create_body_ok( 2, 'Division 1' ); +$division->parent( $zurich->id ); +$division->send_method( 'Zurich' ); +$division->endpoint( 'division@example.org' ); +$division->update; +$division->body_areas->find_or_create({ area_id => 423017 }); +my $subdivision = $mech->create_body_ok( 3, 'Subdivision A' ); +$subdivision->parent( $division->id ); +$subdivision->send_method( 'Zurich' ); +$subdivision->endpoint( 'subdivision@example.org' ); +$subdivision->update; +my $external_body = $mech->create_body_ok( 4, 'External Body' ); +$external_body->send_method( 'Zurich' ); +$external_body->endpoint( 'external_body@example.net' ); +$external_body->update; + +sub get_export_rows_count { + my $mech = shift; + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $mech->get_ok( '/admin/stats?export=1' ); + }; + is $mech->res->code, 200, 'csv retrieved ok'; + is $mech->content_type, 'text/csv', 'content_type correct' and do { + my @lines = split /\n/, $mech->content; + return @lines - 1; + }; + return; +} + +my $EXISTING_REPORT_COUNT = 0; + +my $superuser; +subtest "set up superuser" => sub { + $superuser = $mech->log_in_ok( 'super@example.org' ); + # a user from body $zurich is a superuser, as $zurich has no parent id! + $superuser->update({ from_body => $zurich->id }); + $EXISTING_REPORT_COUNT = get_export_rows_count($mech); + $mech->log_out_ok; +}; + +my @reports = $mech->create_problems_for_body( 1, $division->id, 'Test', { + state => 'unconfirmed', + confirmed => undef, + cobrand => 'zurich', + photo => $sample_photo, + areas => ',423017,', +}); +my $report = $reports[0]; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', +}, sub { + $mech->get_ok( '/report/' . $report->id ); +}; +$mech->content_contains('Überprüfung ausstehend') + or die $mech->content; + +# Check logging in to deal with this report +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], +}, sub { + $mech->get_ok( '/admin' ); + is $mech->uri->path, '/auth', "got sent to the sign in page"; + + my $user = $mech->log_in_ok( 'dm1@example.org') ; + $user->from_body( undef ); + $user->update; + ok $mech->get( '/admin' ); + is $mech->res->code, 403, 'Got 403'; + $user->from_body( $division->id ); + $user->update; + + $mech->get_ok( '/admin' ); +}; +is $mech->uri->path, '/admin', "am logged in"; + +$mech->content_contains( 'report_edit/' . $report->id ); +$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); +$mech->content_contains( 'Erfasst' ); + +subtest "changing of categories" => sub { + # create a few categories (which are actually contacts) + foreach my $name ( qw/Cat1 Cat2/ ) { + $mech->create_contact_ok( + body => $division, + category => $name, + email => "$name\@example.org", + ); + } + + # full Categories dropdown is hidden for unconfirmed reports + $report->update({ state => 'confirmed' }); + + # put report into known category + my $original_category = $report->category; + $report->update({ category => 'Cat1' }); + is( $report->category, "Cat1", "Category set to Cat1" ); + + # get the latest comment + my $comments_rs = $report->comments->search({},{ order_by => { -desc => "created" } }); + ok ( !$comments_rs->first, "There are no comments yet" ); + + # change the category via the web interface + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { category => 'Cat2' } } ); + }; + + # check changes correctly saved + $report->discard_changes(); + is( $report->category, "Cat2", "Category changed to Cat2 as expected" ); + + # Check that a new comment has been created. + my $new_comment = $comments_rs->first(); + is( $new_comment->text, "Weitergeleitet von Cat1 an Cat2", "category change comment created" ); + + # restore report to original category. + $report->update({category => $original_category }); +}; + +sub get_moderated_count { + # my %date_params = ( ); + # my $moderated = FixMyStreet::DB->resultset('Problem')->search({ + # extra => { like => '%moderated_overdue,I1:0%' }, %date_params } )->count; + # return $moderated; + + # use a separate mech to avoid stomping on test state + my $mech = FixMyStreet::TestMech->new; + my $user = $mech->log_in_ok( 'super@example.org' ); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $mech->get( '/admin/stats' ); + }; + if ($mech->content =~/Innerhalb eines Arbeitstages moderiert: (\d+)/) { + return $1; + } + else { + fail sprintf "Could not get moderation results (%d)", $mech->status; + return undef; + } +} + +subtest "report_edit" => sub { + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + + reset_report_state($report); + ok ( ! $report->get_extra_metadata('moderated_overdue'), 'Report currently unmoderated' ); + is get_moderated_count(), 0; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Unbestätigt' ); # Unconfirmed email + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); + + $report->discard_changes(); + + $mech->content_contains('Aufgenommen'); + $mech->content_contains('Test Test'); + $mech->content_lacks('photo/' . $report->id . '.0.jpeg'); + $mech->email_count_is(0); + + $report->discard_changes; + + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Report now marked moderated' ); + is get_moderated_count(), 1; + + # Set state back to 10 days ago so that report is overdue + my $created = $report->created; + reset_report_state($report, $created->clone->subtract(days => 10)); + + is get_moderated_count(), 0; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); + + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 1, 'moderated_overdue set correctly when overdue' ); + is get_moderated_count(), 0, 'Moderated count not increased when overdue'; + + reset_report_state($report, $created); + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/report/' . $report->id ); + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking confirmed sets moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), undef, 'Marking confirmed does NOT set closed_overdue' ); + is get_moderated_count(), 1; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Still marked moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), undef, "Marking hidden doesn't set closed_overdue..." ); + is ( $report->state, 'planned', 'Marking hidden actually sets state to planned'); + is ( $report->get_extra_metadata('closure_status'), 'hidden', 'Marking hidden sets closure_status to hidden'); + is get_moderated_count(), 1, 'Check still counted moderated' + or diag $report->get_column('extra'); + + # publishing actually sets hidden + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $report->discard_changes; + + is ( $report->get_extra_metadata('closed_overdue'), 0, "Closing as hidden sets closed_overdue..." ); + is ( $report->state, 'hidden', 'Closing as hidden sets state to hidden'); + is ( $report->get_extra_metadata('closure_status'), undef, 'Closing as hidden unsets closure_status'); + + + reset_report_state($report); + is ( $report->get_extra_metadata('moderated_overdue'), undef, 'Sanity check' ); + is get_moderated_count(), 0; + + # Check that setting to 'hidden' also triggers moderation + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'hidden' } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); + + $report->discard_changes; + is ( $report->get_extra_metadata('moderated_overdue'), 0, 'Marking hidden from scratch sets moderated_overdue' ); + is ( $report->get_extra_metadata('closed_overdue'), 0, 'Marking hidden from scratch also set closed_overdue' ); + is get_moderated_count(), 1; + + is ($cobrand->get_or_check_overdue($report), 0, 'sanity check'); + $report->update({ created => $created->clone->subtract(days => 10) }); + is ($cobrand->get_or_check_overdue($report), 0, 'overdue call not increased'); + + reset_report_state($report, $created); + } +}; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', +}, sub { + # Photo publishing + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed', publish_photo => 1 } } ); + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('photo/' . $report->id . '.0.jpeg'); + + # Internal notes + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { new_internal_note => 'Initial internal note.' } } ); + $mech->submit_form_ok( { with_fields => { new_internal_note => 'Another internal note.' } } ); + $mech->content_contains( 'Initial internal note.' ); + $mech->content_contains( 'Another internal note.' ); + + # Original description + $mech->submit_form_ok( { with_fields => { detail => 'Edited details text.' } } ); + $mech->content_contains( 'Edited details text.' ); + $mech->content_contains( 'Originaltext: “Test Test 1 for ' . $division->id . ' Detail”' ); + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { body_subdivision => $subdivision->id } } ); + + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('In Bearbeitung'); + $mech->content_contains('Test Test'); +}; + +send_reports_for_zurich(); +my $email = $mech->get_email; +like $email->header('Subject'), qr/Neue Meldung/, 'subject looks okay'; +like $email->header('To'), qr/subdivision\@example.org/, 'to line looks correct'; +$mech->clear_emails_ok; + +$mech->log_out_ok; + +subtest 'SDM' => sub { + my $user = $mech->log_in_ok( 'sdm1@example.org') ; + $user->update({ from_body => undef }); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + ok $mech->get( '/admin' ); + }; + is $mech->res->code, 403, 'Got 403'; + $user->from_body( $subdivision->id ); + $user->update; + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $mech->get_ok( '/admin' ); + }; + is $mech->uri->path, '/admin', "am logged in"; + + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); + $mech->content_contains( 'In Bearbeitung' ); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Initial internal note' ); + + $mech->submit_form_ok( { with_fields => { status_update => 'This is an update.' } } ); + is $mech->uri->path, '/admin/report_edit/' . $report->id, "still on edit page"; + $mech->content_contains('This is an update'); + ok $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'no_more_updates' } ); + is $mech->uri->path, '/admin/summary', "redirected now finished with report."; + + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('In Bearbeitung'); + $mech->content_contains('Test Test'); + }; + + send_reports_for_zurich(); + $email = $mech->get_email; + like $email->header('Subject'), qr/Feedback/, 'subject looks okay'; + like $email->header('To'), qr/division\@example.org/, 'to line looks correct'; + $mech->clear_emails_ok; + + $report->discard_changes; + is $report->state, 'planned', 'Report now in planned state'; + + subtest 'send_back' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { form_number => 2, button => 'send_back' } ); + $report->discard_changes; + is $report->state, 'confirmed', 'Report sent back to confirmed state'; + is $report->bodies_str, $division->id, 'Report sent back to division'; + }; + }; + + subtest 'not contactable' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $report->update({ bodies_str => $subdivision->id, state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { button => 'not_contactable', form_number => 2 } ); + $report->discard_changes; + is $report->state, 'planned', 'Report sent back to Rueckmeldung ausstehend state'; + is $report->get_extra_metadata('closure_status'), 'partial', 'Report sent back to partial (not_contactable) state'; + is $report->bodies_str, $division->id, 'Report sent back to division'; + }; + }; + + $mech->log_out_ok; +}; + +my $user = $mech->log_in_ok( 'dm1@example.org') ; +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], +}, sub { + $mech->get_ok( '/admin' ); +}; + +reset_report_state($report); +$report->update({ state => 'planned' }); + +$mech->content_contains( 'report_edit/' . $report->id ); +$mech->content_contains( DateTime->now->strftime("%d.%m.%Y") ); + +# User confirms their email address +$report->set_extra_metadata(email_confirmed => 1); +$report->update; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', +}, sub { + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_lacks( 'Unbestätigt' ); # Confirmed email + $mech->submit_form_ok( { with_fields => { status_update => 'FINAL UPDATE' } } ); + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response' } ); + + $mech->get_ok( '/report/' . $report->id ); +}; +$mech->content_contains('Beantwortet'); +$mech->content_contains('Test Test'); +$mech->content_contains('FINAL UPDATE'); + +$email = $mech->get_email; +like $email->header('To'), qr/test\@example.com/, 'to line looks correct'; +like $email->header('From'), qr/do-not-reply\@example.org/, 'from line looks correct'; +like $email->body, qr/FINAL UPDATE/, 'body looks correct'; +$mech->clear_emails_ok; + +# Assign planned (via confirmed), don't confirm email +@reports = $mech->create_problems_for_body( 1, $division->id, 'Second', { + state => 'unconfirmed', + confirmed => undef, + cobrand => 'zurich', + photo => $sample_photo, + areas => ',423017,', +}); +$report = $reports[0]; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', +}, sub { + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'confirmed' } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->submit_form_ok( { with_fields => { state => 'planned' } } ); + $mech->get_ok( '/report/' . $report->id ); +}; +$mech->content_contains('In Bearbeitung'); +$mech->content_contains('Second Test'); + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', +}, sub { + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_contains( 'Unbestätigt' ); + $report->discard_changes; + $mech->form_with_fields( 'status_update' ); + $mech->submit_form_ok( { button => 'publish_response', with_fields => { status_update => 'FINAL UPDATE' } } ); + + $mech->get_ok( '/report/' . $report->id ); +}; +$mech->content_contains('Beantwortet'); +$mech->content_contains('Second Test'); +$mech->content_contains('FINAL UPDATE'); + +$mech->email_count_is(0); + +# Report assigned to third party + +@reports = $mech->create_problems_for_body( 1, $division->id, 'Third', { + state => 'unconfirmed', + confirmed => undef, + cobrand => 'zurich', + photo => $sample_photo, + areas => ',423017,', +}); +$report = $reports[0]; + +subtest "external report triggers email" => sub { + my $EXTERNAL_MESSAGE = 'Look Ma, no hands!'; + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + + # required to see body_external field + $report->state('planned'); + $report->set_extra_metadata('closure_status' => 'closed'); + # Set the public_response manually here because the default one will have line breaks that get escaped as HTML, causing the comparison to fail. + $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); + $report->update; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + } }); + $report->discard_changes; + $mech->get_ok( '/report/' . $report->id ); + }; + is ($report->state, 'closed', 'Report was closed correctly'); + $mech->content_contains('Extern') + or die $mech->content; + $mech->content_contains('Third Test'); + $mech->content_contains($report->get_extra_metadata('public_response')) or die $mech->content; + send_reports_for_zurich(); + $email = $mech->get_email; + like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay'; + like $email->header('To'), qr/external_body\@example.net/, 'to line looks correct'; + like $email->body, qr/External Body/, 'body has right name'; + like $email->body, qr/$EXTERNAL_MESSAGE/, 'external_message was passed on'; + unlike $email->body, qr/test\@example.com/, 'body does not contain email address'; + $mech->clear_emails_ok; + + subtest "Test third_personal boolean setting" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $mech->get_ok( '/admin' ); + # required to see body_external field + $report->state('planned'); + $report->set_extra_metadata('closure_status' => 'closed'); + $report->set_extra_metadata('public_response' => 'Freundliche Gruesse Ihre Stadt Zuerich'); + $report->update; + + is $mech->uri->path, '/admin', "am logged in"; + $mech->content_contains( 'report_edit/' . $report->id ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + third_personal => 1, + } }); + $mech->get_ok( '/report/' . $report->id ); + }; + $mech->content_contains('Extern'); + $mech->content_contains('Third Test'); + $mech->content_contains($report->get_extra_metadata('public_response')); + send_reports_for_zurich(); + $email = $mech->get_email; + like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay'; + like $email->header('To'), qr/external_body\@example.net/, 'to line looks correct'; + like $email->body, qr/External Body/, 'body has right name'; + like $email->body, qr/test\@example.com/, 'body does contain email address'; + $mech->clear_emails_ok; + }; + + subtest "Test external wish sending" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + # set as wish + $report->discard_changes; + $report->state('planned'); + $report->set_extra_metadata('closure_status' => 'investigating'); + $report->update; + is ($report->state, 'planned', 'Sanity check') or die; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + } }); + }; + send_reports_for_zurich(); + $email = $mech->get_email; + like $email->header('Subject'), qr/Weitergeleitete Meldung/, 'subject looks okay'; + like $email->header('To'), qr/external_body\@example.net/, 'to line looks correct'; + like $email->body, qr/External Body/, 'body has right name'; + like $email->body, qr/$EXTERNAL_MESSAGE/, 'external_message was passed on'; + like $email->body, qr/test\@example.com/, 'body contains email address'; + $mech->clear_emails_ok; + }; + + subtest "Closure email includes public response" => sub { + my $PUBLIC_RESPONSE = "This is the public response to your report. Freundliche Gruesse."; + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + # set as extern + reset_report_state($report); + $report->state('planned'); + $report->set_extra_metadata('closure_status' => 'closed'); + $report->set_extra_metadata('email_confirmed' => 1); + $report->unset_extra_metadata('public_response'); + $report->update; + is ($report->state, 'planned', 'Sanity check') or die; + + $mech->get_ok( '/admin/report_edit/' . $report->id ); + + $mech->form_with_fields( 'publish_response' ); + $mech->submit_form_ok( { + button => 'publish_response', + with_fields => { + body_external => $external_body->id, + external_message => $EXTERNAL_MESSAGE, + status_update => $PUBLIC_RESPONSE, + } }); + }; + $email = $mech->get_email; + my $report_id = $report->id; + like Encode::decode('MIME-Header', $email->header('Subject')), qr/Meldung #$report_id/, 'subject looks okay'; + like $email->header('To'), qr/test\@example.com/, 'to line looks correct'; + like $email->body, qr/$PUBLIC_RESPONSE/, 'public_response was passed on' or die $email->body; + $mech->clear_emails_ok; + }; + $report->comments->delete; # delete the comments, as they confuse later tests +}; + +subtest "superuser and dm can see stats" => sub { + $mech->log_out_ok; + $user = $mech->log_in_ok( 'super@example.org' ); + + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $mech->get( '/admin/stats' ); + }; + is $mech->res->code, 200, "superuser should be able to see stats page"; + $mech->log_out_ok; + + $user = $mech->log_in_ok( 'dm1@example.org' ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $mech->get( '/admin/stats' ); + }; + is $mech->res->code, 200, "dm can now also see stats page"; + $mech->log_out_ok; +}; + +subtest "only superuser can edit bodies" => sub { + $user = $mech->log_in_ok( 'dm1@example.org' ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $mech->get( '/admin/body/' . $zurich->id ); + }; + is $mech->res->code, 403, "only superuser should be able to edit bodies"; + $mech->log_out_ok; +}; + +subtest "only superuser can see 'Add body' form" => sub { + LWP::Protocol::PSGI->register(t::Mock::MapItZurich->run_if_script, host => 'mapit.zurich'); + $user = $mech->log_in_ok( 'dm1@example.org' ); + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAPIT_URL => 'http://mapit.zurich/', + MAPIT_TYPES => [ 'O08' ], + MAPIT_ID_WHITELIST => [ 423017 ], + }, sub { + $mech->get_ok( '/admin/bodies' ); + }; + $mech->content_lacks( '<form method="post" action="bodies"' ); + $mech->log_out_ok; +}; + +subtest "phone number is mandatory" => sub { + LWP::Protocol::PSGI->register(t::Mock::MapItZurich->run_if_script, host => 'mapit.zurich'); + FixMyStreet::override_config { + MAPIT_TYPES => [ 'O08' ], + MAPIT_URL => 'http://mapit.zurich/', + ALLOWED_COBRANDS => [ 'zurich' ], + MAPIT_ID_WHITELIST => [ 423017 ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $user = $mech->log_in_ok( 'dm1@example.org' ); + $mech->get_ok( '/report/new?lat=47.381817&lon=8.529156' ); + $mech->submit_form( with_fields => { phone => "" } ); + $mech->content_contains( 'Diese Information wird benötigt' ); + $mech->log_out_ok; + }; +}; + +subtest "phone number is not mandatory for reports from mobile apps" => sub { + LWP::Protocol::PSGI->register(t::Mock::MapItZurich->run_if_script, host => 'mapit.zurich'); + FixMyStreet::override_config { + MAPIT_TYPES => [ 'O08' ], + MAPIT_URL => 'http://mapit.zurich/', + ALLOWED_COBRANDS => [ 'zurich' ], + MAPIT_ID_WHITELIST => [ 423017 ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $mech->post_ok( '/report/new/mobile?lat=47.381817&lon=8.529156' , { + service => 'iPhone', + detail => 'Problem-Bericht', + lat => 47.381817, + lon => 8.529156, + email => 'user@example.org', + pc => '', + name => '', + category => 'bad category', + }); + my $res = $mech->response; + ok $res->header('Content-Type') =~ m{^application/json\b}, 'response should be json'; + unlike $res->content, qr/Diese Information wird benötigt/, 'response should not contain phone error'; + # Clear out the mailq + $mech->clear_emails_ok; + }; +}; + +subtest "problems can't be assigned to deleted bodies" => sub { + LWP::Protocol::PSGI->register(t::Mock::MapItZurich->run_if_script, host => 'mapit.zurich'); + $user = $mech->log_in_ok( 'dm1@example.org' ); + $user->from_body( $zurich->id ); + $user->update; + $report->state( 'confirmed' ); + $report->update; + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAPIT_URL => 'http://mapit.zurich/', + MAPIT_TYPES => [ 'O08' ], + MAPIT_ID_WHITELIST => [ 423017 ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $mech->get_ok( '/admin/body/' . $external_body->id ); + $mech->submit_form_ok( { with_fields => { deleted => 1 } } ); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->content_lacks( $external_body->name ) + or do { + diag $mech->content; + diag $external_body->name; + die; + }; + }; + $user->from_body( $division->id ); + $user->update; + $mech->log_out_ok; +}; + +subtest "photo must be supplied for categories that require it" => sub { + LWP::Protocol::PSGI->register(t::Mock::MapItZurich->run_if_script, host => 'mapit.zurich'); + FixMyStreet::App->model('DB::Contact')->find_or_create({ + body => $division, + category => "Graffiti - photo required", + email => "graffiti\@example.org", + confirmed => 1, + deleted => 0, + editor => "editor", + whenedited => DateTime->now(), + note => "note for graffiti", + extra => { photo_required => 1 } + }); + FixMyStreet::override_config { + MAPIT_TYPES => [ 'O08' ], + MAPIT_URL => 'http://mapit.zurich/', + ALLOWED_COBRANDS => [ 'zurich' ], + MAPIT_ID_WHITELIST => [ 423017 ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + $mech->get_ok('/report/new?lat=47.381817&lon=8.529156'); + $mech->submit_form_ok({ with_fields => { + detail => 'Problem-Bericht', + email => 'user@example.org', + category => 'Graffiti - photo required', + }}); + is $mech->res->code, 200, "missing photo shouldn't return anything but 200"; + $mech->content_contains(_("Photo is required."), 'response should contain photo error message'); + }; +}; + +subtest "test stats" => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + }, sub { + $user = $mech->log_in_ok( 'super@example.org' ); + + $mech->get_ok( '/admin/stats' ); + is $mech->res->code, 200, "superuser should be able to see stats page"; + + $mech->content_contains('Innerhalb eines Arbeitstages moderiert: 3'); + $mech->content_contains('Innerhalb von fünf Arbeitstagen abgeschlossen: 3'); + # my @data = $mech->content =~ /(?:moderiert|abgeschlossen): \d+/g; + # diag Dumper(\@data); use Data::Dumper; + + my $export_count = get_export_rows_count($mech); + if (defined $export_count) { + is $export_count - $EXISTING_REPORT_COUNT, 3, 'Correct number of reports'; + $mech->content_contains('fixed - council'); + } + }; +}; + +subtest "test admin_log" => sub { + diag $report->id; + my @entries = FixMyStreet::DB->resultset('AdminLog')->search({ + object_type => 'problem', + object_id => $report->id, + }); + + # XXX: following is dependent on all of test up till now, rewrite to explicitly + # test which things need to be logged! + is scalar @entries, 4, 'State changes logged'; + is $entries[-1]->action, 'state change to closed', 'State change logged as expected'; +}; + +subtest 'email images to external partners' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + reset_report_state($report); + + my $photo = path(__FILE__)->parent->child('zurich-logo_portal.x.jpg')->slurp_raw; + my $photoset = FixMyStreet::App::Model::PhotoSet->new({ + data_items => [ $photo ], + }); + my $fileid = $photoset->data; + + $report->set_extra_metadata('publish_photo' => 1); + # The below email comparison must not have an external message. + $report->unset_extra_metadata('external_message'); + $report->update({ + state => 'closed', + photo => $fileid, + external_body => $external_body->id, + }); + + $mech->clear_emails_ok; + send_reports_for_zurich(); + + my @emails = $mech->get_email; + my $email_as_string = $mech->get_first_email(@emails); + my ($boundary) = $email_as_string =~ /boundary="([A-Za-z0-9.]*)"/ms; + my $email = Email::MIME->new($email_as_string); + + my $expected_email_content = path(__FILE__)->parent->child('zurich_attachments.txt')->slurp; + + my $REPORT_ID = $report->id; + $expected_email_content =~ s{Subject: (.*?)\r?\n}{ + my $subj = Encode::decode('MIME-Header', $1); + $subj =~ s{REPORT_ID}{$REPORT_ID}g; + 'Subject: ' . Email::MIME::Encode::mime_encode($subj, "utf-8") . "\n"; + }eg; + $expected_email_content =~ s{REPORT_ID}{$REPORT_ID}g; + $expected_email_content =~ s{BOUNDARY}{$boundary}g; + my $expected_email = Email::MIME->new($expected_email_content); + + my @email_parts; + $email->walk_parts(sub { + my ($part) = @_; + push @email_parts, [ { $part->header_pairs }, $part->body ]; + }); + my @expected_email_parts; + $expected_email->walk_parts(sub { + my ($part) = @_; + push @expected_email_parts, [ { $part->header_pairs }, $part->body ]; + }); + is_deeply \@email_parts, \@expected_email_parts, 'MIME email text ok' + or do { + (my $test_name = $0) =~ s{/}{_}g; + my $path = path("test-output-$test_name.tmp"); + $path->spew($email_as_string); + diag "Saved output in $path"; + }; + }; +}; + +subtest 'Status update shown as appropriate' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + # ALL closed states must hide the public_response edit, and public ones + # must show the answer in blue. + for (['planned', 1, 0, 0], + ['fixed - council', 0, 1, 0], + ['closed', 0, 1, 0], + ['hidden', 0, 0, 1]) + { + my ($state, $update, $public, $user_response) = @$_; + $report->update({ state => $state }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->contains_or_lacks($update, "name='status_update'"); + $mech->contains_or_lacks($public || $user_response, '<div class="admin-official-answer">'); + + if ($public) { + $mech->get_ok( '/report/' . $report->id ); + $mech->content_contains('Antwort</h4>'); + } + } + }; +}; + +subtest 'time_spent' => sub { + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAP_TYPE => 'Zurich,OSM', + }, sub { + my $report = $reports[0]; + + is $report->get_time_spent, 0, '0 minutes spent'; + $report->update({ state => 'in progress' }); + $mech->get_ok( '/admin/report_edit/' . $report->id ); + $mech->form_with_fields( 'time_spent' ); + $mech->submit_form_ok( { + with_fields => { + time_spent => 10, + } }); + is $report->get_time_spent, 10, '10 minutes spent'; + }; +}; + +$mech->log_out_ok; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'zurich' ], + MAPIT_URL => 'http://mapit.zurich/', + MAPIT_TYPES => [ 'ZZZ' ], +}, sub { + LWP::Protocol::PSGI->register(t::Mock::MapItZurich->run_if_script, host => 'mapit.zurich'); + subtest 'users at the top level can be edited' => sub { + $mech->log_in_ok( $superuser->email ); + $mech->get_ok('/admin/user_edit/' . $superuser->id ); + }; +}; + +END { + $mech->delete_body($subdivision); + $mech->delete_body($division); + $mech->delete_body($zurich); + $mech->delete_body($external_body); + $mech->delete_user( 'dm1@example.org' ); + $mech->delete_user( 'sdm1@example.org' ); + ok $mech->host("www.fixmystreet.com"), "change host back"; + done_testing(); +} + +1; diff --git a/t/cobrand/zurich_attachments.txt b/t/cobrand/zurich_attachments.txt new file mode 100644 index 000000000..25a1bacf0 --- /dev/null +++ b/t/cobrand/zurich_attachments.txt @@ -0,0 +1,33 @@ +MIME-Version: 1.0
+Subject: =?iso-8859-1?Q?Z=FCri?= wie neu: Weitergeleitete Meldung #REPORT_ID
+Content-Type: multipart/mixed; boundary="BOUNDARY"
+To: "External Body" <external_body@example.net>
+Content-Transfer-Encoding: 7bit
+From: "FixMyStreet" <division@example.org>
+
+
+--BOUNDARY
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: quoted-printable
+
+Gr=C3=BCezi External Body,
+
+=C3=96ffentliche URL: http://www.example.org/report/REPORT_ID
+
+Bei Fragen zu "Z=C3=BCri wie neu" wenden Sie sich bitte an =
+gis-zentrum@zuerich.ch.=
+
+--BOUNDARY
+Content-Type: image/jpeg; name="REPORT_ID.0.jpeg"
+Content-Disposition: inline; filename="REPORT_ID.0.jpeg"
+Content-Transfer-Encoding: base64
+
+/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEP
+ERETFhwXExQaFRERGCEYGh0dHx8fExciJCIeJBweHx7/2wBDAQUFBQcGBw4ICA4eFBEUHh4eHh4e
+Hh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh7/wAARCABTAAEDAREA
+AhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIIB//EAB8QAQAABAcAAAAAAAAAAAAAAAADBAbT
+BxcYVVaUpf/EABcBAQEBAQAAAAAAAAAAAAAAAAAFBgT/xAAgEQEAAAQHAQAAAAAAAAAAAAAAAwQV
+UgECFlNhodGx/9oADAMBAAIRAxEAPwCywAIozyxS5R58tbbujSW33j6zFRj3fGbKbjAGAgAACs9N
+FCbtUfYg2mO1BM25e/V+lQeW3ISo/9k=
+
+--BOUNDARY--
|