aboutsummaryrefslogtreecommitdiffstats
path: root/t/cobrand
diff options
context:
space:
mode:
Diffstat (limited to 't/cobrand')
-rw-r--r--t/cobrand/bromley.t138
-rw-r--r--t/cobrand/closest.t12
-rw-r--r--t/cobrand/councils.t12
-rw-r--r--t/cobrand/fixamingata.t121
-rw-r--r--t/cobrand/form_extras.t72
-rw-r--r--t/cobrand/form_extras/templates/report/new/after_photo.html12
-rw-r--r--t/cobrand/get_body_sender.t42
-rw-r--r--t/cobrand/get_council_sender.t30
-rw-r--r--t/cobrand/hart.t16
-rw-r--r--t/cobrand/loading.t111
-rw-r--r--t/cobrand/oxfordshire.t73
-rw-r--r--t/cobrand/restriction.t55
-rw-r--r--t/cobrand/two_tier.t27
-rw-r--r--t/cobrand/zurich-logo_portal.x.jpgbin0 -> 365 bytes
-rw-r--r--t/cobrand/zurich.t995
-rw-r--r--t/cobrand/zurich_attachments.txt33
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
new file mode 100644
index 000000000..c0cfef240
--- /dev/null
+++ b/t/cobrand/zurich-logo_portal.x.jpg
Binary files differ
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('&Uuml;berpr&uuml;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&auml;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: &ldquo;Test Test 1 for ' . $division->id . ' Detail&rdquo;' );
+
+ $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&auml;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&auml;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&ouml;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&ouml;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&uuml;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--