diff options
| -rwxr-xr-x | bin/update-schema | 1 | ||||
| -rw-r--r-- | db/downgrade_0038---0037.sql | 2 | ||||
| -rw-r--r-- | db/schema.sql | 3 | ||||
| -rw-r--r-- | db/schema_0038-time-spent.sql | 2 | ||||
| -rw-r--r-- | perllib/FixMyStreet/App/Controller/Admin.pm | 13 | ||||
| -rw-r--r-- | perllib/FixMyStreet/Cobrand/Zurich.pm | 54 | ||||
| -rw-r--r-- | perllib/FixMyStreet/DB/Result/AdminLog.pm | 2 | ||||
| -rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 12 | ||||
| -rw-r--r-- | perllib/FixMyStreet/TestMech.pm | 1 | ||||
| -rw-r--r-- | t/app/controller/questionnaire.t | 2 | ||||
| -rw-r--r-- | t/cobrand/zurich.t | 22 | ||||
| -rw-r--r-- | templates/web/zurich/admin/report_edit-sdm.html | 18 | ||||
| -rw-r--r-- | templates/web/zurich/admin/report_edit.html | 17 | ||||
| -rw-r--r-- | web/cobrands/zurich/base.scss | 7 | 
14 files changed, 147 insertions, 9 deletions
diff --git a/bin/update-schema b/bin/update-schema index d98fe6e9c..1af08b002 100755 --- a/bin/update-schema +++ b/bin/update-schema @@ -195,6 +195,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 '0038' if column_exists('admin_log', 'time_spent');      return '0037' if table_exists('response_templates');      return '0036' if constraint_contains('problem_cobrand_check', 'a-z0-9_');      return '0035' if column_exists('problem', 'bodies_missing'); diff --git a/db/downgrade_0038---0037.sql b/db/downgrade_0038---0037.sql new file mode 100644 index 000000000..11a0d11ad --- /dev/null +++ b/db/downgrade_0038---0037.sql @@ -0,0 +1,2 @@ +alter table admin_log  +    drop column time_spent; diff --git a/db/schema.sql b/db/schema.sql index e87a2aafe..72fccd7f3 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -427,7 +427,8 @@ create table admin_log (      action text not null,      whenedited timestamp not null default current_timestamp,      user_id int references users(id) null, -    reason text not null default '' +    reason text not null default '', +    time_spent int not null default 0  );   create table moderation_original_data ( diff --git a/db/schema_0038-time-spent.sql b/db/schema_0038-time-spent.sql new file mode 100644 index 000000000..093eb4086 --- /dev/null +++ b/db/schema_0038-time-spent.sql @@ -0,0 +1,2 @@ +alter table admin_log  +    add column time_spent int not null default 0; diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm index be705110b..5ebeffc11 100644 --- a/perllib/FixMyStreet/App/Controller/Admin.pm +++ b/perllib/FixMyStreet/App/Controller/Admin.pm @@ -1339,13 +1339,24 @@ Adds an entry into the admin_log table using the current user.  =cut  sub log_edit : Private { -    my ( $self, $c, $id, $object_type, $action ) = @_; +    my ( $self, $c, $id, $object_type, $action, $time_spent ) = @_; + +    $time_spent //= 0; +    $time_spent = 0 if $time_spent < 0; + +    my $user_object = do { +        my $auth_user = $c->user; +        $auth_user ? $auth_user->get_object : undef; +    }; +      $c->model('DB::AdminLog')->create(          {              admin_user => $c->forward('get_user'), +            $user_object ? ( user => $user_object ) : (), # as (rel => undef) doesn't work              object_type => $object_type,              action => $action,              object_id => $id, +            time_spent => $time_spent,          }      )->insert();  } diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm index 46d57158b..c039deb0d 100644 --- a/perllib/FixMyStreet/Cobrand/Zurich.pm +++ b/perllib/FixMyStreet/Cobrand/Zurich.pm @@ -5,6 +5,7 @@ use DateTime;  use POSIX qw(strcoll);  use RABX;  use Scalar::Util 'blessed'; +use DateTime::Format::Pg;  use strict;  use warnings; @@ -277,13 +278,46 @@ sub get_or_check_overdue {      return $self->overdue($problem);  } +=head1 C<set_problem_state> + +If the state has changed, sets the state and calls C::Admin's C<log_edit> action. +If the state hasn't changed, defers to update_admin_log (to update time_spent if any). + +Returns either undef or the AdminLog entry created. + +=cut +  sub set_problem_state {      my ($self, $c, $problem, $new_state) = @_; -    return if $new_state eq $problem->state; +    return $self->update_admin_log($c, $problem) if $new_state eq $problem->state;      $problem->state( $new_state );      $c->forward( 'log_edit', [ $problem->id, 'problem', "state change to $new_state" ] );  } +=head1 C<update_admin_log> + +Calls C::Admin's C<log_edit> if either a) text is provided, or b) there has +been time_spent on the task.  As set_problem_state will already call log_edit +if required, don't call this as well. + +Returns either undef or the AdminLog entry created. + +=cut + +sub update_admin_log { +    my ($self, $c, $problem, $text) = @_; + +    my $time_spent = ( ($c->req->param('time_spent') // 0) + 0 ); +    $c->req->param('time_spent' => 0); # explicitly zero this to avoid duplicates + +    if (!$text) { +        return unless $time_spent; +        $text = "Logging time_spent"; +    } + +    $c->forward( 'log_edit', [ $problem->id, 'problem', $text, $time_spent ] ); +} +  # Specific administrative displays  sub admin_pages { @@ -503,6 +537,7 @@ sub admin_report_edit {              $problem->whensent( undef );              $problem->set_extra_metadata(changed_category => 1);              $internal_note_text = "Weitergeleitet von $old_cat an $new_cat"; +            $self->update_admin_log($c, $problem, "Changed category from $old_cat to $new_cat");              $redirect = 1 if $cat->body_id ne $body->id;          } elsif ( my $subdiv = $c->get_param('body_subdivision') ) {              $problem->set_extra_metadata_if_undefined( moderated_overdue => $self->overdue( $problem ) ); @@ -576,6 +611,10 @@ sub admin_report_edit {              } );          } +        # Just update if time_spent still hasn't been logged +        # (this will only happen if no other update_admin_log has already been called) +        $self->update_admin_log($c, $problem); +          if ( $redirect ) {              $c->detach('index');          } @@ -748,7 +787,10 @@ sub admin_stats {      if ($y && $m) {          $c->stash->{start_date} = DateTime->new( year => $y, month => $m, day => 1 );          $c->stash->{end_date} = $c->stash->{start_date} + DateTime::Duration->new( months => 1 ); -        $date_params{created} = { '>=', $c->stash->{start_date}, '<', $c->stash->{end_date} }; +        $date_params{created} = { +            '>=', DateTime::Format::Pg->format_datetime($c->stash->{start_date}),  +            '<',  DateTime::Format::Pg->format_datetime($c->stash->{end_date}), +        };      }      my %params = ( @@ -760,6 +802,8 @@ sub admin_stats {          my $problems = $c->model('DB::Problem')->search(              {%date_params},              { +                join => 'admin_log_entries', +                distinct => 1,                  columns => [                      'id',       'created',                      'latitude', 'longitude', @@ -771,10 +815,11 @@ sub admin_stats {                      'whensent', 'lastupdate',                      'service',                      'extra', -                ], +                    { sum_time_spent => { sum => 'admin_log_entries.time_spent' } }, +                ]              }          ); -        my $body = "Report ID,Created,Sent to Agency,Last Updated,E,N,Category,Status,UserID,External Body,Title,Detail,Media URL,Interface Used,Council Response\n"; +        my $body = "Report ID,Created,Sent to Agency,Last Updated,E,N,Category,Status,UserID,External Body,Time Spent,Title,Detail,Media URL,Interface Used,Council Response\n";          require Text::CSV;          my $csv = Text::CSV->new({ binary => 1 });          while ( my $report = $problems->next ) { @@ -802,6 +847,7 @@ sub admin_stats {                  $report->local_coords, $report->category,                  $report->state,        $report->user_id,                  $body_name, +                $report->get_column('sum_time_spent') || 0,                  $report->title,                  $detail,                  $media_url, diff --git a/perllib/FixMyStreet/DB/Result/AdminLog.pm b/perllib/FixMyStreet/DB/Result/AdminLog.pm index fcf909692..d60915cfc 100644 --- a/perllib/FixMyStreet/DB/Result/AdminLog.pm +++ b/perllib/FixMyStreet/DB/Result/AdminLog.pm @@ -37,6 +37,8 @@ __PACKAGE__->add_columns(    { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },    "reason",    { data_type => "text", default_value => "", is_nullable => 0 }, +  "time_spent", +  { data_type => "integer", default_value => "0", is_nullable => 0 },  );  __PACKAGE__->set_primary_key("id");  __PACKAGE__->belongs_to( diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index d3a30db4e..637f4acbf 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -886,6 +886,18 @@ __PACKAGE__->has_many(    }  ); +sub get_time_spent { +    my $self = shift; +    my $admin_logs = $self->admin_log_entries->search({}, +        { +            group_by => 'object_id', +            columns => [ +                { sum_time_spent => { sum => 'time_spent' } }, +            ] +        })->single; +    return $admin_logs ? $admin_logs->get_column('sum_time_spent') : 0; +} +  # we need the inline_constructor bit as we don't inherit from Moose  __PACKAGE__->meta->make_immutable( inline_constructor => 0 ); diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm index 8325b07a8..1035a47ba 100644 --- a/perllib/FixMyStreet/TestMech.pm +++ b/perllib/FixMyStreet/TestMech.pm @@ -165,6 +165,7 @@ sub delete_user {          $a->delete;      }      $_->delete for $user->comments; +    $_->delete for $user->admin_logs;      $user->delete;      return 1; diff --git a/t/app/controller/questionnaire.t b/t/app/controller/questionnaire.t index d4fc9c74b..2a89454d5 100644 --- a/t/app/controller/questionnaire.t +++ b/t/app/controller/questionnaire.t @@ -276,7 +276,7 @@ foreach my $test (          $questionnaire->discard_changes;          is $report->state, $result eq 'unknown' ? $test->{problem_state} : $result;          is $report->send_questionnaire, $another; -        ok DateTime::Format::Pg->format_datetime( $report->lastupdate) gt $report_time, 'lastupdate changed' +        ok (DateTime::Format::Pg->format_datetime( $report->lastupdate) gt $report_time, 'lastupdate changed')              unless $test->{fields}{been_fixed} eq 'Unknown' || $test->{lastupdate_static};          is $questionnaire->old_state, $test->{problem_state};          is $questionnaire->new_state, $result; diff --git a/t/cobrand/zurich.t b/t/cobrand/zurich.t index 02f502d31..5dbbc3bbe 100644 --- a/t/cobrand/zurich.t +++ b/t/cobrand/zurich.t @@ -705,8 +705,6 @@ subtest "test stats" => sub {              $mech->content_contains('fixed - council');              $mech->content_contains(',hidden,');          } - -        $mech->log_out_ok;      };  }; @@ -764,6 +762,26 @@ subtest 'email images to external partners' => sub {          };  }; +subtest 'time_spent' => sub { +    FixMyStreet::override_config { +        ALLOWED_COBRANDS => [ 'zurich' ], +    }, 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; +  END {      $mech->delete_body($subdivision);      $mech->delete_body($division); diff --git a/templates/web/zurich/admin/report_edit-sdm.html b/templates/web/zurich/admin/report_edit-sdm.html index 82bbeba23..6e952022a 100644 --- a/templates/web/zurich/admin/report_edit-sdm.html +++ b/templates/web/zurich/admin/report_edit-sdm.html @@ -46,6 +46,10 @@  <li><span class="mock-label">[% loc('Phone:') %]</span> [% IF problem.user.phone %][% problem.user.phone | html %][% ELSE %]<em>[% loc('None') %]</em>[% END %]</li>  <li><span class="mock-label">[% loc('Created:') %]</span> [% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</li> +<li> +    <label>[% loc('Time spent (in minutes):') %]</label> [% problem.get_time_spent %] +</li> +  [% IF problem.photo %]  <li><img alt="" src="[% c.cobrand.base_url %]/photo/[% problem.photo %].temp.jpeg"></li>  [% END %] @@ -60,6 +64,20 @@  </ul> +<p class="report-edit-action"> +<label for="time_spent">[% loc('Time spent (in minutes):') %]</label> +<input type="text" name="time_spent" id="form_time_spent" style="width: 4em" value="0"> +<script> +    $(function () { +        $('#form_time_spent').spinner({ +            spin: function (e, ui) { +                if (ui.value < 0) { return false } +            } +        }); +    }); +</script> +</p> +  <p class="cf">      <input style="float:left" type="submit" name="Submit changes" value="[% loc('Submit changes') %]" >      <input style="float:right" type="submit" name="no_more_updates" value="[% loc('No further updates') %]"> diff --git a/templates/web/zurich/admin/report_edit.html b/templates/web/zurich/admin/report_edit.html index d2c1760ff..89f27dcda 100644 --- a/templates/web/zurich/admin/report_edit.html +++ b/templates/web/zurich/admin/report_edit.html @@ -60,6 +60,9 @@  <li><span class="mock-label">[% loc('Phone:') %]</span> [% IF problem.user.phone %][% problem.user.phone | html %][% ELSE %]<em>[% loc('None') %]</em>[% END %]</li>  <li><span class="mock-label">[% loc('Created:') %]</span> [% PROCESS format_date this_date=problem.created %] [% problem.created.hms %]</li> +<li> +    <label>[% loc('Time spent (in minutes):') %]</label> [% problem.get_time_spent %] +</li>  [% IF problem.photo %]  <li> @@ -215,6 +218,20 @@ Ihre Stadt Zürich  [% END %] +<p> +<label for="time_spent">[% loc('Time spent (in minutes):') %]</label> +<input type="text" name="time_spent" id="form_time_spent" style="width: 4em" value="0"> +<script> +    $(function () { +        $('#form_time_spent').spinner({ +            spin: function (e, ui) { +                if (ui.value < 0) { return false } +            } +        }); +    }); +</script> +</p> +  <p align="right">  [% IF problem.state == 'planned' %]  <input type="submit" name="publish_response" value="[% loc('Publish the response') %]"> diff --git a/web/cobrands/zurich/base.scss b/web/cobrands/zurich/base.scss index 10eed0b11..013c071bd 100644 --- a/web/cobrands/zurich/base.scss +++ b/web/cobrands/zurich/base.scss @@ -179,6 +179,13 @@ h4.static-with-rule {      }  } +.ui-spinner input { +    // stop jQuery UI spinner inputs from inheriting FMS input styles +    padding: 1px; +    border: none; +    border-radius: 0; +} +  @media print {      #site-header .container {          position: relative;  | 
