aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet')
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm3
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm101
-rw-r--r--perllib/FixMyStreet/DB/RABXColumn.pm98
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm23
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm22
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm45
-rw-r--r--perllib/FixMyStreet/DB/Result/Token.pm25
-rw-r--r--perllib/FixMyStreet/TestMech.pm20
8 files changed, 214 insertions, 123 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 3d3ddce1e..6018dfa80 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -956,6 +956,9 @@ sub check_for_errors : Private {
delete $field_errors{name};
my $report = $c->stash->{report};
$report->title( Utils::cleanup_text( substr($report->detail, 0, 25) ) );
+ if ( ! $c->req->param('phone') ) {
+ $field_errors{phone} = _("This information is required");
+ }
}
# FIXME: need to check for required bromley fields here
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
index ffdc1feab..450786c88 100644
--- a/perllib/FixMyStreet/Cobrand/Zurich.pm
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -8,6 +8,47 @@ use RABX;
use strict;
use warnings;
+=head1 NAME
+
+Zurich FixMyStreet cobrand
+
+=head1 DESCRIPTION
+
+This module provides the specific functionality for the Zurich FMS cobrand.
+
+=head1 DEVELOPMENT NOTES
+
+The admin for Zurich is different to the other cobrands. To access it you need
+to be logged in as a user associated with an appropriate body.
+
+You can create the bodies needed to develop by running the 't/cobrand/zurich.t'
+test script with the three C<$mech->delete...> lines at the end commented out.
+This should leave you with the bodies and users correctly set up.
+
+The entries will be something like this (but with different ids).
+
+ Bodies:
+ id | name | parent | endpoint
+ ----+---------------+--------+---------------------------
+ 1 | Zurich | |
+ 2 | Division 1 | 1 | division@example.org
+ 3 | Subdivision A | 2 | subdivision@example.org
+ 4 | External Body | | external_body@example.org
+
+ Users:
+ id | email | from_body
+ ----+------------------+-----------
+ 2 | dm1@example.org | 2
+ 3 | sdm1@example.org | 3
+
+The passwords for the users is 'secret'.
+
+Note: the password hashes are salted with the user's id so cannot be easily
+changed. High ids have been used so that it should not conflict with anything
+you already have, and the countres set so that they shouldn't in future.
+
+=cut
+
sub shorten_recency_if_new_greater_than_fixed {
return 0;
}
@@ -356,19 +397,38 @@ sub admin_report_edit {
}
- # Problem updates upon submission
+ # If super or sdm check that the token is correct before proceeding
if ( ($type eq 'super' || $type eq 'dm') && $c->req->param('submit') ) {
$c->forward('check_token');
+ }
+
+ # All types of users can add internal notes
+ if ( ($type eq 'super' || $type eq 'dm' || $type eq 'sdm') && $c->req->param('submit') ) {
+ # If there is a new note add it as a comment to the problem (with is_internal_note set true in extra).
+ if ( my $new_internal_note = $c->req->params->{new_internal_note} ) {
+ $problem->add_to_comments( {
+ text => $new_internal_note,
+ user => $c->user->obj,
+ state => 'hidden', # seems best fit, should not be shown publicly
+ mark_fixed => 0,
+ problem_state => $problem->state,
+ anonymous => 1,
+ extra => { is_internal_note => 1 },
+ } );
+ }
+ }
+ # Problem updates upon submission
+ if ( ($type eq 'super' || $type eq 'dm') && $c->req->param('submit') ) {
# Predefine the hash so it's there for lookups
# XXX Note you need to shallow copy each time you set it, due to a bug? in FilterColumn.
my $extra = $problem->extra || {};
- $extra->{internal_notes} = $c->req->param('internal_notes');
$extra->{publish_photo} = $c->req->params->{publish_photo} || 0;
$extra->{third_personal} = $c->req->params->{third_personal} || 0;
# Make sure we have a copy of the original detail field
$extra->{original_detail} = $problem->detail if !$extra->{original_detail} && $c->req->params->{detail} && $problem->detail ne $c->req->params->{detail};
+
# Workflow things
my $redirect = 0;
my $new_cat = $c->req->params->{category};
@@ -462,14 +522,6 @@ sub admin_report_edit {
$db_update = 1;
}
- my $extra = $problem->extra || {};
- $extra->{internal_notes} ||= '';
- if ($c->req->param('internal_notes') && $c->req->param('internal_notes') ne $extra->{internal_notes}) {
- $extra->{internal_notes} = $c->req->param('internal_notes');
- $problem->extra( { %$extra } );
- $db_update = 1;
- }
-
$problem->update if $db_update;
# Add new update from status_update
@@ -592,10 +644,31 @@ sub admin_stats {
);
if ( $c->req->params->{export} ) {
- my $problems = $c->model('DB::Problem')->search( { %params }, { columns => [ 'id', 'created', 'latitude', 'longitude', 'cobrand', 'category' ] } );
- my $body = "ID,Created,E,N,Category\n";
- while (my $report = $problems->next) {
- $body .= join( ',', $report->id, $report->created, $report->local_coords, $report->category ) . "\n";
+ my $problems = $c->model('DB::Problem')->search(
+ {%params},
+ {
+ columns => [
+ 'id', 'created',
+ 'latitude', 'longitude',
+ 'cobrand', 'category',
+ 'state', 'user_id',
+ 'external_body'
+ ]
+ }
+ );
+ my $body = "ID,Created,E,N,Category,Status,UserID,External Body\n";
+ while ( my $report = $problems->next ) {
+ my $external_body;
+ my $body_name = "";
+ if ( $external_body = $report->body($c) ) {
+ $body_name = $external_body->name;
+ }
+ $body .= join( ',',
+ $report->id, $report->created,
+ $report->local_coords, $report->category,
+ $report->state, $report->user_id,
+ "\"$body_name\"" )
+ . "\n";
}
$c->res->content_type('text/csv; charset=utf-8');
$c->res->body($body);
diff --git a/perllib/FixMyStreet/DB/RABXColumn.pm b/perllib/FixMyStreet/DB/RABXColumn.pm
new file mode 100644
index 000000000..5f1583018
--- /dev/null
+++ b/perllib/FixMyStreet/DB/RABXColumn.pm
@@ -0,0 +1,98 @@
+package FixMyStreet::DB::RABXColumn;
+
+use strict;
+use warnings;
+
+use IO::String;
+use RABX;
+
+=head1 NAME
+
+FixMyStreet::DB::RABXColumn
+
+=head2 DESCRIPTION
+
+This is a helper component that will setup the RABX serialisation for some
+fields. This is useful for when you want to persist some data structure such as
+hashrefs etc.
+
+This code will also change the default FilterColumn behaviour so that whenever
+your set a column, or specify a RABX'd column in an ->update the value is saved
+to the database. The default behaviour is to check if the value is already set,
+and for hashrefs this means that changes to the contents are missed as it is
+still the same hashref.
+
+By putting all this code in one place there is also much less repetition.
+
+=cut
+
+# Store which columns are RABX cols.
+# $RABX_COLUMNS{$class}{$col} = 1
+my %RABX_COLUMNS = ();
+
+sub _get_class_identifier {
+ my $class = ref $_[0] || $_[0];
+ $class =~ s/.*?(\w+)$/$1/;
+ return $class;
+}
+
+=head1 METHODS
+
+=head2 rabx_column
+
+ # In one of your ::Result:: modules
+ __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
+ __PACKAGE__->rabx_column('data');
+
+This sets up the filtering to and from the database, and also changes the
+set_filtered_column behaviour to not trust the cache.
+
+=cut
+
+sub rabx_column {
+ my ($class, $col) = @_;
+
+ # Apply the filtering for this column
+ $class->filter_column(
+ $col => {
+ filter_from_storage => sub {
+ my $self = shift;
+ my $ser = shift;
+ return undef unless defined $ser;
+ utf8::encode($ser) if utf8::is_utf8($ser);
+ my $h = new IO::String($ser);
+ return RABX::wire_rd($h);
+ },
+ filter_to_storage => sub {
+ my $self = shift;
+ my $data = shift;
+ my $ser = '';
+ my $h = new IO::String($ser);
+ RABX::wire_wr( $data, $h );
+ return $ser;
+ },
+ }
+ );
+
+ # store that this column is a RABX column.
+ $RABX_COLUMNS{ _get_class_identifier($class) }{$col} = 1;
+}
+
+
+sub set_filtered_column {
+ my ($self, $col, $val) = @_;
+
+ my $class = ref $self;
+
+ # because filtered objects may be expensive to marshall for storage there
+ # is a cache that attempts to detect if they have changed or not. For us
+ # this cache breaks things and our marshalling is cheap, so clear it when
+ # trying set a column.
+ delete $self->{_filtered_column}{$col}
+ if $RABX_COLUMNS{ _get_class_identifier($class) }{$col};
+
+ return $self->next::method($col, $val);
+}
+
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index c712ad4e1..2d5b6b2c3 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -85,32 +85,13 @@ __PACKAGE__->belongs_to(
# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:D/+UWcF7JO/EkCiJaAHUOw
-__PACKAGE__->filter_column(
- extra => {
- filter_from_storage => sub {
- my $self = shift;
- my $ser = shift;
- return undef unless defined $ser;
- utf8::encode($ser) if utf8::is_utf8($ser);
- my $h = new IO::String($ser);
- return RABX::wire_rd($h);
- },
- filter_to_storage => sub {
- my $self = shift;
- my $data = shift;
- my $ser = '';
- my $h = new IO::String($ser);
- RABX::wire_wr( $data, $h );
- return $ser;
- },
- }
-);
+__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
+__PACKAGE__->rabx_column('extra');
use DateTime::TimeZone;
use Image::Size;
use Moose;
use namespace::clean -except => [ 'meta' ];
-use RABX;
with 'FixMyStreet::Roles::Abuser';
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index 2e1287a21..eca028c9b 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -60,25 +60,7 @@ __PACKAGE__->belongs_to(
# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hq/BFHDEu4OUI4MSy3OyHg
-__PACKAGE__->filter_column(
- extra => {
- filter_from_storage => sub {
- my $self = shift;
- my $ser = shift;
- return undef unless defined $ser;
- utf8::encode($ser) if utf8::is_utf8($ser);
- my $h = new IO::String($ser);
- return RABX::wire_rd($h);
- },
- filter_to_storage => sub {
- my $self = shift;
- my $data = shift;
- my $ser = '';
- my $h = new IO::String($ser);
- RABX::wire_wr( $data, $h );
- return $ser;
- },
- }
-);
+__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
+__PACKAGE__->rabx_column('extra');
1;
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index c8b53e2d1..f14a29f56 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -135,54 +135,15 @@ __PACKAGE__->has_one(
{ cascade_copy => 0, cascade_delete => 0 },
);
-__PACKAGE__->filter_column(
- extra => {
- filter_from_storage => sub {
- my $self = shift;
- my $ser = shift;
- return undef unless defined $ser;
- utf8::encode($ser) if utf8::is_utf8($ser);
- my $h = new IO::String($ser);
- return RABX::wire_rd($h);
- },
- filter_to_storage => sub {
- my $self = shift;
- my $data = shift;
- my $ser = '';
- my $h = new IO::String($ser);
- RABX::wire_wr( $data, $h );
- return $ser;
- },
- }
-);
-
-__PACKAGE__->filter_column(
- geocode => {
- filter_from_storage => sub {
- my $self = shift;
- my $ser = shift;
- return undef unless defined $ser;
- utf8::encode($ser) if utf8::is_utf8($ser);
- my $h = new IO::String($ser);
- return RABX::wire_rd($h);
- },
- filter_to_storage => sub {
- my $self = shift;
- my $data = shift;
- my $ser = '';
- my $h = new IO::String($ser);
- RABX::wire_wr( $data, $h );
- return $ser;
- },
- }
-);
+__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
+__PACKAGE__->rabx_column('extra');
+__PACKAGE__->rabx_column('geocode');
use DateTime::TimeZone;
use Image::Size;
use Moose;
use namespace::clean -except => [ 'meta' ];
use Utils;
-use RABX;
with 'FixMyStreet::Roles::Abuser';
diff --git a/perllib/FixMyStreet/DB/Result/Token.pm b/perllib/FixMyStreet/DB/Result/Token.pm
index 028300842..5525fe7a5 100644
--- a/perllib/FixMyStreet/DB/Result/Token.pm
+++ b/perllib/FixMyStreet/DB/Result/Token.pm
@@ -34,8 +34,6 @@ __PACKAGE__->set_primary_key("scope", "token");
# use mySociety::DBHandle qw(dbh);
use mySociety::AuthToken;
-use IO::String;
-use RABX;
=head1 NAME
@@ -54,26 +52,9 @@ ms_current_timestamp.
=cut
-__PACKAGE__->filter_column(
- data => {
- filter_from_storage => sub {
- my $self = shift;
- my $ser = shift;
- return undef unless defined $ser;
- utf8::encode($ser) if utf8::is_utf8($ser);
- my $h = new IO::String($ser);
- return RABX::wire_rd($h);
- },
- filter_to_storage => sub {
- my $self = shift;
- my $data = shift;
- my $ser = '';
- my $h = new IO::String($ser);
- RABX::wire_wr( $data, $h );
- return $ser;
- },
- }
-);
+__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
+__PACKAGE__->rabx_column('data');
+
sub new {
my ( $class, $attrs ) = @_;
diff --git a/perllib/FixMyStreet/TestMech.pm b/perllib/FixMyStreet/TestMech.pm
index e91c6a1d6..be8f004a5 100644
--- a/perllib/FixMyStreet/TestMech.pm
+++ b/perllib/FixMyStreet/TestMech.pm
@@ -87,8 +87,8 @@ sub log_in_ok {
my $user = $mech->create_user_ok($email);
- # store the old password and then change it
- my $old_password = $user->password;
+ # remember the old password and then change it to a known one
+ my $old_password = $user->password || '';
$user->update( { password => 'secret' } );
# log in
@@ -99,7 +99,19 @@ sub log_in_ok {
$mech->logged_in_ok;
# restore the password (if there was one)
- $user->update( { password => $old_password } ) if $old_password;
+ if ($old_password) {
+
+ # Use store_column and then make_column_dirty to bypass the filters that
+ # would hash the password, otherwise the password required ito log in
+ # would be the hash of the previous one.
+ $user->store_column("password", $old_password);
+ $user->make_column_dirty("password");
+ $user->update();
+
+ # Belt and braces, check that the password has been correctly saved.
+ die "password not correctly restored after log_in_ok"
+ if $user->password ne $old_password;
+ }
return $user;
}
@@ -296,7 +308,7 @@ sub extract_location {
$meta = $mech->extract_problem_meta;
-Returns the problem meta information ( submitted by, at etc ) from a
+Returns the problem meta information ( submitted by, at etc ) from a
problem report page
=cut