diff options
Diffstat (limited to 't/app/model')
-rw-r--r-- | t/app/model/alert_type.t | 137 | ||||
-rw-r--r-- | t/app/model/comment.t | 10 | ||||
-rw-r--r-- | t/app/model/defecttype.t | 67 | ||||
-rw-r--r-- | t/app/model/extra.t | 109 | ||||
-rw-r--r-- | t/app/model/moderation.t | 66 | ||||
-rw-r--r-- | t/app/model/photoset.t | 81 | ||||
-rw-r--r-- | t/app/model/problem.t | 598 | ||||
-rw-r--r-- | t/app/model/questionnaire.t | 30 | ||||
-rw-r--r-- | t/app/model/rabx_column.t | 23 | ||||
-rw-r--r-- | t/app/model/token.t | 108 | ||||
-rw-r--r-- | t/app/model/user.t | 61 | ||||
-rw-r--r-- | t/app/model/user_planned_report.t | 52 |
12 files changed, 1087 insertions, 255 deletions
diff --git a/t/app/model/alert_type.t b/t/app/model/alert_type.t index c592e9d3f..5e4fcec0a 100644 --- a/t/app/model/alert_type.t +++ b/t/app/model/alert_type.t @@ -9,21 +9,21 @@ my $mech = FixMyStreet::TestMech->new(); # this is the easiest way to make sure we're not going # to get any emails sent by data kicking about in the database -FixMyStreet::App->model('DB::AlertType')->email_alerts(); +FixMyStreet::DB->resultset('AlertType')->email_alerts(); $mech->clear_emails_ok; 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"; my $user2 = - FixMyStreet::App->model('DB::User') + FixMyStreet::DB->resultset('User') ->find_or_create( { email => 'commenter@example.com', name => 'Commenter' } ); ok $user2, "created comment user"; my $user3 = - FixMyStreet::App->model('DB::User') + FixMyStreet::DB->resultset('User') ->find_or_create( { email => 'bystander@example.com', name => 'Bystander' } ); ok $user3, "created bystander"; @@ -36,10 +36,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', @@ -62,7 +62,7 @@ my $report = FixMyStreet::App->model('DB::Problem')->find_or_create( my $report_id = $report->id; ok $report, "created test report - $report_id"; -my $comment = FixMyStreet::App->model('DB::Comment')->find_or_create( +my $comment = FixMyStreet::DB->resultset('Comment')->find_or_create( { problem_id => $report_id, user_id => $user2->id, @@ -74,7 +74,7 @@ my $comment = FixMyStreet::App->model('DB::Comment')->find_or_create( anonymous => 'f', } ); -my $comment2 = FixMyStreet::App->model('DB::Comment')->find_or_create( +my $comment2 = FixMyStreet::DB->resultset('Comment')->find_or_create( { problem_id => $report_id, user_id => $user2->id, @@ -87,26 +87,28 @@ my $comment2 = FixMyStreet::App->model('DB::Comment')->find_or_create( } ); -$comment->confirmed( \"ms_current_timestamp() - '3 days'::interval" ); +$comment->confirmed( \"current_timestamp - '3 days'::interval" ); $comment->update; -my $alert = FixMyStreet::App->model('DB::Alert')->find_or_create( +my $alert = FixMyStreet::DB->resultset('Alert')->find_or_create( { user => $user, parameter => $report_id, alert_type => 'new_updates', whensubscribed => $dt->ymd . ' ' . $dt->hms, confirmed => 1, + cobrand => 'default', } ); -my $alert3 = FixMyStreet::App->model('DB::Alert')->find_or_create( +my $alert3 = FixMyStreet::DB->resultset('Alert')->find_or_create( { user => $user3, parameter => $report_id, alert_type => 'new_updates', whensubscribed => $dt->ymd . ' ' . $dt->hms, confirmed => 1, + cobrand => 'default', } ); @@ -127,7 +129,7 @@ for my $test ( subtest "correct summary for state of $test->{state}" => sub { $mech->clear_emails_ok; - my $sent = FixMyStreet::App->model('DB::AlertSent')->search( + my $sent = FixMyStreet::DB->resultset('AlertSent')->search( { alert_id => [ $alert->id, $alert3->id ], parameter => $comment->id, @@ -137,18 +139,18 @@ for my $test ( $report->state( $test->{state} ); $report->update; - FixMyStreet::App->model('DB::AlertType')->email_alerts(); + FixMyStreet::DB->resultset('AlertType')->email_alerts(); $mech->email_count_is( 2 ); my @emails = $mech->get_email; my $msg = $test->{msg}; for my $email (@emails) { - my $body = $email->body; + my $body = $mech->get_text_body_from_email($email); my $to = $email->header('To'); like $body, qr/$msg/, 'email says problem is ' . $test->{state}; if ($to eq $user->email) { - like $body, qr{/M/}, 'contains problem login url'; + like $body, qr{/R/}, 'contains problem login url'; } elsif ($to eq $user3->email) { like $body, qr{/report/$report_id}, 'contains problem url'; } @@ -165,7 +167,7 @@ my $now = DateTime->now(); $report->confirmed( $now->ymd . ' ' . $now->hms ); $report->update(); -my $council_alert = FixMyStreet::App->model('DB::Alert')->find_or_create( +my $council_alert = FixMyStreet::DB->resultset('Alert')->find_or_create( { user => $user2, parameter => 2504, @@ -179,17 +181,20 @@ my $council_alert = FixMyStreet::App->model('DB::Alert')->find_or_create( subtest "correct text for title after URL" => sub { $mech->clear_emails_ok; - my $sent = FixMyStreet::App->model('DB::AlertSent')->search( + my $sent = FixMyStreet::DB->resultset('AlertSent')->search( { alert_id => $council_alert->id, parameter => $report->id, } )->delete; - FixMyStreet::App->model('DB::AlertType')->email_alerts(); + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + }, sub { + FixMyStreet::DB->resultset('AlertType')->email_alerts(); + }; - my $email = $mech->get_email; (my $title = $report->title) =~ s/ /\\s+/; - my $body = $email->body; + my $body = $mech->get_text_body_from_email; like $body, qr#report/$report_id\s+-\s+$title#, 'email contains expected title'; }; @@ -281,7 +286,7 @@ foreach my $test ( desc => 'address only', addressLine => '18 North Bridge', locality => undef, - nearest => qr/: 18 North Bridge\n/, + nearest => qr/: 18 North Bridge\r?\n/, }, { desc => 'no fields', @@ -298,7 +303,7 @@ foreach my $test ( subtest "correct Nearest Road text with $test->{desc}" => sub { $mech->clear_emails_ok; - my $sent = FixMyStreet::App->model('DB::AlertSent')->search( + my $sent = FixMyStreet::DB->resultset('AlertSent')->search( { alert_id => $council_alert->id, parameter => $report->id, @@ -318,10 +323,13 @@ foreach my $test ( $report->geocode( $g ); $report->update(); - FixMyStreet::App->model('DB::AlertType')->email_alerts(); + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + }, sub { + FixMyStreet::DB->resultset('AlertType')->email_alerts(); + }; - my $email = $mech->get_email; - my $body = $email->body; + my $body = $mech->get_text_body_from_email; if ( $test->{nearest} ) { like $body, $test->{nearest}, 'correct nearest line'; @@ -331,21 +339,21 @@ foreach my $test ( }; } -my $ward_alert = FixMyStreet::App->model('DB::Alert')->find_or_create( +my $ward_alert = FixMyStreet::DB->resultset('Alert')->find_or_create( { user => $user, parameter => 7117, alert_type => 'area_problems', whensubscribed => $dt->ymd . ' ' . $dt->hms, confirmed => 1, - cobrand => 'lichfielddc', + cobrand => 'hart', } ); -my $report_to_council = FixMyStreet::App->model('DB::Problem')->find_or_create( +my $report_to_council = FixMyStreet::DB->resultset('Problem')->find_or_create( { postcode => 'WS13 6YY', - council => '2434', + bodies_str => '2434', areas => ',105255,11806,11828,2247,2504,7117,', category => 'Other', title => 'council report', @@ -366,10 +374,10 @@ my $report_to_council = FixMyStreet::App->model('DB::Problem')->find_or_create( } ); -my $report_to_county_council = FixMyStreet::App->model('DB::Problem')->find_or_create( +my $report_to_county_council = FixMyStreet::DB->resultset('Problem')->find_or_create( { postcode => 'WS13 6YY', - council => '2240', + bodies_str => '2240', areas => ',105255,11806,11828,2247,2504,7117,', category => 'Other', title => 'county report', @@ -390,10 +398,10 @@ my $report_to_county_council = FixMyStreet::App->model('DB::Problem')->find_or_c } ); -my $report_outside_district = FixMyStreet::App->model('DB::Problem')->find_or_create( +my $report_outside_district = FixMyStreet::DB->resultset('Problem')->find_or_create( { postcode => 'WS13 6YY', - council => '2221', + bodies_str => '2221', areas => ',105255,11806,11828,2247,2504,7117,', category => 'Other', title => 'outside district report', @@ -417,20 +425,23 @@ my $report_outside_district = FixMyStreet::App->model('DB::Problem')->find_or_cr subtest "check alerts from cobrand send main site url for alerts for different council" => sub { $mech->clear_emails_ok; - my $sent = FixMyStreet::App->model('DB::AlertSent')->search( + my $sent = FixMyStreet::DB->resultset('AlertSent')->search( { alert_id => $ward_alert->id, } )->delete; - FixMyStreet::App->model('DB::AlertType')->email_alerts(); + FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.uk/', + }, sub { + FixMyStreet::DB->resultset('AlertType')->email_alerts(); + }; - my $email = $mech->get_email; - my $body = $email->body; + my $body = $mech->get_text_body_from_email; - my $expected1 = mySociety::Config::get('BASE_URL') . '/report/' . $report_to_county_council->id; - my $expected3 = mySociety::Config::get('BASE_URL') . '/report/' . $report_outside_district->id; - my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('lichfielddc')->new(); + my $expected1 = FixMyStreet->config('BASE_URL') . '/report/' . $report_to_county_council->id; + my $expected3 = FixMyStreet->config('BASE_URL') . '/report/' . $report_outside_district->id; + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('hart')->new(); my $expected2 = $cobrand->base_url . '/report/' . $report_to_council->id; like $body, qr#$expected1#, 'non cobrand area report point to fixmystreet.com'; @@ -439,14 +450,14 @@ subtest "check alerts from cobrand send main site url for alerts for different c }; -my $local_alert = FixMyStreet::App->model('DB::Alert')->find_or_create( +my $local_alert = FixMyStreet::DB->resultset('Alert')->find_or_create( { user => $user, parameter => -1.731322, parameter2 => 52.727588, alert_type => 'local_problems', whensubscribed => $dt->ymd . ' ' . $dt->hms, - cobrand => 'lichfielddc', + cobrand => 'hart', confirmed => 1, } ); @@ -454,26 +465,50 @@ my $local_alert = FixMyStreet::App->model('DB::Alert')->find_or_create( subtest "check local alerts from cobrand send main site url for alerts for different council" => sub { $mech->clear_emails_ok; - my $sent = FixMyStreet::App->model('DB::AlertSent')->search( + my $sent = FixMyStreet::DB->resultset('AlertSent')->search( { alert_id => $local_alert->id, } )->delete; - FixMyStreet::App->model('DB::AlertType')->email_alerts(); + FixMyStreet::DB->resultset('AlertType')->email_alerts(); - my $email = $mech->get_email; - my $body = $email->body; + my $body = $mech->get_text_body_from_email; - my $expected1 = mySociety::Config::get('BASE_URL') . '/report/' . $report_to_county_council->id; - my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('lichfielddc')->new(); + my $expected1 = FixMyStreet->config('BASE_URL') . '/report/' . $report_to_county_council->id; + my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker('hart')->new(); my $expected2 = $cobrand->base_url . '/report/' . $report_to_council->id; like $body, qr#$expected1#, 'non cobrand area report point to fixmystreet.com'; like $body, qr#$expected2#, 'cobrand area report point to cobrand url'; }; -$report->comments->delete(); -$report->delete(); -done_testing(); +# Test that email alerts are sent in the right language. +subtest "correct i18n-ed summary for state of closed" => sub { + $mech->clear_emails_ok; + + $report->update( { state => 'closed' } ); + $alert->update( { lang => 'nb', cobrand => 'fiksgatami' } ); + + FixMyStreet::DB->resultset('AlertSent')->search( { + alert_id => $alert->id, + parameter => $comment->id, + } )->delete; + FixMyStreet::override_config { + ALLOWED_COBRANDS => [ 'fiksgatami' ], + }, sub { + FixMyStreet::DB->resultset('AlertType')->email_alerts(); + }; + + my $body = $mech->get_text_body_from_email; + my $msg = 'Denne rapporten er for tiden markert som lukket'; + like $body, qr/$msg/, 'email says problem is closed, in Norwegian'; +}; + +END { + $mech->delete_user($user) if $user; + $mech->delete_user($user2) if $user2; + $mech->delete_user($user3) if $user3; + done_testing(); +} diff --git a/t/app/model/comment.t b/t/app/model/comment.t index 93104c2e5..e83d795fc 100644 --- a/t/app/model/comment.t +++ b/t/app/model/comment.t @@ -1,14 +1,12 @@ -#!/usr/bin/perl - use strict; use warnings; use Test::More tests => 2; use FixMyStreet; -use FixMyStreet::App; +use FixMyStreet::DB; -my $comment_rs = FixMyStreet::App->model('DB::Comment'); +my $comment_rs = FixMyStreet::DB->resultset('Comment'); my $comment = $comment_rs->new( { @@ -23,5 +21,5 @@ my $comment = $comment_rs->new( } ); -is $comment->confirmed_local, undef, 'inflating null confirmed ok'; -is $comment->created_local, undef, 'inflating null confirmed ok'; +is $comment->confirmed, undef, 'inflating null confirmed ok'; +is $comment->created, undef, 'inflating null confirmed ok'; diff --git a/t/app/model/defecttype.t b/t/app/model/defecttype.t new file mode 100644 index 000000000..0f66ac684 --- /dev/null +++ b/t/app/model/defecttype.t @@ -0,0 +1,67 @@ +use strict; +use warnings; +use Test::More; + +use FixMyStreet::App; +use FixMyStreet::TestMech; +my $mech = FixMyStreet::TestMech->new; + +my $oxfordshire = $mech->create_body_ok(2237, 'Oxfordshire County Council', id => 2237); +my $potholes_contact = $mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Potholes', email => 'potholes@example.com' ); +my $traffic_lights_contact =$mech->create_contact_ok( body_id => $oxfordshire->id, category => 'Traffic lights', email => 'lights@example.com' ); + +my $potholes_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create( + { + body_id => 2237, + name => 'Potholes', + description => 'This defect type is to do with potholes' + } +); +$potholes_defect_type->contact_defect_types->find_or_create({ + contact_id => $potholes_contact->id, +}); + +my $general_defect_type = FixMyStreet::App->model('DB::DefectType')->find_or_create( + { + body_id => 2237, + name => 'All categories', + description => 'This defect type is for all categories' + } +); + + +subtest 'for_bodies returns correct results' => sub { + my $defect_types = FixMyStreet::App->model('DB::DefectType')->for_bodies( + [ $oxfordshire->id ], + 'Potholes' + ); + + is $defect_types->count, 2, 'Both defect types are included for Potholes category'; + + $defect_types = FixMyStreet::App->model('DB::DefectType')->for_bodies( + [ $oxfordshire->id ], + 'Traffic lights' + ); + + is $defect_types->count, 1, 'Only 1 defect type is included for Traffic lights category'; + is $defect_types->first->name, $general_defect_type->name, 'Correct defect type is returned for Traffic lights category'; +}; + +subtest 'Problem->defect_types behaves correctly' => sub { + my ($problem) = $mech->create_problems_for_body(1, $oxfordshire->id, 'Test', { + category => 'Potholes', + }); + + is $problem->defect_types->count, 2, 'Both defect types are available for the problem'; + + $problem->update({ category => 'Traffic lights' }); + is $problem->defect_types->count, 1, 'Only 1 defect type is included for Traffic lights category'; + is $problem->defect_types->first->name, $general_defect_type->name, 'Correct defect type is returned for Traffic lights category'; +}; + + +END { + $mech->delete_body( $oxfordshire ); + + done_testing(); +} diff --git a/t/app/model/extra.t b/t/app/model/extra.t new file mode 100644 index 000000000..3b46ce128 --- /dev/null +++ b/t/app/model/extra.t @@ -0,0 +1,109 @@ +use strict; +use warnings; +use Test::More; +use utf8; + +use FixMyStreet::DB; +use Data::Dumper; +use DateTime; + +my $db = FixMyStreet::DB->connect; +$db->txn_begin; + +my $body = $db->resultset('Body')->create({ name => 'ExtraTestingBody' }); + +my $serial = 1; +sub get_test_contact { + my $extra = shift; + my $contact = $db->resultset('Contact')->create({ + category => "Testing ${serial}", + body => $body, + email => 'test@example.com', + confirmed => 1, + deleted => 0, + editor => 'test script', + note => 'test script', + whenedited => DateTime->now(), + $extra ? ( extra => $extra ) : (), + }); + $serial++; + return $contact; +} + +subtest 'Old list layout transparently upgraded' => sub { + + subtest 'layout' => sub { + my $contact = get_test_contact([]); + + is_deeply $contact->get_extra(), { _fields => [] }, 'transparently upgraded to a hash'; + }; + + subtest 'extra fields' => sub { + my $contact = get_test_contact([]); + + is_deeply $contact->get_extra_fields(), [], 'No extra fields'; + + my @fields = ( { a => 1 }, { b => 2 } ); + $contact->set_extra_fields(@fields); + is_deeply $contact->extra, { _fields => \@fields }, 'extra fields set...'; + $contact->update; + $contact->discard_changes; + is_deeply $contact->extra, { _fields => \@fields }, '...and retrieved'; + is_deeply $contact->get_extra_fields(), \@fields, 'extra fields returned'; + }; + + subtest 'metadata' => sub { + my $contact = get_test_contact([]); + is_deeply $contact->get_extra_metadata, {}, 'No extra metadata'; + + $contact->set_extra_metadata('foo' => 'bar'); + is $contact->get_extra_metadata('foo'), 'bar', 'extra metadata set...'; + $contact->update; + $contact->discard_changes; + is $contact->get_extra_metadata('foo'), 'bar', '... and retrieved'; + is_deeply $contact->get_extra_metadata, { foo => 'bar' }, 'No extra metadata'; + }; +}; + +subtest 'Default hash layout' => sub { + subtest 'layout' => sub { + my $contact = get_test_contact(); + + is_deeply $contact->get_extra(), {}, 'default layout is hash'; + }; + + subtest 'extra fields' => sub { + my $contact = get_test_contact(); + + is_deeply $contact->get_extra_fields(), [], 'No extra fields'; + + my @fields = ( { a => 1 }, { b => 2 } ); + $contact->set_extra_fields(@fields); + is_deeply $contact->get_extra_fields, \@fields, 'extra fields set...'; + $contact->update; + $contact->discard_changes; + is_deeply $contact->get_extra_fields(), \@fields, '... and returned'; + is_deeply $contact->extra, { _fields => \@fields }, '(sanity check layout)'; + }; + + subtest 'metadata' => sub { + my $contact = get_test_contact(); + is_deeply $contact->get_extra_metadata, {}, 'No extra metadata'; + + $contact->set_extra_metadata('foo' => 'bar'); + is $contact->get_extra_metadata('foo'), 'bar', 'extra metadata set...'; + $contact->update; + $contact->discard_changes; + is $contact->get_extra_metadata( 'foo'), 'bar', '... and retrieved'; + is_deeply $contact->get_extra_metadata, { foo => 'bar' }, 'No extra metadata'; + + $contact->unset_extra_metadata('foo'); + is $contact->get_extra_metadata('foo'), undef, 'extra metadata now unset'; + $contact->update; + $contact->discard_changes; + is $contact->get_extra_metadata('foo'), undef, '... after retrieval'; + }; +}; + +$db->txn_rollback; +done_testing(); diff --git a/t/app/model/moderation.t b/t/app/model/moderation.t new file mode 100644 index 000000000..8fa333db4 --- /dev/null +++ b/t/app/model/moderation.t @@ -0,0 +1,66 @@ +use strict; +use warnings; +use Test::More; +use Test::Exception; +use utf8; + +use FixMyStreet::DB; +use Data::Dumper; +use DateTime; + +my $dt = DateTime->now; +my $user = FixMyStreet::DB->resultset('User')->find_or_create({ + name => 'Bob', email => 'bob@example.com', +}); + +sub get_report_and_original_data { + my $report = FixMyStreet::DB->resultset('Problem')->create( + { + postcode => 'BR1 3SB', + bodies_str => '', + areas => ",,", + category => 'Other', + title => 'test', + detail => 'test', + used_map => 't', + name => 'Anon', + anonymous => 't', + state => 'confirmed', + confirmed => $dt->ymd . ' ' . $dt->hms, + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 't', + latitude => '51.4129', + longitude => '0.007831', + user => $user, + }); + my $original = $report->create_related( moderation_original_data => { + anonymous => 't', + title => 'test', + detail => 'test', + photo => 'f', + } ); + + return ($report, $original); +} + +subtest 'Explicit Deletion (sanity test)' => sub { + my ($report, $orig) = get_report_and_original_data; + + lives_ok { + $orig->delete; + $report->delete; + }; +}; + +subtest 'Implicit Chained Deletion' => sub { + my ($report, $orig) = get_report_and_original_data; + + lives_ok { + $report->delete; + }; +}; + +done_testing(); diff --git a/t/app/model/photoset.t b/t/app/model/photoset.t new file mode 100644 index 000000000..54530adfb --- /dev/null +++ b/t/app/model/photoset.t @@ -0,0 +1,81 @@ +use strict; +use warnings; +use Test::More; +use Test::Exception; +use utf8; + +use FixMyStreet::DB; +use DateTime; +use Path::Tiny 'path'; +use File::Temp 'tempdir'; + +my $dt = DateTime->now; + +my $UPLOAD_DIR = tempdir( CLEANUP => 1 ); + +my $db = FixMyStreet::DB->storage->schema; + +my $user = $db->resultset('User')->find_or_create({ + name => 'Bob', email => 'bob@example.com', +}); + +FixMyStreet::override_config { + UPLOAD_DIR => $UPLOAD_DIR, +}, sub { + +$db->txn_begin; + +my $image_path = path('t/app/controller/sample.jpg'); + +sub make_report { + my $photo_data = shift; + return $db->resultset('Problem')->create({ + postcode => 'BR1 3SB', + bodies_str => '', + areas => ",,", + category => 'Other', + title => 'test', + detail => 'test', + used_map => 't', + name => 'Anon', + anonymous => 't', + state => 'confirmed', + confirmed => $dt, + lang => 'en-gb', + service => '', + cobrand => 'default', + cobrand_data => '', + send_questionnaire => 't', + latitude => '51.4129', + longitude => '0.007831', + user => $user, + photo => $photo_data, + }); +} + + +subtest 'Photoset with photo inline in DB' => sub { + my $report = make_report( $image_path->slurp ); + my $photoset = $report->get_photoset(); + is $photoset->num_images, 1, 'Found just 1 image'; + is $photoset->data, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg'; +}; + +$image_path->copy( path( $UPLOAD_DIR, '0123456789012345678901234567890123456789.jpeg' ) ); +subtest 'Photoset with 1 referenced photo' => sub { + my $report = make_report( '0123456789012345678901234567890123456789' ); + my $photoset = $report->get_photoset(); + is $photoset->num_images, 1, 'Found just 1 image'; +}; + +subtest 'Photoset with 3 referenced photo' => sub { + my $report = make_report( '0123456789012345678901234567890123456789,0123456789012345678901234567890123456789,0123456789012345678901234567890123456789' ); + my $photoset = $report->get_photoset(); + is $photoset->num_images, 3, 'Found 3 images'; +}; + +$db->txn_rollback; + +}; + +done_testing(); diff --git a/t/app/model/problem.t b/t/app/model/problem.t index baec6baf0..6b1be0a76 100644 --- a/t/app/model/problem.t +++ b/t/app/model/problem.t @@ -1,24 +1,24 @@ -#!/usr/bin/perl - use strict; use warnings; use Test::More; +use FixMyStreet::TestMech; use FixMyStreet; use FixMyStreet::App; -use FixMyStreet::TestMech; +use FixMyStreet::DB; use mySociety::Locale; +use Sub::Override; mySociety::Locale::gettext_domain('FixMyStreet'); -my $problem_rs = FixMyStreet::App->model('DB::Problem'); +my $problem_rs = FixMyStreet::DB->resultset('Problem'); my $problem = $problem_rs->new( { postcode => 'EH99 1SP', - latitude => '51.5016605453401', - longitude => '-0.142497580865087', + latitude => '54.5', + longitude => '-1.5', areas => 1, title => '', detail => '', @@ -32,47 +32,40 @@ my $problem = $problem_rs->new( } ); -is $problem->confirmed_local, undef, 'inflating null confirmed ok'; -is $problem->whensent_local, undef, 'inflating null confirmed ok'; -is $problem->lastupdate_local, undef, 'inflating null confirmed ok'; -is $problem->created_local, undef, 'inflating null confirmed ok'; +my $visible_states = $problem->visible_states; +is_deeply $visible_states, { + 'confirmed' => 1, + 'investigating' => 1, + 'in progress' => 1, + 'planned' => 1, + 'action scheduled' => 1, + 'fixed' => 1, + 'fixed - council' => 1, + 'fixed - user' => 1, + 'unable to fix' => 1, + 'not responsible' => 1, + 'duplicate' => 1, + 'closed' => 1, + 'internal referral' => 1, + }, 'visible_states is correct'; + +is $problem->confirmed, undef, 'inflating null confirmed ok'; +is $problem->whensent, undef, 'inflating null confirmed ok'; +is $problem->lastupdate, undef, 'inflating null confirmed ok'; +is $problem->created, undef, 'inflating null confirmed ok'; -for my $test ( +for my $test ( { desc => 'more or less empty problem', changed => {}, errors => { title => 'Please enter a subject', detail => 'Please enter some details', - council => 'No council selected', + bodies => 'No council selected', name => 'Please enter your name', } }, { - desc => 'name too short', - changed => { - name => 'xx', - }, - errors => { - title => 'Please enter a subject', - detail => 'Please enter some details', - council => 'No council selected', - name => 'Please enter your full name, councils need this information – if you do not wish your name to be shown on the site, untick the box below', - } - }, - { - desc => 'name is anonymous', - changed => { - name => 'anonymous', - }, - errors => { - title => 'Please enter a subject', - detail => 'Please enter some details', - council => 'No council selected', - name => 'Please enter your full name, councils need this information – if you do not wish your name to be shown on the site, untick the box below', - } - }, - { desc => 'correct name', changed => { name => 'A User', @@ -80,7 +73,7 @@ for my $test ( errors => { title => 'Please enter a subject', detail => 'Please enter some details', - council => 'No council selected', + bodies => 'No council selected', } }, { @@ -90,7 +83,7 @@ for my $test ( }, errors => { detail => 'Please enter some details', - council => 'No council selected', + bodies => 'No council selected', } }, { @@ -99,22 +92,22 @@ for my $test ( detail => 'Some information about the problem', }, errors => { - council => 'No council selected', + bodies => 'No council selected', } }, { - desc => 'incorrectly formatted council', + desc => 'incorrectly formatted body', changed => { - council => 'my council', + bodies_str => 'my body', }, errors => { - council => 'No council selected', + bodies => 'No council selected', } }, { - desc => 'correctly formatted council', + desc => 'correctly formatted body', changed => { - council => '1001', + bodies_str => '1001', }, errors => { } @@ -153,9 +146,9 @@ for my $test ( }; } -my $user = FixMyStreet::App->model('DB::User')->find_or_create( +my $user = FixMyStreet::DB->resultset('User')->find_or_create( { - email => 'system_user@example.com' + email => 'system_user@example.net' } ); @@ -167,6 +160,10 @@ $problem->insert; my $tz_local = DateTime::TimeZone->new( name => 'local' ); +my $body = FixMyStreet::DB->resultset('Body')->new({ + name => 'Edinburgh City Council' +}); + for my $test ( { desc => 'request older than problem ignored', @@ -174,9 +171,6 @@ for my $test ( request => { updated_datetime => DateTime::Format::W3CDTF->new()->format_datetime( DateTime->now()->set_time_zone( $tz_local )->subtract( days => 2 ) ), }, - council => { - name => 'Edinburgh City Council', - }, created => 0, }, { @@ -187,9 +181,6 @@ for my $test ( status => 'open', status_notes => 'this is an update from the council', }, - council => { - name => 'Edinburgh City Council', - }, created => 1, state => 'confirmed', mark_fixed => 0, @@ -203,9 +194,6 @@ for my $test ( status => 'closed', status_notes => 'the council have fixed this', }, - council => { - name => 'Edinburgh City Council', - }, created => 1, state => 'fixed', mark_fixed => 1, @@ -219,9 +207,6 @@ for my $test ( status => 'open', status_notes => 'the council do not think this is fixed', }, - council => { - name => 'Edinburgh City Council', - }, created => 1, start_state => 'fixed', state => 'fixed', @@ -238,7 +223,7 @@ for my $test ( $problem->update; my $w3c = DateTime::Format::W3CDTF->new(); - my $ret = $problem->update_from_open311_service_request( $test->{request}, $test->{council}, $user ); + my $ret = $problem->update_from_open311_service_request( $test->{request}, $body, $user ); is $ret, $test->{created}, 'return value'; return unless $test->{created}; @@ -258,12 +243,13 @@ for my $test ( }; } -for my $test ( +for my $test ( { state => 'partial', is_visible => 0, is_fixed => 0, is_open => 0, + is_in_progress => 0, is_closed => 0, }, { @@ -271,6 +257,7 @@ for my $test ( is_visible => 0, is_fixed => 0, is_open => 0, + is_in_progress => 0, is_closed => 0, }, { @@ -278,6 +265,7 @@ for my $test ( is_visible => 0, is_fixed => 0, is_open => 0, + is_in_progress => 0, is_closed => 0, }, { @@ -285,6 +273,7 @@ for my $test ( is_visible => 1, is_fixed => 0, is_open => 1, + is_in_progress => 0, is_closed => 0, }, { @@ -292,6 +281,7 @@ for my $test ( is_visible => 1, is_fixed => 0, is_open => 1, + is_in_progress => 1, is_closed => 0, }, { @@ -299,6 +289,15 @@ for my $test ( is_visible => 1, is_fixed => 0, is_open => 1, + is_in_progress => 1, + is_closed => 0, + }, + { + state => 'action scheduled', + is_visible => 1, + is_fixed => 0, + is_open => 1, + is_in_progress => 1, is_closed => 0, }, { @@ -306,13 +305,39 @@ for my $test ( is_visible => 1, is_fixed => 0, is_open => 1, + is_in_progress => 1, is_closed => 0, }, { + state => 'duplicate', + is_visible => 1, + is_fixed => 0, + is_open => 0, + is_in_progress => 0, + is_closed => 1, + }, + { + state => 'not responsible', + is_visible => 1, + is_fixed => 0, + is_open => 0, + is_in_progress => 0, + is_closed => 1, + }, + { + state => 'unable to fix', + is_visible => 1, + is_fixed => 0, + is_open => 0, + is_in_progress => 0, + is_closed => 1, + }, + { state => 'fixed', is_visible => 1, is_fixed => 1, is_open => 0, + is_in_progress => 0, is_closed => 0, }, { @@ -320,6 +345,7 @@ for my $test ( is_visible => 1, is_fixed => 1, is_open => 0, + is_in_progress => 0, is_closed => 0, }, { @@ -327,6 +353,7 @@ for my $test ( is_visible => 1, is_fixed => 1, is_open => 0, + is_in_progress => 0, is_closed => 0, }, { @@ -334,6 +361,7 @@ for my $test ( is_visible => 1, is_fixed => 0, is_open => 0, + is_in_progress => 0, is_closed => 1, }, ) { @@ -343,64 +371,75 @@ for my $test ( is $problem->is_fixed, $test->{is_fixed}, 'is_fixed'; is $problem->is_closed, $test->{is_closed}, 'is_closed'; is $problem->is_open, $test->{is_open}, 'is_open'; + is $problem->is_in_progress, $test->{is_in_progress}, 'is_in_progress'; }; } my $mech = FixMyStreet::TestMech->new(); -my %contact_params = ( - confirmed => 1, - deleted => 0, - editor => 'Test', - whenedited => \'ms_current_timestamp()', - note => 'Created for test', -); +my %body_ids; +my @bodies; +for my $body ( + { area_id => 2651, name => 'City of Edinburgh Council' }, + { area_id => 2226, name => 'Gloucestershire County Council' }, + { area_id => 2326, name => 'Cheltenham Borough Council' }, + { area_id => 2333, name => 'Hart Council' }, + { area_id => 2227, name => 'Hampshire County Council' }, + { area_id => 14279, name => 'Ballymoney Borough Council' }, + { area_id => 2636, name => 'Isle of Wight Council' }, + { area_id => 2649, name => 'Fife Council' }, + { area_id => 14279, name => 'TransportNI (Western)' }, +) { + my $aid = $body->{area_id}; + my $body = $mech->create_body_ok($aid, $body->{name}); + if ($body_ids{$aid}) { + $body_ids{$aid} = [ $body_ids{$aid}, $body->id ]; + } else { + $body_ids{$aid} = $body->id; + } + push @bodies, $body; +} + # Let's make some contacts to send things to! -FixMyStreet::App->model('DB::Contact')->search( { - email => { 'like', '%example.com' }, -} )->delete; -my @contacts; for my $contact ( { - body_id => 2651, # Edinburgh + body_id => $body_ids{2651}, # Edinburgh category => 'potholes', email => 'test@example.org', }, { - body_id => 2226, # Gloucestershire + body_id => $body_ids{2226}, # Gloucestershire category => 'potholes', email => '2226@example.org', }, { - body_id => 2326, # Cheltenham + body_id => $body_ids{2326}, # Cheltenham category => 'potholes', email => '2326@example.org', }, { - body_id => 2434, # Lichfield + body_id => $body_ids{2333}, # Hart category => 'potholes', email => 'trees@example.com', }, { - body_id => 2240, # Staffordshire + body_id => $body_ids{2227}, # Hampshire category => 'potholes', email => 'highways@example.com', }, { - body_id => 14279, # Ballymoney + body_id => $body_ids{14279}[1], # TransportNI category => 'Street lighting', email => 'roads.western@drdni.example.org', }, { - body_id => 14279, # Ballymoney + body_id => $body_ids{14279}[0], # Ballymoney category => 'Graffiti', - email => 'highways@example.com', + email => 'highways@example.net', }, { confirmed => 0, - body_id => 2636, # Isle of Wight + body_id => $body_ids{2636}, # Isle of Wight category => 'potholes', email => '2636@example.com', } ) { - my $new_contact = FixMyStreet::App->model('DB::Contact')->find_or_create( { %contact_params, %$contact } ); - ok $new_contact, "created test contact"; - push @contacts, $new_contact; + $mech->create_contact_ok( %$contact ); } my %common = ( - email => 'system_user@example.com', + email => 'system_user@example.net', name => 'Andrew Smith', ); foreach my $test ( { @@ -410,21 +449,21 @@ foreach my $test ( { email_count => 1, dear => qr'Dear City of Edinburgh Council', to => qr'City of Edinburgh Council', - council => 2651, + body => $body_ids{2651}, }, { %common, desc => 'no email sent if no unsent problems', unset_whendef => 0, email_count => 0, - council => 2651, + body => $body_ids{2651}, }, { %common, desc => 'email to two tier council', unset_whendef => 1, email_count => 1, - to => qr'Gloucestershire County Council.*Cheltenham Borough Council', - dear => qr'Dear Gloucestershire County Council and Cheltenham Borough', - council => '2226,2326', + to => qr'Cheltenham Borough Council.*Gloucestershire County Council', + dear => qr'Dear Cheltenham Borough Council and Gloucestershire County', + body => $body_ids{2226} . ',' . $body_ids{2326}, multiple => 1, }, { %common, @@ -433,28 +472,29 @@ foreach my $test ( { email_count => 1, to => qr'Gloucestershire County Council" <2226@example', dear => qr'Dear Gloucestershire County Council,', - council => '2226|2649', + body => $body_ids{2226}, + body_missing => $body_ids{2649}, missing => qr'problem might be the responsibility of Fife.*Council'ms, }, { %common, desc => 'email to two tier council that only shows district, district', unset_whendef => 1, email_count => 1, - to => qr'Lichfield District Council', - dear => qr'Dear Lichfield District Council,', - council => '2434', - cobrand => 'lichfielddc', - url => 'lichfielddc.', + to => qr'Hart Council', + dear => qr'Dear Hart Council,', + body => $body_ids{2333}, + cobrand => 'hart', + url => 'hart.', }, { %common, desc => 'email to two tier council that only shows district, county', unset_whendef => 1, email_count => 1, - to => qr'Staffordshire County Council" <highways@example', - dear => qr'Dear Staffordshire County Council,', - council => '2240', - cobrand => 'lichfielddc', - url => '', + to => qr'Hampshire County Council" <highways@example', + dear => qr'Dear Hampshire County Council,', + body => $body_ids{2227}, + cobrand => 'hart', + url => 'www.', }, { %common, desc => 'directs NI correctly, 1', @@ -462,72 +502,96 @@ foreach my $test ( { email_count => 1, dear => qr'Dear Ballymoney Borough Council', to => qr'Ballymoney Borough Council', - council => 14279, + body => $body_ids{14279}[0], category => 'Graffiti', + longitude => -6.5, + # As Ballmoney contact has same domain as reporter, the From line will + # become a unique reply address and Reply-To will become the reporter + reply_to => 1, }, { %common, desc => 'directs NI correctly, 2', unset_whendef => 1, email_count => 1, - dear => qr'Dear Roads Service \(Western\)', - to => qr'Roads Service \(Western\)" <roads', - council => 14279, + dear => qr'Dear TransportNI \(Western\)', + to => qr'TransportNI \(Western\)" <roads', + body => $body_ids{14279}[1], category => 'Street lighting', + longitude => -6.5, }, { %common, desc => 'does not send to unconfirmed contact', unset_whendef => 1, stays_unsent => 1, email_count => 0, - council => 2636, + body => $body_ids{2636}, }, ) { subtest $test->{ desc } => sub { - if ( $test->{cobrand} && $test->{cobrand} =~ /lichfielddc/ && !FixMyStreet::Cobrand->exists('lichfielddc') ) { - plan skip_all => 'Skipping Lichfield tests without Lichfield cobrand'; + my $override = { + ALLOWED_COBRANDS => [ 'fixmystreet' ], + BASE_URL => 'http://www.fixmystreet.com', + MAPIT_URL => 'http://mapit.mysociety.org/', + }; + if ( $test->{cobrand} && $test->{cobrand} =~ /hart/ ) { + $override->{ALLOWED_COBRANDS} = [ 'hart' ]; } $mech->clear_emails_ok; - FixMyStreet::App->model('DB::Problem')->search( + $problem_rs->search( { whensent => undef } - )->update( { whensent => \'ms_current_timestamp()' } ); + )->update( { whensent => \'current_timestamp' } ); $problem->discard_changes; $problem->update( { - council => $test->{ council }, + bodies_str => $test->{ body }, + bodies_missing => $test->{ body_missing }, state => 'confirmed', - confirmed => \'ms_current_timestamp()', - whensent => $test->{ unset_whendef } ? undef : \'ms_current_timestamp()', + confirmed => \'current_timestamp', + whensent => $test->{ unset_whendef } ? undef : \'current_timestamp', category => $test->{ category } || 'potholes', name => $test->{ name }, cobrand => $test->{ cobrand } || 'fixmystreet', + longitude => $test->{longitude} || '-1.5', } ); - FixMyStreet::App->model('DB::Problem')->send_reports(); + FixMyStreet::override_config $override, sub { + $problem_rs->send_reports(); + }; $mech->email_count_is( $test->{ email_count } ); if ( $test->{ email_count } ) { my $email = $mech->get_email; like $email->header('To'), $test->{ to }, 'to line looks correct'; - is $email->header('From'), sprintf('"%s" <%s>', $test->{ name }, $test->{ email } ), 'from line looks correct'; + if ($test->{reply_to}) { + is $email->header('Reply-To'), sprintf('"%s" <%s>', $test->{ name }, $test->{ email } ), 'Reply-To line looks correct'; + like $email->header('From'), qr/"$test->{name}" <fms-report-\d+-\w+\@example.org>/, 'from line looks correct'; + } else { + is $email->header('From'), sprintf('"%s" <%s>', $test->{ name }, $test->{ email } ), 'from line looks correct'; + } like $email->header('Subject'), qr/A Title/, 'subject line looks correct'; - like $email->body, qr/A user of FixMyStreet/, 'email body looks a bit like a report'; - like $email->body, qr/Subject: A Title/, 'more email body checking'; - like $email->body, $test->{ dear }, 'Salutation looks correct'; + my $body = $mech->get_text_body_from_email($email); + like $body, qr/A user of FixMyStreet/, 'email body looks a bit like a report'; + like $body, qr/Subject: A Title/, 'more email body checking'; + like $body, $test->{ dear }, 'Salutation looks correct'; + if ($test->{longitude}) { + like $body, qr{Easting/Northing \(IE\): 297279/362371}; + } else { + like $body, qr{Easting/Northing: }; + } if ( $test->{multiple} ) { - like $email->body, qr/This email has been sent to several councils /, 'multiple council text correct'; + like $body, qr/This email has been sent to several councils /, 'multiple body text correct'; } elsif ( $test->{ missing } ) { - like $email->body, $test->{ missing }, 'missing council information correct'; + like $body, $test->{ missing }, 'missing body information correct'; } if ( $test->{url} ) { - (my $base_url = FixMyStreet->config('BASE_URL')) =~ s{http://}{}; my $id = $problem->id; - like $email->body, qr[$test->{url}$base_url/report/$id], 'URL present is correct'; + like $body, qr[$test->{url}fixmystreet.com/report/$id], 'URL present is correct'; } $problem->discard_changes; @@ -540,12 +604,290 @@ foreach my $test ( { }; } -$problem->comments->delete; -$problem->delete; -$user->delete; +subtest 'check can set mutiple emails as a single contact' => sub { + my $override = { + ALLOWED_COBRANDS => [ 'fixmystreet' ], + BASE_URL => 'http://www.fixmystreet.com', + MAPIT_URL => 'http://mapit.mysociety.org/', + }; -foreach (@contacts) { - $_->delete; -} + my $contact = { + body_id => $body_ids{2651}, # Edinburgh + category => 'trees', + email => '2636@example.com,2636-2@example.com', + }; + $mech->create_contact_ok( %$contact ); -done_testing(); + $mech->clear_emails_ok; + + $problem_rs->search( + { + whensent => undef + } + )->update( { whensent => \'current_timestamp' } ); + + $problem->discard_changes; + $problem->update( { + bodies_str => $contact->{ body_id }, + state => 'confirmed', + confirmed => \'current_timestamp', + whensent => undef, + category => 'trees', + name => 'Test User', + cobrand => 'fixmystreet', + send_fail_count => 0, + } ); + + FixMyStreet::override_config $override, sub { + $problem_rs->send_reports(); + }; + + $mech->email_count_is(1); + my $email = $mech->get_email; + is $email->header('To'), '"City of Edinburgh Council" <2636@example.com>, "City of Edinburgh Council" <2636-2@example.com>', 'To contains two email addresses'; +}; + +subtest 'check can turn on report sent email alerts' => sub { + my $send_confirmation_mail_override = Sub::Override->new( + "FixMyStreet::Cobrand::Default::report_sent_confirmation_email", + sub { return 1; } + ); + $mech->clear_emails_ok; + + $problem_rs->search( + { + whensent => undef + } + )->update( { whensent => \'current_timestamp' } ); + + $problem->discard_changes; + $problem->update( { + bodies_str => $body_ids{2651}, + state => 'confirmed', + confirmed => \'current_timestamp', + whensent => undef, + category => 'potholes', + name => 'Test User', + cobrand => 'fixmystreet', + send_fail_count => 0, + } ); + + $problem_rs->send_reports(); + + $mech->email_count_is( 2 ); + my @emails = $mech->get_email; + my $email = $emails[0]; + + like $email->header('To'),qr/City of Edinburgh Council/, 'to line looks correct'; + is $email->header('From'), '"Test User" <system_user@example.net>', 'from line looks correct'; + like $email->header('Subject'), qr/A Title/, 'subject line looks correct'; + my $body = $mech->get_text_body_from_email($email); + like $body, qr/A user of FixMyStreet/, 'email body looks a bit like a report'; + like $body, qr/Subject: A Title/, 'more email body checking'; + like $body, qr/Dear City of Edinburgh Council/, 'Salutation looks correct'; + + $problem->discard_changes; + ok defined( $problem->whensent ), 'whensent set'; + + $email = $emails[1]; + like $email->header('Subject'), qr/FixMyStreet Report Sent/, 'report sent email title correct'; + $body = $mech->get_text_body_from_email($email); + like $body, qr/to submit your report/, 'report sent body correct'; + + $send_confirmation_mail_override->restore(); +}; + + +subtest 'check iOS app store test reports not sent' => sub { + $mech->clear_emails_ok; + + $problem_rs->search( + { + whensent => undef + } + )->update( { whensent => \'current_timestamp' } ); + + $problem->discard_changes; + $problem->update( { + bodies_str => $body_ids{2651}, + title => 'App store test', + state => 'confirmed', + confirmed => \'current_timestamp', + whensent => undef, + category => 'potholes', + send_fail_count => 0, + } ); + + $problem_rs->send_reports(); + + $mech->email_count_is( 0 ); + + $problem->discard_changes(); + is $problem->state, 'hidden', 'iOS test reports are hidden automatically'; + is $problem->whensent, undef, 'iOS test reports are not sent'; +}; + +subtest 'check reports from abuser not sent' => sub { + $mech->clear_emails_ok; + + $problem_rs->search( + { + whensent => undef + } + )->update( { whensent => \'current_timestamp' } ); + + $problem->discard_changes; + $problem->update( { + bodies_str => $body_ids{2651}, + title => 'Report', + state => 'confirmed', + confirmed => \'current_timestamp', + whensent => undef, + category => 'potholes', + send_fail_count => 0, + } ); + + $problem_rs->send_reports(); + + $mech->email_count_is( 1 ); + + $problem->discard_changes(); + ok $problem->whensent, 'Report has been sent'; + + $problem->update( { + state => 'confirmed', + confirmed => \'current_timestamp', + whensent => undef, + } ); + + my $abuse = FixMyStreet::DB->resultset('Abuse')->create( { email => $problem->user->email } ); + + $mech->clear_emails_ok; + $problem_rs->send_reports(); + + $mech->email_count_is( 0 ); + + $problem->discard_changes(); + is $problem->state, 'hidden', 'reports from abuse user are hidden automatically'; + is $problem->whensent, undef, 'reports from abuse user are not sent'; + + ok $abuse->delete(), 'user removed from abuse table'; +}; + +subtest 'check response templates' => sub { + my $c1 = $mech->create_contact_ok(category => 'Potholes', body_id => $body_ids{2651}, email => 'p'); + my $c2 = $mech->create_contact_ok(category => 'Graffiti', body_id => $body_ids{2651}, email => 'g'); + my $t1 = FixMyStreet::DB->resultset('ResponseTemplate')->create({ body_id => $body_ids{2651}, title => "Title 1", text => "Text 1" }); + my $t2 = FixMyStreet::DB->resultset('ResponseTemplate')->create({ body_id => $body_ids{2651}, title => "Title 2", text => "Text 2" }); + my $t3 = FixMyStreet::DB->resultset('ResponseTemplate')->create({ body_id => $body_ids{2651}, title => "Title 3", text => "Text 3" }); + $t1->add_to_contacts($c1); + $t2->add_to_contacts($c2); + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + is $problem->response_templates, 1, 'Only the global template returned'; + ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE', { category => 'Potholes' }); + is $problem->response_templates, 2, 'Global and pothole templates returned'; +}; + +subtest 'check duplicate reports' => sub { + my ($problem1, $problem2) = $mech->create_problems_for_body(2, $body_ids{2651}, 'TITLE'); + $problem1->set_extra_metadata(duplicate_of => $problem2->id); + $problem1->state('duplicate'); + $problem1->update; + + is $problem1->duplicate_of->title, $problem2->title, 'problem1 returns correct problem from duplicate_of'; + is scalar @{ $problem2->duplicates }, 1, 'problem2 has correct number of duplicates'; + is $problem2->duplicates->[0]->title, $problem1->title, 'problem2 includes problem1 in duplicates'; +}; + +subtest 'generates a tokenised url for a user' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + my $url = $problem->tokenised_url($user); + (my $token = $url) =~ s/\/M\///g; + + like $url, qr/\/M\//, 'problem generates tokenised url'; + + my $token_obj = FixMyStreet::App->model('DB::Token')->find( { + scope => 'email_sign_in', token => $token + } ); + is $token, $token_obj->token, 'token is generated in database with correct scope'; + is $token_obj->data->{r}, $problem->url, 'token has correct redirect data'; +}; + +subtest 'stores params in a token' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + my $url = $problem->tokenised_url($user, { foo => 'bar', baz => 'boo'}); + (my $token = $url) =~ s/\/M\///g; + + my $token_obj = FixMyStreet::App->model('DB::Token')->find( { + scope => 'email_sign_in', token => $token + } ); + + is_deeply $token_obj->data->{p}, { foo => 'bar', baz => 'boo'}, 'token has correct params'; +}; + +subtest 'get report time ago in appropriate format' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + + $problem->update( { + confirmed => DateTime->now->subtract( minutes => 2) + } ); + is $problem->time_ago, '2 minutes', 'problem returns time ago in minutes'; + + $problem->update( { + confirmed => DateTime->now->subtract( hours => 18) + } ); + is $problem->time_ago, '18 hours', 'problem returns time ago in hours'; + + $problem->update( { + confirmed => DateTime->now->subtract( days => 4) + } ); + is $problem->time_ago, '4 days', 'problem returns time ago in days'; + + $problem->update( { + confirmed => DateTime->now->subtract( weeks => 3 ) + } ); + is $problem->time_ago, '3 weeks', 'problem returns time ago in weeks'; + + $problem->update( { + confirmed => DateTime->now->subtract( months => 4 ) + } ); + is $problem->time_ago, '4 months', 'problem returns time ago in months'; + + $problem->update( { + confirmed => DateTime->now->subtract( years => 2 ) + } ); + is $problem->time_ago, '2 years', 'problem returns time ago in years'; +}; + +subtest 'time ago works with other dates' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + + $problem->update( { + lastupdate => DateTime->now->subtract( days => 4) + } ); + is $problem->time_ago('lastupdate'), '4 days', 'problem returns last updated time ago in days'; +}; + +subtest 'return how many days ago a problem was reported' => sub { + my ($problem) = $mech->create_problems_for_body(1, $body_ids{2651}, 'TITLE'); + $problem->update( { + confirmed => DateTime->now->subtract( weeks => 2 ) + } ); + is $problem->days_ago, 14, 'days_ago returns the amount of days'; + + $problem->update( { + lastupdate => DateTime->now->subtract( days => 4) + } ); + + is $problem->days_ago('lastupdate'), 4, 'days_ago allows other dates to be specified'; +}; + +END { + $problem->comments->delete if $problem; + $problem->delete if $problem; + $mech->delete_user( $user ) if $user; + + $mech->delete_body($_) for @bodies; + + done_testing(); +} diff --git a/t/app/model/questionnaire.t b/t/app/model/questionnaire.t index 60b52043a..945a64633 100644 --- a/t/app/model/questionnaire.t +++ b/t/app/model/questionnaire.t @@ -1,5 +1,3 @@ -#!/usr/bin/perl - use strict; use warnings; @@ -8,9 +6,9 @@ use Test::More; use FixMyStreet; use FixMyStreet::TestMech; -my $user = FixMyStreet::App->model('DB::User')->find_or_create( { email => 'test@example.com' } ); +my $user = FixMyStreet::DB->resultset('User')->find_or_create( { email => 'test@example.com' } ); -my $problem = FixMyStreet::App->model('DB::Problem')->create( +my $problem = FixMyStreet::DB->resultset('Problem')->create( { postcode => 'EH99 1SP', latitude => 1, @@ -25,15 +23,13 @@ my $problem = FixMyStreet::App->model('DB::Problem')->create( service => '', cobrand => 'default', cobrand_data => '', - confirmed => \"ms_current_timestamp() - '5 weeks'::interval", - whensent => \"ms_current_timestamp() - '5 weeks'::interval", + confirmed => \"current_timestamp - '5 weeks'::interval", + whensent => \"current_timestamp - '5 weeks'::interval", user => $user, anonymous => 0, } ); -diag $problem->id; - my $mech = FixMyStreet::TestMech->new; for my $test ( @@ -62,6 +58,10 @@ for my $test ( send_email => 1, }, { + state => 'action scheduled', + send_email => 1, + }, + { state => 'in progress', send_email => 1, }, @@ -78,6 +78,18 @@ for my $test ( send_email => 1, }, { + state => 'duplicate', + send_email => 1, + }, + { + state => 'unable to fix', + send_email => 1, + }, + { + state => 'not responsible', + send_email => 1, + }, + { state => 'closed', send_email => 1, }, @@ -92,7 +104,7 @@ for my $test ( $mech->email_count_is(0); - FixMyStreet::App->model('DB::Questionnaire') + FixMyStreet::DB->resultset('Questionnaire') ->send_questionnaires( { site => 'fixmystreet' } ); $mech->email_count_is( $test->{send_email} ); diff --git a/t/app/model/rabx_column.t b/t/app/model/rabx_column.t new file mode 100644 index 000000000..607d578ce --- /dev/null +++ b/t/app/model/rabx_column.t @@ -0,0 +1,23 @@ +use strict; +use warnings; + +use Test::More; + +use_ok "FixMyStreet::DB::RABXColumn"; + +# Test that the class names are correctly normalised +my @tests = ( + ["FixMyStreet::DB::Result::Token", "Token"], + ["FixMyStreet::App::Model::DB::Token", "Token"], +); + +foreach my $test (@tests) { + my ($input, $expected) = @$test; + is( + FixMyStreet::DB::RABXColumn::_get_class_identifier($input), + $expected, + "$input -> $expected" + ); +} + +done_testing(); diff --git a/t/app/model/token.t b/t/app/model/token.t index 12945975e..e31901187 100644 --- a/t/app/model/token.t +++ b/t/app/model/token.t @@ -1,23 +1,10 @@ -#!/usr/bin/perl - use strict; use warnings; -use Test::More tests => 45; +use Test::More; use FixMyStreet; -use FixMyStreet::App; -use mySociety::AuthToken; -use mySociety::DBHandle 'dbh'; - -# set things up so that code using mySociety::DBHandle is happy -FixMyStreet->configure_mysociety_dbhandle(); - -# NOTE - remember that you need to explicitly dbh()->commit after making -# database changes with the mySociety::* modules. - -# create a token using DBIC and check we can read it using AuthToken, and vice -# versa +use FixMyStreet::DB; my %tests = ( nested_hash => { foo => 'bar', and => [ 'baz', 'bundy' ] }, @@ -25,72 +12,71 @@ my %tests = ( scalar => 123, ); -my $token_rs = FixMyStreet::App->model('DB::Token'); +my $token_rs = FixMyStreet::DB->resultset('Token'); -# create using DBIC foreach my $test_data_name ( sort keys %tests ) { my $test_data = $tests{$test_data_name}; - pass "--- testing DBIC create using '$test_data_name'"; + pass "--- testing token creation using '$test_data_name'"; my $dbic_token = $token_rs->create( { scope => 'testing', data => $test_data } ); my $token = $dbic_token->token; ok $token, "stored token '$token'"; - is_deeply $dbic_token->data, $test_data, "data stored correctly using DBIC"; + is_deeply $dbic_token->data, $test_data, "data stored correctly"; - # read back using DBIC + # read back from database is_deeply $token_rs->find( { token => $token, scope => 'testing' } )->data, $test_data, - "data read back correctly with DBIC"; - - # read back using mySociety::AuthToken - is_deeply mySociety::AuthToken::retrieve( 'testing', $token ), - $test_data, "data read back correctly with m::AT"; + "data read back correctly"; # delete token ok $dbic_token->delete, "delete token"; is $token_rs->find( { token => $token, scope => 'testing' } ), undef, - "token gone for DBIC"; - - # read back using mySociety::AuthToken - is mySociety::AuthToken::retrieve( 'testing', $token ), - undef, "token gone with m::AT"; - + "token gone"; } -# create using m::AT -foreach my $test_data_name ( sort keys %tests ) { - my $test_data = $tests{$test_data_name}; - - pass "--- testing m::AT create using '$test_data_name'"; - - my $token = mySociety::AuthToken::store( 'testing', $test_data ); - dbh->commit(); - ok $token, "stored token '$token'"; - - # read back using DBIC - is_deeply $token_rs->find( { token => $token, scope => 'testing' } )->data, - $test_data, - "data read back correctly with DBIC"; - - # read back using mySociety::AuthToken - is_deeply mySociety::AuthToken::retrieve( 'testing', $token ), - $test_data, "data read back correctly with m::AT"; - - # delete token - ok mySociety::AuthToken::destroy( 'testing', $token ), "destroy token"; - dbh->commit(); - - is $token_rs->find( { token => $token, scope => 'testing' } ), - undef, - "token gone for DBIC"; - - # read back using mySociety::AuthToken - is mySociety::AuthToken::retrieve( 'testing', $token ), - undef, "token gone with m::AT"; +# Test that the inflation and deflation works as expected +{ + my $token = + $token_rs->create( { scope => 'testing', data => {} } ); + END { $token->delete() }; + + # Add in temporary check to test that the data is updated as expected. + is_deeply($token->data, {}, "data is empty"); + + # store something in it + $token->update({ data => { foo => 'bar' } }); + $token->discard_changes(); + is_deeply($token->data, { foo => 'bar' }, "data has content"); + + # change the hash stored + $token->update({ data => { baz => 'bundy' } }); + $token->discard_changes(); + is_deeply($token->data, { baz => 'bundy' }, "data has new content"); + + # change the hashref in place + { + my $data = $token->data; + $data->{baz} = 'new'; + $token->data( $data ); + $token->update(); + $token->discard_changes(); + is_deeply($token->data, { baz => 'new' }, "data has been updated"); + } + + # change the hashref in place + { + my $data = $token->data; + $data->{baz} = 'new'; + $token->update({ data => $data }); + $token->discard_changes(); + is_deeply($token->data, { baz => 'new' }, "data has been updated"); + } } + +done_testing(); diff --git a/t/app/model/user.t b/t/app/model/user.t new file mode 100644 index 000000000..d4115d586 --- /dev/null +++ b/t/app/model/user.t @@ -0,0 +1,61 @@ +use strict; +use warnings; + +use Test::More; + +use FixMyStreet::TestMech; +use FixMyStreet::DB; + +my $mech = FixMyStreet::TestMech->new(); +$mech->log_in_ok('test@example.com'); + +my ($problem) = $mech->create_problems_for_body(1, '2504', 'Title', { anonymous => 'f' }); +is $problem->user->latest_anonymity, 0, "User's last report was not anonymous"; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { fixmystreet => '.' } ], + MAPIT_URL => 'http://mapit.uk/', +}, sub { + $mech->get_ok('/around?pc=sw1a1aa'); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->content_like(qr/may_show_name[^>]*checked/); +}; + +($problem) = $mech->create_problems_for_body(1, '2504', 'Title', { anonymous => 't' }); +is $problem->user->latest_anonymity, 1, "User's last report was anonymous"; + +create_update($problem, anonymous => 'f'); +is $problem->user->latest_anonymity, 0, "User's last update was not anonyous"; + +create_update($problem, anonymous => 't'); +is $problem->user->latest_anonymity, 1, "User's last update was anonymous"; + +FixMyStreet::override_config { + ALLOWED_COBRANDS => [ { fixmystreet => '.' } ], + MAPIT_URL => 'http://mapit.uk/', +}, sub { + $mech->get_ok('/around?pc=sw1a1aa'); + $mech->follow_link_ok( { text_regex => qr/skip this step/i, }, "follow 'skip this step' link" ); + $mech->content_like(qr/may_show_name[^>c]*>/); +}; + +END { + $mech->delete_user( $problem->user ) if $problem; + done_testing(); +} + +sub create_update { + my ($problem, %params) = @_; + my $dt = DateTime->now()->add(days => 1); + return FixMyStreet::App->model('DB::Comment')->find_or_create({ + problem_id => $problem->id, + user_id => $problem->user_id, + name => 'Other User', + mark_fixed => 'false', + text => 'This is some update text', + state => 'confirmed', + anonymous => 'f', + created => $dt->ymd . ' ' . $dt->hms, + %params, + }); +} diff --git a/t/app/model/user_planned_report.t b/t/app/model/user_planned_report.t new file mode 100644 index 000000000..95a76615e --- /dev/null +++ b/t/app/model/user_planned_report.t @@ -0,0 +1,52 @@ +use strict; +use warnings; + +use Test::More; + +use FixMyStreet::TestMech; +use FixMyStreet::DB; + +my $mech = FixMyStreet::TestMech->new(); + +my @problems = $mech->create_problems_for_body(1, 2237, 'Title'); +my $problem = $problems[0]; +my $user = $problem->user; +my $user2 = $mech->create_user_ok('other@example.net'); + +is $user->active_planned_reports, 0; +is $user->planned_reports, 0; + +$user->add_to_planned_reports($problem); +is $user->active_planned_reports, 1; +is $user->planned_reports, 1; + +$user->add_to_planned_reports($problem); +is $user->active_planned_reports, 1; +is $user->planned_reports, 1; + +$user->remove_from_planned_reports($problem); +is $user->active_planned_reports, 0; +is $user->planned_reports, 1; + +$user->add_to_planned_reports($problem); +is $user->active_planned_reports, 1; +is $user->planned_reports, 2; + +$user2->add_to_planned_reports($problem); +is $user->active_planned_reports, 0; +is $user->planned_reports, 2; +is $user2->active_planned_reports, 1; +is $user2->planned_reports, 1; + +$user->add_to_planned_reports($problem); +is $user->active_planned_reports, 1; +is $user->planned_reports, 3; +is $user2->active_planned_reports, 0; +is $user2->planned_reports, 1; + +done_testing(); + +END { + $mech->delete_user($user); + $mech->delete_user($user2); +} |