package FixMyStreet::Cobrand::Tester;
use parent 'FixMyStreet::Cobrand::Default';
sub send_moderation_notifications { 0 }
package FixMyStreet::Cobrand::TestTitle;
use parent 'FixMyStreet::Cobrand::Default';
sub moderate_permission_title { 0 }
package main;
use Path::Tiny;
use File::Temp 'tempdir';
use FixMyStreet::TestMech;
my $mech = FixMyStreet::TestMech->new;
$mech->host('www.example.org');
my $BROMLEY_ID = 2482;
my $body = $mech->create_body_ok( $BROMLEY_ID, 'Bromley Council' );
$mech->create_contact_ok( body => $body, category => 'Lost toys', email => 'losttoys@example.net' );
my $dt = DateTime->now;
my $user = $mech->create_user_ok('test-moderation@example.com', name => 'Test User');
my $user2 = $mech->create_user_ok('test-moderation2@example.com', name => 'Test User 2');
sub create_report {
FixMyStreet::DB->resultset('Problem')->create(
{
postcode => 'BR1 3SB',
bodies_str => $body->id,
areas => ",$BROMLEY_ID,",
category => 'Other',
title => 'Good bad good',
detail => 'Good bad bad bad good bad',
used_map => 't',
name => 'Test User 2',
anonymous => 'f',
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_id => $user2->id,
photo => '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg',
extra => { moon => 'waxing full', sent_to => [ 'authority@example.org' ] },
});
}
my $report = create_report();
my $REPORT_URL = '/report/' . $report->id ;
subtest 'Auth' => sub {
subtest 'Unaffiliated user cannot see moderation' => sub {
$mech->get_ok($REPORT_URL);
$mech->content_lacks('Moderat');
$mech->get_ok("$REPORT_URL/moderate");
$mech->content_lacks('Moderat');
$mech->log_in_ok( $user->email );
$mech->get_ok($REPORT_URL);
$mech->content_lacks('Moderat');
$user->update({ from_body => $body->id });
$mech->get_ok($REPORT_URL);
$mech->content_lacks('Moderat');
$mech->get('/contact?m=1&id=' . $report->id);
is $mech->res->code, 400;
$mech->content_lacks('Good bad bad bad');
};
subtest 'Affiliated and permissioned user can see moderation' => sub {
# login and from_body are done in previous test.
$user->user_body_permissions->create({
body => $body,
permission_type => 'moderate',
});
$mech->get_ok($REPORT_URL);
$mech->content_contains('Moderat');
};
};
my %problem_prepopulated = (
problem_show_name => 1,
problem_photo => 1,
problem_title => 'Good bad good',
problem_detail => 'Good bad bad bad good bad',
);
subtest 'Problem moderation' => sub {
subtest 'Post modify title and text' => sub {
$mech->get_ok($REPORT_URL);
$mech->content_lacks('show-moderation');
$mech->follow_link_ok({ text_regex => qr/^Moderate$/ });
$mech->content_contains('show-moderation');
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_title => 'Good good',
problem_detail => 'Good good improved',
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_like(qr/Moderated by Bromley Council/);
$mech->content_lacks('sent_to = ARRAY(0x');
$report->discard_changes;
is $report->title, 'Good good';
is $report->detail, 'Good good improved';
};
subtest 'Revert title and text' => sub {
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_revert_title => 1,
problem_revert_detail => 1,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$report->discard_changes;
is $report->title, 'Good bad good';
is $report->detail, 'Good bad bad bad good bad';
my @history = $report->moderation_original_datas->search(undef, { order_by => 'id' })->all;
is @history, 2, 'Right number of entries';
is $history[0]->title, 'Good bad good', 'Correct original title';
is $history[1]->title, 'Good good', 'Correct second title';
};
subtest 'Post modified title after edited elsewhere' => sub {
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_title => 'Good good',
form_started => 1, # January 1970!
}});
$mech->base_like( qr{\Q/moderate$REPORT_URL\E} );
$mech->content_contains('Good bad good'); # Displayed title
$mech->content_contains('Good good'); # Form edit
$report->discard_changes;
is $report->title, 'Good bad good', 'title unchanged';
};
subtest 'Make anonymous' => sub {
$mech->content_lacks('Reported anonymously');
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_show_name => 0,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_contains('Reported anonymously');
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_show_name => 1,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_lacks('Reported anonymously');
};
subtest 'Hide photo' => sub {
my $UPLOAD_DIR = tempdir( CLEANUP => 1 );
FixMyStreet::override_config {
PHOTO_STORAGE_BACKEND => 'FileSystem',
PHOTO_STORAGE_OPTIONS => {
UPLOAD_DIR => $UPLOAD_DIR,
},
}, sub {
my $image_path = path('t/app/controller/sample.jpg');
$image_path->copy( path($UPLOAD_DIR, '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg') );
$mech->get_ok('/photo/' . $report->id . '.0.jpeg');
$mech->get_ok($REPORT_URL);
$mech->content_contains('Photo of this report');
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_photo => 0,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
my $res = $mech->get('/photo/' . $report->id . '.0.jpeg');
is $res->code, 404, 'got 404';
$mech->get_ok($REPORT_URL);
$mech->content_lacks('Photo of this report');
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_photo => 1,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_contains('Photo of this report');
};
};
subtest 'Hide report' => sub {
$mech->clear_emails_ok;
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_hide => 1,
}});
$mech->base_unlike( qr{/report/}, 'redirected to front page' );
$report->discard_changes;
is $report->state, 'hidden', 'Is hidden';
my $email = $mech->get_email;
is $email->header('To'), '"Test User 2" <' . $user2->email . '>', 'Sent to correct email';
my $url = $mech->get_link_from_email($email);
ok $url, "extracted complain url '$url'";
$mech->get_ok($url);
$mech->content_contains('Good bad bad bad');
# reset
$report->update({ state => 'confirmed' });
};
subtest 'Hide report without sending email' => sub {
FixMyStreet::override_config {
ALLOWED_COBRANDS => [ { 'tester' => '.' } ]
}, sub {
$mech->clear_emails_ok;
$mech->get_ok($REPORT_URL);
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_hide => 1,
}});
$mech->base_unlike( qr{/report/}, 'redirected to front page' );
$report->discard_changes;
is $report->state, 'hidden', 'Is hidden';
ok $mech->email_count_is(0), "Email wasn't sent";
# reset
$report->update({ state => 'confirmed' });
}
};
subtest 'Try and moderate title when not allowed' => sub {
FixMyStreet::override_config {
ALLOWED_COBRANDS => 'testtitle'
}, sub {
$mech->get_ok($REPORT_URL);
$mech->submit_form_ok({ with_fields => {
problem_show_name => 1,
problem_photo => 1,
problem_detail => 'Changed detail',
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_like(qr/Moderated by Bromley Council/);
$report->discard_changes;
is $report->title, 'Good bad good';
is $report->detail, 'Changed detail';
}
};
subtest 'Moderate extra data' => sub {
my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/;
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
'extra.weather' => 'snow',
'extra.moon' => 'waning full',
token => $csrf,
});
$report->discard_changes;
is $report->get_extra_metadata('weather'), 'snow';
is $report->get_extra_metadata('moon'), 'waning full';
my $mod = $report->moderation_original_data;
is $mod->get_extra_metadata('moon'), 'waxing full';
is $mod->get_extra_metadata('weather'), undef;
my $diff = $mod->extra_diff($report, 'moon');
is $diff, "waxning full", 'Correct diff';
};
subtest 'Moderate category' => sub {
$report->update;
my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/;
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
'category' => 'Lost toys',
token => $csrf,
});
$report->discard_changes;
is $report->category, 'Lost toys';
};
subtest 'Moderate state' => sub {
my $mods_count = $report->moderation_original_datas->count;
my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/;
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
state => 'confirmed',
token => $csrf,
});
$report->discard_changes;
is $report->state, 'confirmed', 'state has not changed';
is $report->comments->count, 0, 'same state, no update';
is $report->moderation_original_datas->count, $mods_count, 'No moderation entry either';
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
state => 'in progress',
token => $csrf,
});
$report->discard_changes;
is $report->state, 'in progress', 'state has changed';
is $report->comments->count, 1, 'a new update added';
$report->update({ state => 'confirmed' });
is $report->moderation_original_datas->count, $mods_count, 'No moderation entry, only state changed';
};
subtest 'Moderate location' => sub {
FixMyStreet::override_config {
MAPIT_URL => 'http://mapit.uk/',
ALLOWED_COBRANDS => 'fixmystreet',
}, sub {
my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/;
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
latitude => '53',
longitude => '0.01578',
token => $csrf,
});
$report->discard_changes;
is $report->latitude, 51.4129, 'No change when moved out of area';
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
latitude => '51.4021',
longitude => '0.01578',
token => $csrf,
});
$report->discard_changes;
is $report->latitude, 51.4021, 'Updated when same body';
};
};
};
$mech->content_lacks('Posted anonymously', 'sanity check');
my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/;
subtest 'Edit photos' => sub {
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
photo1 => 'something-wrong',
token => $csrf,
});
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id, {
%problem_prepopulated,
photo1 => '',
upload_fileid => '',
token => $csrf,
});
$report->discard_changes;
is $report->photo, undef;
};
sub create_update {
$report->comments->create({
user => $user2,
name => 'Test User 2',
anonymous => 'f',
photo => '74e3362283b6ef0c48686fb0e161da4043bbcc97.jpeg',
text => 'update good good bad good',
state => 'confirmed',
mark_fixed => 0,
confirmed => $dt,
});
}
my %update_prepopulated = (
update_show_name => 1,
update_photo => 1,
update_text => 'update good good bad good',
);
my $update = create_update();
subtest 'updates' => sub {
subtest 'Update modify text' => sub {
$mech->get_ok($REPORT_URL);
$mech->content_lacks('show-moderation');
$mech->follow_link_ok({ text_regex => qr/^Moderate this update$/ });
$mech->content_contains('show-moderation');
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_text => 'update good good good',
}}) or die $mech->content;
$mech->base_like( qr{\Q$REPORT_URL\E} );
$update->discard_changes;
is $update->text, 'update good good good',
};
subtest 'Revert text' => sub {
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_revert_text => 1,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$update->discard_changes;
is $update->text, 'update good good bad good',
};
subtest 'Make anonymous' => sub {
$mech->content_lacks('Posted anonymously')
or die sprintf '%d (%d)', $update->id, $report->comments->count;
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_show_name => 0,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_contains('Posted anonymously');
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_show_name => 1,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_lacks('Posted anonymously');
};
subtest 'Moderate extra data' => sub {
$update->set_extra_metadata('moon', 'waxing full');
$update->update;
my ($csrf) = $mech->content =~ /meta content="([^"]*)" name="csrf-token"/;
$mech->post_ok('http://www.example.org/moderate/report/' . $report->id . '/update/' . $update->id, {
%update_prepopulated,
'extra.weather' => 'snow',
'extra.moon' => 'waxing full',
token => $csrf,
});
$update->discard_changes;
is $update->get_extra_metadata('weather'), 'snow';
};
subtest 'Hide photo' => sub {
$report->update({ photo => undef }); # hide the main photo so we can just look for text in comment
$mech->get_ok($REPORT_URL);
$mech->content_contains('Photo of this report')
or die $mech->content;
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_photo => 0,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_lacks('Photo of this report');
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_photo => 1,
}});
$mech->base_like( qr{\Q$REPORT_URL\E} );
$mech->content_contains('Photo of this report');
};
subtest 'Hide comment' => sub {
$mech->content_contains('update good good bad good');
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_hide => 1,
}});
$mech->content_lacks('update good good bad good');
};
};
my $update2 = create_update();
subtest 'Update 2' => sub {
$mech->get_ok($REPORT_URL);
$mech->submit_form_ok({ with_fields => {
%update_prepopulated,
update_text => 'update good good good',
}}) or die $mech->content;
$update2->discard_changes;
is $update2->text, 'update good good good',
};
subtest 'Now stop being a staff user' => sub {
$user->update({ from_body => undef });
$mech->get_ok($REPORT_URL);
$mech->content_contains('Moderated by Bromley Council');
$mech->get_ok("$REPORT_URL/moderate/" . $update->id);
$mech->content_lacks('Moderate this update');
};
subtest 'And do it as a superuser' => sub {
$user->update({ is_superuser => 1 });
$mech->get_ok($REPORT_URL);
$mech->submit_form_ok({ with_fields => {
%problem_prepopulated,
problem_title => 'Good good',
problem_detail => 'Good good improved',
}});
$mech->content_contains('Moderated by an administrator');
};
subtest 'Check moderation history in admin' => sub {
$mech->get_ok('/admin/report_edit/' . $report->id);
};
subtest 'Check moderation in user log' => sub {
$mech->get_ok('/admin/users/' . $user->id . '/log');
my $report_id = $report->id;
$mech->content_like(qr/Moderated report.*?$report_id/);
my $update_id = $update->id;
$mech->content_like(qr/Moderated update.*?$update_id/);
};
done_testing();