diff options
-rwxr-xr-x | bin/update-schema | 1 | ||||
-rw-r--r-- | db/downgrade_0046---0045.sql | 6 | ||||
-rw-r--r-- | db/schema.sql | 3 | ||||
-rw-r--r-- | db/schema_0046-user-add-extra.sql | 6 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 3 | ||||
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 7 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/User.pm | 28 | ||||
-rw-r--r-- | perllib/FixMyStreet/Script/Reports.pm | 9 | ||||
-rw-r--r-- | t/app/controller/report_inspect.t | 30 | ||||
-rw-r--r-- | t/app/sendreport/inspection_required.t | 32 | ||||
-rw-r--r-- | templates/web/base/admin/category_edit.html | 11 | ||||
-rw-r--r-- | templates/web/base/admin/user-form.html | 8 | ||||
-rw-r--r-- | templates/web/base/report/display_tools.html | 2 | ||||
-rw-r--r-- | web/js/fixmystreet-admin.js | 10 |
14 files changed, 144 insertions, 12 deletions
diff --git a/bin/update-schema b/bin/update-schema index bb0360fb2..500e771f1 100755 --- a/bin/update-schema +++ b/bin/update-schema @@ -194,6 +194,7 @@ else { # By querying the database schema, we can see where we're currently at # (assuming schema change files are never half-applied, which should be the case) sub get_db_version { + return '0046' if column_exists('users', 'extra'); return '0045' if table_exists('response_priorities'); return '0044' if table_exists('contact_response_templates'); return '0043' if column_exists('users', 'area_id'); diff --git a/db/downgrade_0046---0045.sql b/db/downgrade_0046---0045.sql new file mode 100644 index 000000000..c0cc566af --- /dev/null +++ b/db/downgrade_0046---0045.sql @@ -0,0 +1,6 @@ +BEGIN; + +ALTER TABLE users + DROP COLUMN extra; + +COMMIT; diff --git a/db/schema.sql b/db/schema.sql index 27f4bad13..fe45fb4aa 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -31,7 +31,8 @@ create table users ( title text, twitter_id bigint unique, facebook_id bigint unique, - area_id integer + area_id integer, + extra text ); -- Record details of reporting bodies, including open311 configuration details diff --git a/db/schema_0046-user-add-extra.sql b/db/schema_0046-user-add-extra.sql new file mode 100644 index 000000000..06937237c --- /dev/null +++ b/db/schema_0046-user-add-extra.sql @@ -0,0 +1,6 @@ +BEGIN; + +ALTER TABLE users + ADD COLUMN extra TEXT; + +COMMIT; diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index 46ac10d36..8ec9eeaab 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -385,6 +385,9 @@ sub update_contacts : Private { else { $contact->unset_extra_metadata( 'inspection_required' ); } + if ( $c->get_param('reputation_threshold') ) { + $contact->set_extra_metadata( reputation_threshold => int($c->get_param('reputation_threshold')) ); + } if ( %errors ) { $c->stash->{updated} = _('Please correct the errors below'); diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 34392782b..d56521fde 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -270,6 +270,8 @@ sub delete :Local :Args(1) { $p->lastupdate( \'current_timestamp' ); $p->update; + $p->user->update_reputation(-1); + $c->model('DB::AdminLog')->create( { admin_user => $c->user->email, object_type => 'problem', @@ -315,6 +317,7 @@ sub inspect : Private { my $valid = 1; my $update_text; + my $reputation_change = 0; if ($permissions->{report_inspect}) { foreach (qw/detailed_location detailed_information traffic_information/) { @@ -325,6 +328,7 @@ sub inspect : Private { $update_text = Utils::cleanup_text( $c->get_param('public_update'), { allow_multiline => 1 } ); if ($update_text) { $problem->set_extra_metadata( inspected => 1 ); + $reputation_change = 1; } else { $valid = 0; $c->stash->{errors} ||= []; @@ -362,6 +366,9 @@ sub inspect : Private { } if ($valid) { + if ( $reputation_change != 0 ) { + $problem->user->update_reputation($reputation_change); + } $problem->update; if ( defined($update_text) ) { $problem->add_to_comments( { diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm index 2a2d0d5e3..8d42d5926 100644 --- a/perllib/FixMyStreet/DB/Result/User.pm +++ b/perllib/FixMyStreet/DB/Result/User.pm @@ -26,20 +26,22 @@ __PACKAGE__->add_columns( { data_type => "text", is_nullable => 1 }, "password", { data_type => "text", default_value => "", is_nullable => 0 }, - "flagged", - { data_type => "boolean", default_value => \"false", is_nullable => 0 }, "from_body", { data_type => "integer", is_foreign_key => 1, is_nullable => 1 }, + "flagged", + { data_type => "boolean", default_value => \"false", is_nullable => 0 }, "title", { data_type => "text", is_nullable => 1 }, - "facebook_id", - { data_type => "bigint", is_nullable => 1 }, "twitter_id", { data_type => "bigint", is_nullable => 1 }, + "facebook_id", + { data_type => "bigint", is_nullable => 1 }, "is_superuser", { data_type => "boolean", default_value => \"false", is_nullable => 0 }, "area_id", { data_type => "integer", is_nullable => 1 }, + "extra", + { data_type => "text", is_nullable => 1 }, ); __PACKAGE__->set_primary_key("id"); __PACKAGE__->add_unique_constraint("users_email_key", ["email"]); @@ -100,11 +102,17 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-08-03 13:52:28 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SX8BS91mWHoOm2oWdNth1w +# Created by DBIx::Class::Schema::Loader v0.07035 @ 2016-09-16 14:22:10 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:7wfF1VnZax2QTXCIPXr+vg + +__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn"); +__PACKAGE__->rabx_column('extra'); use Moo; use mySociety::EmailUtil; +use namespace::clean -except => [ 'meta' ]; + +with 'FixMyStreet::Roles::Extra'; __PACKAGE__->many_to_many( planned_reports => 'user_planned_reports', 'report' ); @@ -370,4 +378,12 @@ sub is_planned_report { return $self->active_planned_reports->find({ id => $problem->id }); } +sub update_reputation { + my ( $self, $change ) = @_; + + my $reputation = $self->get_extra_metadata('reputation') || 0; + $self->set_extra_metadata( reputation => $reputation + $change); + $self->update; +} + 1; diff --git a/perllib/FixMyStreet/Script/Reports.pm b/perllib/FixMyStreet/Script/Reports.pm index 8d3b2ddbc..7d614bc30 100644 --- a/perllib/FixMyStreet/Script/Reports.pm +++ b/perllib/FixMyStreet/Script/Reports.pm @@ -145,9 +145,16 @@ sub send(;$) { my $inspection_required = $sender_info->{contact}->get_extra_metadata('inspection_required') if $sender_info->{contact}; if ( $inspection_required ) { + my $reputation_threshold = $sender_info->{contact}->get_extra_metadata('reputation_threshold') || 0; + my $reputation_threshold_met = 0; + if ( $reputation_threshold > 0 ) { + my $user_reputation = $row->user->get_extra_metadata('reputation') || 0; + $reputation_threshold_met = $user_reputation >= $reputation_threshold; + } unless ( $row->get_extra_metadata('inspected') || - $row->user->has_permission_to( trusted => $row->bodies_str_ids ) + $row->user->has_permission_to( trusted => $row->bodies_str_ids ) || + $reputation_threshold_met ) { $skip = 1; debug_print("skipped because not yet inspected", $row->id) if $debug_mode; diff --git a/t/app/controller/report_inspect.t b/t/app/controller/report_inspect.t index 6d6ec6559..393a8beb2 100644 --- a/t/app/controller/report_inspect.t +++ b/t/app/controller/report_inspect.t @@ -6,8 +6,8 @@ use FixMyStreet::TestMech; my $mech = FixMyStreet::TestMech->new; -my $brum = $mech->create_body_ok(2514, 'Birmingham City Council'); -my $oxon = $mech->create_body_ok(2237, 'Oxfordshire County Council'); +my $brum = $mech->create_body_ok(2514, 'Birmingham City Council', id => 2514); +my $oxon = $mech->create_body_ok(2237, 'Oxfordshire County Council', id => 2237); my $contact = $mech->create_contact_ok( body_id => $oxon->id, category => 'Cows', email => 'cows@example.net' ); my $rp = FixMyStreet::DB->resultset("ResponsePriority")->create({ body => $oxon, @@ -62,6 +62,16 @@ FixMyStreet::override_config { is $report->get_extra_metadata('inspected'), 1, 'report marked as inspected'; }; + subtest "test positive reputation" => sub { + $report->unset_extra_metadata('inspected'); + $report->update; + my $reputation = $report->user->get_extra_metadata("reputation"); + $mech->get_ok("/report/$report_id/inspect"); + $mech->submit_form_ok({ button => 'save_inspected', with_fields => { public_update => "This is a public update." } }); + $report->discard_changes; + is $report->user->get_extra_metadata('reputation'), $reputation+1, "User reputation was increased"; + }; + subtest "test update is required when instructing" => sub { $report->unset_extra_metadata('inspected'); $report->update; @@ -107,6 +117,22 @@ FixMyStreet::override_config { } }; +FixMyStreet::override_config { + MAPIT_URL => 'http://mapit.mysociety.org/', + ALLOWED_COBRANDS => 'oxfordshire', +}, sub { + subtest "test negative reputation" => sub { + my $reputation = $report->user->get_extra_metadata("reputation"); + + $mech->get_ok("/report/$report_id"); + $mech->submit_form( button => 'remove_from_site' ); + + $report->discard_changes; + is $report->user->get_extra_metadata('reputation'), $reputation-1, "User reputation was decreased"; + }; +}; + + END { $mech->delete_body($oxon); $mech->delete_body($brum); diff --git a/t/app/sendreport/inspection_required.t b/t/app/sendreport/inspection_required.t index 88a48e991..f9d40d39f 100644 --- a/t/app/sendreport/inspection_required.t +++ b/t/app/sendreport/inspection_required.t @@ -69,6 +69,38 @@ subtest 'Uninspected report is sent when made by trusted user' => sub { $report->discard_changes; $mech->email_count_is( 1 ); ok $report->whensent, 'Report marked as sent'; + is $report->get_extra_metadata('inspected'), undef, 'Report not marked as inspected'; +}; + +subtest 'Uninspected report isn’t sent when user rep is too low' => sub { + $mech->clear_emails_ok; + $report->whensent( undef ); + $report->update; + + $user->user_body_permissions->delete; + $user->set_extra_metadata(reputation => 15); + $user->update; + + $contact->set_extra_metadata(reputation_threshold => 20); + $contact->update; + + FixMyStreet::DB->resultset('Problem')->send_reports(); + + $report->discard_changes; + $mech->email_count_is( 0 ); + is $report->whensent, undef, 'Report hasn’t been sent'; +}; + +subtest 'Uninspected report is sent when user rep is high enough' => sub { + $user->set_extra_metadata(reputation => 21); + $user->update; + + FixMyStreet::DB->resultset('Problem')->send_reports(); + + $report->discard_changes; + $mech->email_count_is( 1 ); + ok $report->whensent, 'Report marked as sent'; + is $report->get_extra_metadata('inspected'), undef, 'Report not marked as inspected'; }; done_testing(); diff --git a/templates/web/base/admin/category_edit.html b/templates/web/base/admin/category_edit.html index 6aec0c132..05fa2ca4e 100644 --- a/templates/web/base/admin/category_edit.html +++ b/templates/web/base/admin/category_edit.html @@ -19,7 +19,7 @@ [% END %] </p> -<form method="post" action="[% c.uri_for('body', body_id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8"> +<form method="post" action="[% c.uri_for('body', body_id ) %]" enctype="application/x-www-form-urlencoded" accept-charset="utf-8" id="category_edit"> <p><strong>[% loc('Category:') %] </strong>[% contact.category | html %] <input type="hidden" name="category" value="[% contact.category | html %]" > <input type="hidden" name="token" value="[% csrf_token %]" > @@ -47,6 +47,15 @@ [% END %] </p> + [% IF c.cobrand.moniker != 'zurich' %] + <p [% 'class=hidden' UNLESS contact.get_extra_metadata('inspection_required') %]> + <label> + [% loc('Reputation threshold:') %] + <input type="text" name="reputation_threshold" id="reputation_threshold" value="[% contact.get_extra_metadata('reputation_threshold') | html %]" size="30"> + </label> + </p> + [% END %] + <p><strong>[% loc('Note:') %] </strong><textarea name="note" rows="3" cols="40"></textarea> [% IF body.can_be_devolved %] diff --git a/templates/web/base/admin/user-form.html b/templates/web/base/admin/user-form.html index 40e0b510a..87324666d 100644 --- a/templates/web/base/admin/user-form.html +++ b/templates/web/base/admin/user-form.html @@ -110,6 +110,14 @@ </label> [% END %] </li> + <li> + <div class="admin-hint"> + <p> + [% loc("Reports from users with high enough reputation will be sent immediately without requiring inspection. Each category's threshold can be managed on its edit page. Users earn reputation when a report they have made is marked as inspected by inspectors.") %] + </p> + </div> + [% loc('Reputation:') %] [% user.get_extra_metadata('reputation') %] + </li> [% END %] [% IF c.user.is_superuser %] diff --git a/templates/web/base/report/display_tools.html b/templates/web/base/report/display_tools.html index 052ffb8a5..82f7d0ac3 100644 --- a/templates/web/base/report/display_tools.html +++ b/templates/web/base/report/display_tools.html @@ -3,7 +3,7 @@ [% IF c.user_exists AND c.cobrand.users_can_hide AND c.user.belongs_to_body( problem.bodies_str ) %] <li><form method="post" action="/report/delete/[% problem.id %]" id="remove-from-site-form"> <input type="hidden" name="token" value="[% csrf_token %]"> - <input type="submit" id="key-tool-report-abuse" class="abuse" data-confirm="[% loc('Are you sure?') %]" value="[% loc('Remove from site') %]"> + <input type="submit" id="key-tool-report-abuse" class="abuse" data-confirm="[% loc('Are you sure?') %]" name="remove_from_site" value="[% loc('Remove from site') %]"> </form></li> [% ELSIF c.cobrand.moniker != 'zurich' %] <li><a rel="nofollow" id="key-tool-report-abuse" class="abuse" href="[% c.uri_for( '/contact', { id => problem.id } ) %]">[% loc('Report abuse' ) %]</a></li> diff --git a/web/js/fixmystreet-admin.js b/web/js/fixmystreet-admin.js index aa79a9b46..6f4580feb 100644 --- a/web/js/fixmystreet-admin.js +++ b/web/js/fixmystreet-admin.js @@ -79,5 +79,15 @@ $(function(){ var show_area = $(this).val() == $(this).find("[data-originally-selected]").val(); $("form#user_edit select#area_id").closest("li").toggle(show_area); }); + + // On category edit page, hide the reputation input if inspection isn't required + $("form#category_edit #inspection_required").change(function() { + var $p = $("form#category_edit #reputation_threshold").closest("p"); + if (this.checked) { + $p.removeClass("hidden"); + } else { + $p.addClass("hidden"); + } + }); }); |