aboutsummaryrefslogtreecommitdiffstats
path: root/perllib
diff options
context:
space:
mode:
Diffstat (limited to 'perllib')
-rw-r--r--perllib/CrossSell.pm14
-rw-r--r--perllib/FixMyStreet.pm37
-rw-r--r--perllib/FixMyStreet/App.pm8
-rw-r--r--perllib/FixMyStreet/App/Controller/Admin.pm81
-rw-r--r--perllib/FixMyStreet/App/Controller/Contact.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/Dashboard.pm126
-rwxr-xr-xperllib/FixMyStreet/App/Controller/FakeMapit.pm4
-rw-r--r--perllib/FixMyStreet/App/Controller/My.pm3
-rw-r--r--perllib/FixMyStreet/App/Controller/Photo.pm14
-rw-r--r--perllib/FixMyStreet/App/Controller/Report/New.pm18
-rw-r--r--perllib/FixMyStreet/App/View/Web.pm8
-rw-r--r--perllib/FixMyStreet/Cobrand.pm15
-rw-r--r--perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm33
-rw-r--r--perllib/FixMyStreet/Cobrand/Default.pm7
-rw-r--r--perllib/FixMyStreet/Cobrand/FiksGataMi.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMindelo.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/FixMyStreet.pm2
-rw-r--r--perllib/FixMyStreet/Cobrand/Hart.pm72
-rw-r--r--perllib/FixMyStreet/Cobrand/Oxfordshire.pm3
-rw-r--r--perllib/FixMyStreet/Cobrand/UKCouncils.pm17
-rw-r--r--perllib/FixMyStreet/Cobrand/Zurich.pm226
-rw-r--r--perllib/FixMyStreet/DB/RABXColumn.pm98
-rw-r--r--perllib/FixMyStreet/DB/Result/Alert.pm8
-rw-r--r--perllib/FixMyStreet/DB/Result/AlertSent.pm6
-rw-r--r--perllib/FixMyStreet/DB/Result/Body.pm22
-rw-r--r--perllib/FixMyStreet/DB/Result/BodyArea.pm6
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm46
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm28
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm72
-rw-r--r--perllib/FixMyStreet/DB/Result/Questionnaire.pm6
-rw-r--r--perllib/FixMyStreet/DB/Result/Token.pm25
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm10
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/AlertType.pm3
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm18
-rw-r--r--perllib/FixMyStreet/Map/GoogleOL.pm22
-rw-r--r--perllib/FixMyStreet/SendReport/Email.pm18
-rw-r--r--perllib/FixMyStreet/TestMech.pm20
-rw-r--r--perllib/Open311.pm1
-rw-r--r--perllib/Open311/GetServiceRequestUpdates.pm16
39 files changed, 855 insertions, 266 deletions
diff --git a/perllib/CrossSell.pm b/perllib/CrossSell.pm
index f9cde6936..231bb9361 100644
--- a/perllib/CrossSell.pm
+++ b/perllib/CrossSell.pm
@@ -142,6 +142,15 @@ details. You can unsubscribe at any time.</p>
EOF
}
+sub display_survey_link {
+ return <<EOF;
+<h1 style="padding-top:0.5em">User Survey</h1>
+<p>
+We're running a survey to help us understand who uses our sites. If you have 10-15 minutes to spare then we'd be grateful if you could <a href="http://questions.mysociety.org/S/fms/w/" target="_blank">take part</a>.
+</p>
+EOF
+}
+
# Not currently used, needs more explanation and testing; perhaps in future.
sub display_gny_groups {
my ($lon, $lat) = @_;
@@ -201,6 +210,11 @@ sub display_advert ($$;$%) {
#EOF
#unless (defined $data{done_tms} && $data{done_tms}==1) {
+ $c->stash->{scratch} = 'advert=survey';
+ return '<div style="margin: 0 5em; border-top: dotted 1px #666666;">'
+ . display_survey_link()
+ . '</div>';
+
$c->stash->{scratch} = 'advert=news';
my $auth_signature = '';
unless (defined $data{emailunvalidated} && $data{emailunvalidated}==1) {
diff --git a/perllib/FixMyStreet.pm b/perllib/FixMyStreet.pm
index be488a796..cc5286bbb 100644
--- a/perllib/FixMyStreet.pm
+++ b/perllib/FixMyStreet.pm
@@ -7,6 +7,7 @@ use Path::Class;
my $ROOT_DIR = file(__FILE__)->parent->parent->absolute->resolve;
use Readonly;
+use Sub::Override;
use mySociety::Config;
use mySociety::DBHandle;
@@ -85,6 +86,42 @@ sub config {
return exists $CONFIG{$key} ? $CONFIG{$key} : undef;
}
+sub override_config($&) {
+ my $config = shift;
+ my $code = \&{shift @_};
+
+ mySociety::MaPit::configure($config->{MAPIT_URL}) if $config->{MAPIT_URL};
+
+ # For historical reasons, we have two ways of asking for config variables.
+ # Override them both, I'm sure we'll find time to get rid of one eventually.
+ my $override_guard1 = Sub::Override->new(
+ "FixMyStreet::config",
+ sub {
+ my ($class, $key) = @_;
+ return { %CONFIG, %$config } unless $key;
+ return $config->{$key} if exists $config->{$key};
+ my $orig_config = mySociety::Config::load_default();
+ return $orig_config->{$key} if exists $orig_config->{$key};
+ }
+ );
+ my $override_guard2 = Sub::Override->new(
+ "mySociety::Config::get",
+ sub ($;$) {
+ my ($key, $default) = @_;
+ return $config->{$key} if exists $config->{$key};
+ my $orig_config = mySociety::Config::load_default();
+ return $orig_config->{$key} if exists $orig_config->{$key};
+ return $default if @_ == 2;
+ }
+ );
+
+ $code->();
+
+ $override_guard1->restore();
+ $override_guard2->restore();
+ mySociety::MaPit::configure() if $config->{MAPIT_URL};;
+}
+
=head2 dbic_connect_info
$connect_info = FixMyStreet->dbic_connect_info();
diff --git a/perllib/FixMyStreet/App.pm b/perllib/FixMyStreet/App.pm
index cf766348f..4f70d2c68 100644
--- a/perllib/FixMyStreet/App.pm
+++ b/perllib/FixMyStreet/App.pm
@@ -208,6 +208,14 @@ sub setup_request {
DateTime->DefaultLocale( 'en_US' );
}
+ if (FixMyStreet->test_mode) {
+ # Is there a better way of altering $c->config that may have
+ # override_config involved?
+ $c->setup_finished(0);
+ $c->config( %{ FixMyStreet->config() } );
+ $c->setup_finished(1);
+ }
+
return $c;
}
diff --git a/perllib/FixMyStreet/App/Controller/Admin.pm b/perllib/FixMyStreet/App/Controller/Admin.pm
index 133c83024..9c0018f38 100644
--- a/perllib/FixMyStreet/App/Controller/Admin.pm
+++ b/perllib/FixMyStreet/App/Controller/Admin.pm
@@ -9,6 +9,8 @@ use POSIX qw(strftime strcoll);
use Digest::SHA qw(sha1_hex);
use mySociety::EmailUtil qw(is_valid_email);
use if !$ENV{TRAVIS}, 'Image::Magick';
+use DateTime::Format::Strptime;
+
use FixMyStreet::SendReport;
@@ -130,9 +132,21 @@ sub index : Path : Args(0) {
$c->stash->{categories} = $c->cobrand->problems->categories_summary();
+ $c->stash->{total_bodies} = $c->model('DB::Body')->count();
+
return 1;
}
+sub config_page : Path( 'config' ) : Args(0) {
+ my ($self, $c) = @_;
+ my $dir = $c->stash->{additional_template_paths}->[0];
+ my $git_version = `cd $dir && git describe --tags`;
+ chomp $git_version;
+ $c->stash(
+ git_version => $git_version,
+ );
+}
+
sub timeline : Path( 'timeline' ) : Args(0) {
my ($self, $c) = @_;
@@ -411,7 +425,7 @@ sub update_contacts : Private {
sub body_params : Private {
my ( $self, $c ) = @_;
- my @fields = qw/name endpoint jurisdiction api_key send_method send_comments suppress_alerts send_extended_statuses comment_user_id can_be_devolved parent/;
+ my @fields = qw/name endpoint jurisdiction api_key send_method send_comments suppress_alerts send_extended_statuses comment_user_id can_be_devolved parent deleted/;
my %defaults = map { $_ => '' } @fields;
%defaults = ( %defaults,
send_comments => 0,
@@ -420,6 +434,7 @@ sub body_params : Private {
send_extended_statuses => 0,
can_be_devolved => 0,
parent => undef,
+ deleted => 0,
);
my %params = map { $_ => $c->req->param($_) || $defaults{$_} } @fields;
return \%params;
@@ -430,6 +445,7 @@ sub display_contacts : Private {
my $contacts = $c->stash->{body}->contacts->search(undef, { order_by => [ 'category' ] } );
$c->stash->{contacts} = $contacts;
+ $c->stash->{live_contacts} = $contacts->search({ deleted => 0 });
if ( $c->req->param('text') && $c->req->param('text') == 1 ) {
$c->stash->{template} = 'admin/council_contacts.txt';
@@ -546,10 +562,15 @@ sub reports : Path('reports') {
$query->{'-or'} = [
'me.areas' => { like => "%,$1,%" }
];
+ } elsif ($search =~ /^ref:(\d+)$/) {
+ $query->{'-or'} = [
+ 'me.external_id' => { like => "%$1%" }
+ ];
} else {
$query->{'-or'} = [
'me.id' => $search_n,
'user.email' => { ilike => $like_search },
+ 'me.external_id' => { ilike => $like_search },
'me.name' => { ilike => $like_search },
'me.title' => { ilike => $like_search },
detail => { ilike => $like_search },
@@ -749,11 +770,15 @@ sub report_edit : Path('report_edit') : Args(1) {
$problem->user( $user );
}
+ # Deal with photos
if ( $c->req->param('remove_photo') ) {
$problem->photo(undef);
}
+ if ( $new_state eq 'hidden' ) {
+ unlink glob FixMyStreet->path_to( 'web', 'photo', $problem->id . '.*' );
+ }
- if ( $new_state eq 'confirmed' and $old_state eq 'unconfirmed' ) {
+ if ( $problem->is_visible() and $old_state eq 'unconfirmed' ) {
$problem->confirmed( \'ms_current_timestamp()' );
}
@@ -894,7 +919,7 @@ sub update_edit : Path('update_edit') : Args(1) {
$update->name( $c->req->param('name') || '' );
$update->text( $c->req->param('text') );
$update->anonymous( $c->req->param('anonymous') );
- $update->state( $c->req->param('state') );
+ $update->state( $new_state );
if ( $c->req->param('email') ne $update->user->email ) {
my $user =
@@ -914,6 +939,10 @@ sub update_edit : Path('update_edit') : Args(1) {
}
}
+ if ( $new_state eq 'hidden' ) {
+ unlink glob FixMyStreet->path_to( 'web', 'photo', 'c', $update->id . '.*' );
+ }
+
$update->update;
$c->stash->{status_message} = '<p><em>' . _('Updated!') . '</em></p>';
@@ -954,6 +983,11 @@ sub user_add : Path('user_edit') : Args(0) {
$c->forward('check_token');
+ if ( $c->cobrand->moniker eq 'zurich' and $c->req->param('email') eq '' ) {
+ $c->stash->{field_errors}->{email} = _('Please enter a valid email');
+ return 1;
+ }
+
return unless $c->req->param('name') && $c->req->param('email');
my $user = $c->model('DB::User')->find_or_create( {
@@ -1001,6 +1035,11 @@ sub user_edit : Path('user_edit') : Args(1) {
$user->email( $c->req->param('email') );
$user->from_body( $c->req->param('body') || undef );
$user->flagged( $c->req->param('flagged') || 0 );
+
+ if ( $c->cobrand->moniker eq 'zurich' and $user->email eq '' ) {
+ $c->stash->{field_errors}->{email} = _('Please enter a valid email');
+ return 1;
+ }
$user->update;
if ($edited) {
@@ -1024,8 +1063,20 @@ sub flagged : Path('flagged') : Args(0) {
$c->stash->{problems} = [ $problems->all ];
my $users = $c->model('DB::User')->search( { flagged => 1 } );
+ my @users = $users->all;
+ my %email2user = map { $_->email => $_ } @users;
+ $c->stash->{users} = [ @users ];
- $c->stash->{users} = $users;
+ my @abuser_emails = $c->model('DB::Abuse')->all();
+
+ foreach my $email (@abuser_emails) {
+ # Slight abuse of the boolean flagged value
+ if ($email2user{$email->email}) {
+ $email2user{$email->email}->flagged( 2 );
+ } else {
+ push @{$c->stash->{users}}, { email => $email->email, flagged => 2 };
+ }
+ }
return 1;
}
@@ -1042,26 +1093,15 @@ sub stats : Path('stats') : Args(0) {
if ( $c->req->param('getcounts') ) {
my ( $start_date, $end_date, @errors );
+ my $parser = DateTime::Format::Strptime->new( pattern => '%d/%m/%Y' );
- eval {
- $start_date = DateTime->new(
- year => $c->req->param('start_date_year'),
- month => $c->req->param('start_date_month'),
- day => $c->req->param('start_date_day'),
- );
- };
+ $start_date = $parser-> parse_datetime ( $c->req->param('start_date') );
- push @errors, _('Invalid start date') if $@;
+ push @errors, _('Invalid start date') unless defined $start_date;
- eval {
- $end_date = DateTime->new(
- year => $c->req->param('end_date_year'),
- month => $c->req->param('end_date_month'),
- day => $c->req->param('end_date_day'),
- );
- };
+ $end_date = $parser-> parse_datetime ( $c->req->param('end_date') ) ;
- push @errors, _('Invalid end date') if $@;
+ push @errors, _('Invalid end date') unless defined $end_date;
$c->stash->{errors} = \@errors;
$c->stash->{start_date} = $start_date;
@@ -1148,6 +1188,7 @@ sub set_allowed_pages : Private {
'users' => [_('Users'), 5],
'flagged' => [_('Flagged'), 6],
'stats' => [_('Stats'), 6],
+ 'config' => [ undef, undef ],
'user_edit' => [undef, undef],
'body' => [undef, undef],
'body_edit' => [undef, undef],
diff --git a/perllib/FixMyStreet/App/Controller/Contact.pm b/perllib/FixMyStreet/App/Controller/Contact.pm
index 3fcb449d2..7ba18ed2d 100644
--- a/perllib/FixMyStreet/App/Controller/Contact.pm
+++ b/perllib/FixMyStreet/App/Controller/Contact.pm
@@ -149,7 +149,7 @@ sub prepare_params_for_email : Private {
my $problem_url = $base_url . '/report/' . $c->stash->{update}->problem_id
. '#update_' . $c->stash->{update}->id;
- my $admin_url = " - $admin_url" . 'update_edit/' . $c->stash->{update}->id
+ my $admin_url = " - $admin_url" . '/update_edit/' . $c->stash->{update}->id
if $admin_url;
$c->stash->{message} .= sprintf(
" \n\n[ Complaint about update %d on report %d - %s%s ]",
@@ -161,7 +161,7 @@ sub prepare_params_for_email : Private {
elsif ( $c->stash->{problem} ) {
my $problem_url = $base_url . '/report/' . $c->stash->{problem}->id;
- $admin_url = " - $admin_url" . 'report_edit/' . $c->stash->{problem}->id
+ $admin_url = " - $admin_url" . '/report_edit/' . $c->stash->{problem}->id
if $admin_url;
$c->stash->{message} .= sprintf(
" \n\n[ Complaint about report %d - %s%s ]",
diff --git a/perllib/FixMyStreet/App/Controller/Dashboard.pm b/perllib/FixMyStreet/App/Controller/Dashboard.pm
index 028b9aadd..b47a1f54b 100644
--- a/perllib/FixMyStreet/App/Controller/Dashboard.pm
+++ b/perllib/FixMyStreet/App/Controller/Dashboard.pm
@@ -121,16 +121,22 @@ sub index : Path : Args(0) {
if $c->stash->{category};
$c->stash->{where} = \%where;
my $prob_where = { %where };
- $prob_where->{state} = $prob_where->{'problem.state'};
+ $prob_where->{'me.state'} = $prob_where->{'problem.state'};
delete $prob_where->{'problem.state'};
$c->stash->{prob_where} = $prob_where;
+ my $dtf = $c->model('DB')->storage->datetime_parser;
+
my %counts;
my $t = DateTime->today;
- $counts{wtd} = $c->forward( 'updates_search', [ $t->subtract( days => $t->dow - 1 ) ] );
- $counts{week} = $c->forward( 'updates_search', [ DateTime->now->subtract( weeks => 1 ) ] );
- $counts{weeks} = $c->forward( 'updates_search', [ DateTime->now->subtract( weeks => 4 ) ] );
- $counts{ytd} = $c->forward( 'updates_search', [ DateTime->today->set( day => 1, month => 1 ) ] );
+ $counts{wtd} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( $t->subtract( days => $t->dow - 1 ) ) ] );
+ $counts{week} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( DateTime->now->subtract( weeks => 1 ) ) ] );
+ $counts{weeks} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( DateTime->now->subtract( weeks => 4 ) ) ] );
+ $counts{ytd} = $c->forward( 'updates_search',
+ [ $dtf->format_datetime( DateTime->today->set( day => 1, month => 1 ) ) ] );
$c->stash->{problems} = \%counts;
@@ -138,17 +144,19 @@ sub index : Path : Args(0) {
$c->stash->{q_state} = $c->req->param('state') || '';
if ( $c->stash->{q_state} eq 'fixed' ) {
- $prob_where->{state} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
+ $prob_where->{'me.state'} = [ FixMyStreet::DB::Result::Problem->fixed_states() ];
} elsif ( $c->stash->{q_state} ) {
- $prob_where->{state} = $c->stash->{q_state};
- $prob_where->{state} = { IN => [ 'planned', 'action scheduled' ] }
- if $prob_where->{state} eq 'action scheduled';
+ $prob_where->{'me.state'} = $c->stash->{q_state};
+ $prob_where->{'me.state'} = { IN => [ 'planned', 'action scheduled' ] }
+ if $prob_where->{'me.state'} eq 'action scheduled';
}
my $params = {
%$prob_where,
- 'me.confirmed' => { '>=', DateTime->now->subtract( days => 30 ) },
+ 'me.confirmed' => { '>=', $dtf->format_datetime( DateTime->now->subtract( days => 30 ) ) },
};
- my @problems = $c->cobrand->problems->search( $params )->all;
+ my $problems_rs = $c->cobrand->problems->search( $params );
+ my @problems = $problems_rs->all;
+
my %problems;
foreach (@problems) {
if ($_->confirmed >= DateTime->now->subtract(days => 7)) {
@@ -160,6 +168,102 @@ sub index : Path : Args(0) {
}
}
$c->stash->{lists} = \%problems;
+
+ if ( $c->req->params->{export} ) {
+ $self->export_as_csv($c, $problems_rs, $body);
+ }
+}
+
+sub export_as_csv {
+ my ($self, $c, $problems_rs, $body) = @_;
+ require Text::CSV;
+ my $problems = $problems_rs->search(
+ {}, { prefetch => 'comments' });
+
+ my $filename = do {
+ my %where = (
+ body => $body->id,
+ category => $c->stash->{category},
+ state => $c->stash->{q_state},
+ ward => $c->stash->{ward},
+ );
+ join '-',
+ $c->req->uri->host,
+ map {
+ my $value = $where{$_};
+ (defined $value and length $value) ? ($_, $value) : ()
+ } sort keys %where };
+
+ my $csv = Text::CSV->new();
+ $csv->combine(
+ 'Report ID',
+ 'Title',
+ 'Detail',
+ 'User Name',
+ 'Category',
+ 'Created',
+ 'Confirmed',
+ 'Acknowledged',
+ 'Fixed',
+ 'Closed',
+ 'Status',
+ 'Latitude', 'Longitude',
+ 'Nearest Postcode',
+ 'Report URL',
+ );
+ my @body = ($csv->string);
+
+ my $fixed_states = FixMyStreet::DB::Result::Problem->fixed_states;
+ my $closed_states = FixMyStreet::DB::Result::Problem->closed_states;
+
+ while ( my $report = $problems->next ) {
+ my $external_body;
+ my $body_name = "";
+ if ( $external_body = $report->body($c) ) {
+ # seems to be a zurich specific thing
+ $body_name = $external_body->name if ref $external_body;
+ }
+ my $hashref = $report->as_hashref($c);
+
+ $hashref->{user_name_display} = $report->anonymous?
+ '(anonymous)' : $report->user->name;
+
+ for my $comment ($report->comments) {
+ my $problem_state = $comment->problem_state or next;
+ next if $problem_state eq 'confirmed';
+ $hashref->{acknowledged_pp} //= $c->cobrand->prettify_dt( $comment->created );
+ $hashref->{fixed_pp} //= $fixed_states->{ $problem_state } ?
+ $c->cobrand->prettify_dt( $comment->created ): undef;
+ if ($closed_states->{ $problem_state }) {
+ $hashref->{closed_pp} = $c->cobrand->prettify_dt( $comment->created );
+ last;
+ }
+ }
+
+ $csv->combine(
+ @{$hashref}{
+ 'id',
+ 'title',
+ 'detail',
+ 'user_name_display',
+ 'category',
+ 'created_pp',
+ 'confirmed_pp',
+ 'acknowledged_pp',
+ 'fixed_pp',
+ 'closed_pp',
+ 'state',
+ 'latitude', 'longitude',
+ 'postcode',
+ },
+ (join '', $c->cobrand->base_url_for_report($report), $report->url),
+ );
+
+ push @body, $csv->string;
+ }
+ $c->res->content_type('text/csv; charset=utf-8');
+ $c->res->header('content-disposition' => "attachment; filename=${filename}.csv");
+ $c->res->body( join "\n", @body );
}
sub updates_search : Private {
diff --git a/perllib/FixMyStreet/App/Controller/FakeMapit.pm b/perllib/FixMyStreet/App/Controller/FakeMapit.pm
index bc46df712..253c75ba4 100755
--- a/perllib/FixMyStreet/App/Controller/FakeMapit.pm
+++ b/perllib/FixMyStreet/App/Controller/FakeMapit.pm
@@ -12,13 +12,13 @@ FixMyStreet::App::Controller::FakeMapit - Catalyst Controller
A controller to fake mapit when we don't have it. If you set MAPIT_URL to
.../fakemapit/ it should all just work, with a mapit that assumes the whole
-world is one area, with ID 161 and name "Default Area".
+world is one area, with ID 161 and name "Everywhere".
=head1 METHODS
=cut
-my $area = { "name" => "Default Area", "type" => "ZZZ", "id" => 161 };
+my $area = { "name" => "Everywhere", "type" => "ZZZ", "id" => 161 };
sub output : Private {
my ( $self, $c, $data ) = @_;
diff --git a/perllib/FixMyStreet/App/Controller/My.pm b/perllib/FixMyStreet/App/Controller/My.pm
index c00264315..bbef1f8d8 100644
--- a/perllib/FixMyStreet/App/Controller/My.pm
+++ b/perllib/FixMyStreet/App/Controller/My.pm
@@ -45,6 +45,7 @@ sub my : Path : Args(0) {
} )->page( $p_page );
while ( my $problem = $rs->next ) {
+ $c->stash->{has_content}++;
push @$pins, {
latitude => $problem->latitude,
longitude => $problem->longitude,
@@ -64,7 +65,9 @@ sub my : Path : Args(0) {
order_by => { -desc => 'confirmed' },
rows => 50
} )->page( $u_page );
+
my @updates = $rs->all;
+ $c->stash->{has_content} += scalar @updates;
$c->stash->{updates} = \@updates;
$c->stash->{updates_pager} = $rs->pager;
diff --git a/perllib/FixMyStreet/App/Controller/Photo.pm b/perllib/FixMyStreet/App/Controller/Photo.pm
index 8b00d1533..09afabecf 100644
--- a/perllib/FixMyStreet/App/Controller/Photo.pm
+++ b/perllib/FixMyStreet/App/Controller/Photo.pm
@@ -30,17 +30,19 @@ Display a photo
=cut
-sub during :LocalRegex('^([0-9a-f]{40})\.temp\.jpeg$') {
+sub during :LocalRegex('^([0-9a-f]{40})\.(temp|fulltemp)\.jpeg$') {
my ( $self, $c ) = @_;
- my ( $hash ) = @{ $c->req->captures };
+ my ( $hash, $size ) = @{ $c->req->captures };
my $file = file( $c->config->{UPLOAD_DIR}, "$hash.jpeg" );
my $photo = $file->slurp;
- if ( $c->cobrand->default_photo_resize ) {
- $photo = _shrink( $photo, $c->cobrand->default_photo_resize );
- } else {
- $photo = _shrink( $photo, '250x250' );
+ if ( $size eq 'temp' ) {
+ if ( $c->cobrand->default_photo_resize ) {
+ $photo = _shrink( $photo, $c->cobrand->default_photo_resize );
+ } else {
+ $photo = _shrink( $photo, '250x250' );
+ }
}
$c->forward( 'output', [ $photo ] );
diff --git a/perllib/FixMyStreet/App/Controller/Report/New.pm b/perllib/FixMyStreet/App/Controller/Report/New.pm
index 128ef2790..a419e9cc1 100644
--- a/perllib/FixMyStreet/App/Controller/Report/New.pm
+++ b/perllib/FixMyStreet/App/Controller/Report/New.pm
@@ -585,7 +585,7 @@ sub setup_categories_and_bodies : Private {
my $first_area = ( values %$all_areas )[0];
my @bodies = $c->model('DB::Body')->search(
- { 'body_areas.area_id' => [ keys %$all_areas ] },
+ { 'body_areas.area_id' => [ keys %$all_areas ], deleted => 0 },
{ join => 'body_areas' }
)->all;
my %bodies = map { $_->id => $_ } @bodies;
@@ -666,6 +666,15 @@ sub setup_categories_and_bodies : Private {
}
}
+ if ($c->cobrand->can('hidden_categories')) {
+ my %hidden_categories = map { $_ => 1 }
+ $c->cobrand->hidden_categories;
+
+ @category_options = grep {
+ !$hidden_categories{$_}
+ } @category_options;
+ }
+
# put results onto stash for display
$c->stash->{bodies} = \%bodies;
$c->stash->{all_body_names} = [ map { $_->name } values %bodies ];
@@ -957,6 +966,13 @@ sub check_for_errors : Private {
delete $field_errors{name};
my $report = $c->stash->{report};
$report->title( Utils::cleanup_text( substr($report->detail, 0, 25) ) );
+
+ # We only want to validate the phone number web requests (where the
+ # service parameter is blank) because previous versions of the mobile
+ # apps don't validate the presence of a phone number.
+ if ( ! $c->req->param('phone') and ! $c->req->param('service') ) {
+ $field_errors{phone} = _("This information is required");
+ }
}
# FIXME: need to check for required bromley fields here
diff --git a/perllib/FixMyStreet/App/View/Web.pm b/perllib/FixMyStreet/App/View/Web.pm
index 8d3775ddc..e4aafe951 100644
--- a/perllib/FixMyStreet/App/View/Web.pm
+++ b/perllib/FixMyStreet/App/View/Web.pm
@@ -19,7 +19,7 @@ __PACKAGE__->config(
render_die => 1,
expose_methods => [
'loc', 'nget', 'tprintf', 'display_crosssell_advert', 'prettify_dt',
- 'add_links', 'version',
+ 'add_links', 'version', 'decode',
],
FILTERS => {
escape_js => \&escape_js,
@@ -181,5 +181,11 @@ sub version {
return "$file?$version_hash{$file}";
}
+sub decode {
+ my ( $self, $c, $text ) = @_;
+ utf8::decode($text) unless utf8::is_utf8($text);
+ return $text;
+}
+
1;
diff --git a/perllib/FixMyStreet/Cobrand.pm b/perllib/FixMyStreet/Cobrand.pm
index 881183463..ff7d7f943 100644
--- a/perllib/FixMyStreet/Cobrand.pm
+++ b/perllib/FixMyStreet/Cobrand.pm
@@ -8,6 +8,7 @@ use warnings;
use FixMyStreet;
use Carp;
+use Moose;
use Module::Pluggable
sub_name => '_cobrands',
@@ -38,7 +39,10 @@ Simply returns the config variable (so this function can be overridden in test s
=cut
sub _get_allowed_cobrands {
- return FixMyStreet->config('ALLOWED_COBRANDS') || [];
+ my $allowed = FixMyStreet->config('ALLOWED_COBRANDS') || [];
+ # If the user has supplied a string, convert to an arrayref
+ $allowed = [ $allowed ] unless ref $allowed;
+ return $allowed;
}
=head2 available_cobrand_classes
@@ -92,7 +96,14 @@ sub get_class_for_host {
my $class = shift;
my $host = shift;
- foreach my $avail ( $class->available_cobrand_classes ) {
+ my @available = $class->available_cobrand_classes;
+
+ # If only one entry, always use it
+ return class($available[0]) if 1 == @available;
+
+ # If more than one entry, pick first whose regex (or
+ # name by default) matches hostname
+ foreach my $avail ( @available ) {
return class($avail) if $host =~ /$avail->{host}/;
}
diff --git a/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm b/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm
new file mode 100644
index 000000000..d96e7bc96
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/BellaVistaEnAccion.pm
@@ -0,0 +1,33 @@
+package FixMyStreet::Cobrand::BellaVistaEnAccion;
+use base 'FixMyStreet::Cobrand::Default';
+
+use strict;
+use warnings;
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
+
+sub country {
+ return 'CL';
+}
+
+sub example_places {
+ return ( 'Dominica, Recoleta', 'Pio Nono' );
+}
+
+sub languages { [ 'es-cl,Castellano,es_CL', 'en-gb,English,en_GB' ] }
+
+sub disambiguate_location {
+ return {
+ country => 'cl',
+ town => 'Santiago',
+ };
+}
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/Default.pm b/perllib/FixMyStreet/Cobrand/Default.pm
index 38efb7a35..a39a98135 100644
--- a/perllib/FixMyStreet/Cobrand/Default.pm
+++ b/perllib/FixMyStreet/Cobrand/Default.pm
@@ -295,8 +295,11 @@ to null/0.
sub uri {
my ( $self, $uri ) = @_;
- (my $map_class = $FixMyStreet::Map::map_class) =~ s/^FixMyStreet::Map:://;
- return $uri unless $map_class =~ /OSM|FMS/;
+ {
+ no warnings 'once';
+ (my $map_class = $FixMyStreet::Map::map_class) =~ s/^FixMyStreet::Map:://;
+ return $uri unless $map_class =~ /OSM|FMS/;
+ }
$uri->query_param( zoom => 3 )
if $uri->query_param('lat') && !$uri->query_param('zoom');
diff --git a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
index 5e90db038..461018639 100644
--- a/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
+++ b/perllib/FixMyStreet/Cobrand/FiksGataMi.pm
@@ -38,7 +38,7 @@ sub area_types {
}
sub admin_base_url {
- return 'http://www.fiksgatami.no/admin/';
+ return 'http://www.fiksgatami.no/admin';
}
# If lat/lon are present in the URL, OpenLayers will use that to centre the map.
diff --git a/perllib/FixMyStreet/Cobrand/FixMindelo.pm b/perllib/FixMyStreet/Cobrand/FixMindelo.pm
index 59debf157..fd3a55c6c 100644
--- a/perllib/FixMyStreet/Cobrand/FixMindelo.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMindelo.pm
@@ -4,6 +4,8 @@ use base 'FixMyStreet::Cobrand::Default';
use strict;
use warnings;
+sub site_title { return 'FixMindelo'; }
+
sub country {
return 'CV';
}
diff --git a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
index aa2be4a0f..c3a1f9d9d 100644
--- a/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
+++ b/perllib/FixMyStreet/Cobrand/FixMyStreet.pm
@@ -9,7 +9,7 @@ sub restriction {
}
sub admin_base_url {
- return 'https://secure.mysociety.org/admin/bci/';
+ return 'https://secure.mysociety.org/admin/bci';
}
sub title_list {
diff --git a/perllib/FixMyStreet/Cobrand/Hart.pm b/perllib/FixMyStreet/Cobrand/Hart.pm
new file mode 100644
index 000000000..cab834b69
--- /dev/null
+++ b/perllib/FixMyStreet/Cobrand/Hart.pm
@@ -0,0 +1,72 @@
+package FixMyStreet::Cobrand::Hart;
+use parent 'FixMyStreet::Cobrand::UKCouncils';
+
+use strict;
+use warnings;
+
+sub council_id { return 2333; } # http://mapit.mysociety.org/area/2333.html
+sub council_area { return 'Hart'; }
+sub council_name { return 'Hart Council'; }
+sub council_url { return 'hart'; }
+sub is_two_tier { return 1; }
+
+# Different to councils parent due to this being a two-tier council. If we get
+# more, this can be genericised in the parent.
+sub problems_clause {
+ return { bodies_str => { like => '%2333%' } };
+}
+
+sub path_to_web_templates {
+ my $self = shift;
+ return [
+ FixMyStreet->path_to( 'templates/web', $self->moniker )->stringify,
+ FixMyStreet->path_to( 'templates/web/fixmystreet' )->stringify
+ ];
+}
+
+sub disambiguate_location {
+ my $self = shift;
+ my $string = shift;
+
+ my $town = 'Hart, Hampshire';
+
+ return {
+ %{ $self->SUPER::disambiguate_location() },
+ town => $town,
+ # these are taken from mapit http://mapit.mysociety.org/area/2333/geometry -- should be automated?
+ centre => '51.284839,-0.8974600',
+ span => '0.180311,0.239375',
+ bounds => [ 51.186005, -1.002295, 51.366316, -0.762920 ],
+ };
+}
+
+sub example_places {
+ return ( 'GU51 4JX', 'Primrose Drive' );
+}
+
+sub hidden_categories {
+ return (
+ 'Graffiti on bridges/subways',
+ );
+}
+
+sub send_questionnaires {
+ return 0;
+}
+
+sub ask_ever_reported {
+ return 0;
+}
+
+sub contact_email {
+ my $self = shift;
+ return join( '@', 'info', 'hart.gov.uk' );
+}
+sub contact_name { 'Hart District Council (do not reply)'; }
+
+sub default_map_zoom { 3 }
+
+sub reports_per_page { return 20; }
+
+1;
+
diff --git a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
index 173d5a09f..33611b219 100644
--- a/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
+++ b/perllib/FixMyStreet/Cobrand/Oxfordshire.pm
@@ -53,6 +53,9 @@ sub example_places {
# don't send questionnaires to people who used the OCC cobrand to report their problem
sub send_questionnaires { return 0; }
+# increase map zoom level so street names are visible
+sub default_map_zoom { return 3; }
+
# let staff hide OCC reports
sub users_can_hide { return 1; }
diff --git a/perllib/FixMyStreet/Cobrand/UKCouncils.pm b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
index 5531ed048..ec3423f35 100644
--- a/perllib/FixMyStreet/Cobrand/UKCouncils.pm
+++ b/perllib/FixMyStreet/Cobrand/UKCouncils.pm
@@ -84,10 +84,7 @@ sub all_reports_single_body {
sub reports_body_check {
my ( $self, $c, $code ) = @_;
- # First, the normal UK checks
- $self->SUPER::find_closest( $c, $code );
-
- # Now we want to make sure we're only on our page.
+ # We want to make sure we're only on our page.
unless ( $self->council_name =~ /^\Q$code\E/ ) {
$c->res->redirect( 'http://www.fixmystreet.com' . $c->req->uri->path_query, 301 );
$c->detach();
@@ -102,13 +99,19 @@ sub recent_photos {
return $self->problems->recent_photos( $num, $lat, $lon, $dist );
}
+# Returns true if the cobrand owns the problem.
+sub owns_problem {
+ my ($self, $report) = @_;
+ my $bodies = $report->bodies;
+ my %areas = map { %{$_->areas} } values %$bodies;
+ return $areas{$self->council_id} ? 1 : undef;
+}
+
# If we ever link to a county problem report, needs to be to main FixMyStreet
sub base_url_for_report {
my ( $self, $report ) = @_;
if ( $self->is_two_tier ) {
- my $bodies = $report->bodies;
- my %areas = map { %{$_->areas} } values %$bodies;
- if ( $areas{$self->council_id} ) {
+ if ( $self->owns_problem( $report ) ) {
return $self->base_url;
} else {
return FixMyStreet->config('BASE_URL');
diff --git a/perllib/FixMyStreet/Cobrand/Zurich.pm b/perllib/FixMyStreet/Cobrand/Zurich.pm
index ffdc1feab..0a05fe835 100644
--- a/perllib/FixMyStreet/Cobrand/Zurich.pm
+++ b/perllib/FixMyStreet/Cobrand/Zurich.pm
@@ -8,6 +8,48 @@ 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
+ ----+------------------+-----------
+ 1 | super@example.org| 1
+ 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;
}
@@ -53,6 +95,27 @@ sub prettify_dt {
return Utils::prettify_dt( $dt, 'zurich' );
}
+# problem already has a concept of is_fixed/is_closed, but Zurich has different
+# workflow for this here.
+#
+# TODO: look at more elegant way of doing this, for example having ::DB::Problem
+# consider cobrand specific state config?
+
+sub zurich_closed_states {
+ my $states = {
+ 'fixed - council' => 1,
+ 'closed' => 1,
+ 'hidden' => 1,
+ };
+
+ return wantarray ? keys %{ $states } : $states;
+}
+
+sub problem_is_closed {
+ my ($self, $problem) = @_;
+ return exists $self->zurich_closed_states->{ $problem->state } ? 1 : 0;
+}
+
sub problem_as_hashref {
my $self = shift;
my $problem = shift;
@@ -174,19 +237,47 @@ sub overdue {
my $w = $problem->created;
return 0 unless $w;
- if ( $problem->state eq 'unconfirmed' || $problem->state eq 'confirmed' ) {
+ # call with previous state
+ if ( $problem->state eq 'unconfirmed' ) {
# One working day
$w = add_days( $w, 1 );
return $w < DateTime->now() ? 1 : 0;
- } elsif ( $problem->state eq 'in progress' || $problem->state eq 'planned' ) {
+ } elsif ( $problem->state eq 'confirmed' || $problem->state eq 'in progress' || $problem->state eq 'planned' ) {
+ # States which affect the subdiv_overdue statistic. TODO: this may no longer be required
# Six working days from creation
$w = add_days( $w, 6 );
return $w < DateTime->now() ? 1 : 0;
+
+ # call with new state
+ } elsif ( $self->problem_is_closed($problem) ) {
+ # States which affect the closed_overdue statistic
+ # Five working days from moderation (so 6 from creation)
+
+ $w = add_days( $w, 6 );
+ return $w < DateTime->now() ? 1 : 0;
} else {
return 0;
}
}
+sub get_or_check_overdue {
+ my ($self, $problem) = @_;
+
+ # use the cached version is it exists (e.g. when called from template)
+ my $extra = $problem->extra;
+ if (exists $extra->{closed_overdue} and defined $extra->{closed_overdue}) {
+ return $extra->{closed_overdue}
+ }
+ return $self->overdue($problem);
+}
+
+sub set_problem_state {
+ my ($self, $c, $problem, $new_state) = @_;
+ return if $new_state eq $problem->state;
+ $problem->state( $new_state );
+ $c->forward( 'log_edit', [ $problem->id, 'problem', "state change to $new_state" ] );
+}
+
sub email_indent { ''; }
# Specific administrative displays
@@ -356,52 +447,87 @@ 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,
+ 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};
+ # Some changes will be accompanied by an internal note, which if needed
+ # should be stored in this variable.
+ my $internal_note_text = "";
+
# Workflow things
my $redirect = 0;
my $new_cat = $c->req->params->{category};
if ( $new_cat && $new_cat ne $problem->category ) {
my $cat = $c->model('DB::Contact')->search( { category => $c->req->params->{category} } )->first;
+ my $old_cat = $problem->category;
$problem->category( $new_cat );
$problem->external_body( undef );
$problem->bodies_str( $cat->body_id );
$problem->whensent( undef );
$extra->{changed_category} = 1;
+ $internal_note_text = "Weitergeleitet von $old_cat an $new_cat";
$redirect = 1 if $cat->body_id ne $body->id;
} elsif ( my $subdiv = $c->req->params->{body_subdivision} ) {
- $extra->{moderated_overdue} = $self->overdue( $problem );
- $problem->state( 'in progress' );
+ $extra->{moderated_overdue} //= $self->overdue( $problem );
+ $self->set_problem_state($c, $problem, 'in progress');
$problem->external_body( undef );
$problem->bodies_str( $subdiv );
$problem->whensent( undef );
$redirect = 1;
} elsif ( my $external = $c->req->params->{body_external} ) {
- $extra->{moderated_overdue} = $self->overdue( $problem );
- $problem->state( 'closed' );
+ $extra->{moderated_overdue} //= $self->overdue( $problem );
+ $self->set_problem_state($c, $problem, 'closed');
+ $extra->{closed_overdue} //= $self->overdue( $problem );
$problem->external_body( $external );
$problem->whensent( undef );
_admin_send_email( $c, 'problem-external.txt', $problem );
$redirect = 1;
} else {
- $problem->state( $c->req->params->{state} ) if $c->req->params->{state};
- if ( $problem->state eq 'hidden' ) {
- _admin_send_email( $c, 'problem-rejected.txt', $problem );
+ if (my $state = $c->req->params->{state}) {
+
+ if ($problem->state eq 'unconfirmed' and $state ne 'unconfirmed') {
+ # only set this for the first state change
+ $extra->{moderated_overdue} //= $self->overdue( $problem );
+ }
+
+ $self->set_problem_state($c, $problem, $state);
+
+ if ($self->problem_is_closed($problem)) {
+ $extra->{closed_overdue} //= $self->overdue( $problem );
+ }
+ if ( $state eq 'hidden' && $c->req->params->{send_rejected_email} ) {
+ _admin_send_email( $c, 'problem-rejected.txt', $problem );
+ }
}
}
- $problem->extra( { %$extra } );
+ $problem->extra( $extra );
$problem->title( $c->req->param('title') );
$problem->detail( $c->req->param('detail') );
$problem->latitude( $c->req->param('latitude') );
@@ -410,9 +536,11 @@ sub admin_report_edit {
# Final, public, Update from DM
if (my $update = $c->req->param('status_update')) {
$extra->{public_response} = $update;
- $problem->extra( { %$extra } );
+ $problem->extra( $extra );
if ($c->req->params->{publish_response}) {
- $problem->state( 'fixed - council' );
+ $self->set_problem_state($c, $problem, 'fixed - council');
+ $extra->{closed_overdue} = $self->overdue( $problem );
+ $problem->extra( { %$extra } );
_admin_send_email( $c, 'problem-closed.txt', $problem );
}
}
@@ -424,9 +552,22 @@ sub admin_report_edit {
'<p><em>' . _('Updated!') . '</em></p>';
# do this here otherwise lastupdate and confirmed times
- # do not display correctly
+ # do not display correctly (reloads problem from database, including
+ # fields modified by the database when saving)
$problem->discard_changes;
+ # Create an internal note if required
+ if ($internal_note_text) {
+ $problem->add_to_comments( {
+ text => $internal_note_text,
+ user => $c->user->obj,
+ state => 'hidden', # seems best fit, should not be shown publicly
+ mark_fixed => 0,
+ anonymous => 1,
+ extra => { is_internal_note => 1 },
+ } );
+ }
+
if ( $redirect ) {
$c->detach('index');
}
@@ -447,7 +588,7 @@ sub admin_report_edit {
$c->forward('check_token');
$problem->bodies_str( $body->parent->id );
- $problem->state( 'confirmed' );
+ $self->set_problem_state($c, $problem, 'confirmed');
$problem->update;
# log here
$c->res->redirect( '/admin/summary' );
@@ -462,14 +603,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
@@ -491,10 +624,10 @@ sub admin_report_edit {
if ($c->req->param('no_more_updates')) {
my $extra = $problem->extra || {};
$extra->{subdiv_overdue} = $self->overdue( $problem );
- $problem->extra( { %$extra } );
+ $problem->extra( $extra );
$problem->bodies_str( $body->parent->id );
$problem->whensent( undef );
- $problem->state( 'planned' );
+ $self->set_problem_state($c, $problem, 'planned');
$problem->update;
$c->res->redirect( '/admin/summary' );
}
@@ -578,7 +711,7 @@ sub admin_stats {
my %date_params;
my $ym = $c->req->params->{ym};
- my ($m, $y) = $ym =~ /^(\d+)\.(\d+)$/;
+ my ($m, $y) = $ym ? ($ym =~ /^(\d+)\.(\d+)$/) : ();
$c->stash->{ym} = $ym;
if ($y && $m) {
$c->stash->{start_date} = DateTime->new( year => $y, month => $m, day => 1 );
@@ -592,10 +725,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(
+ {%date_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);
@@ -616,9 +770,11 @@ sub admin_stats {
# Reports assigned to third party
my $closed = $c->model('DB::Problem')->search( { state => 'closed', %date_params } )->count;
# Reports moderated within 1 day
- my $moderated = $c->model('DB::Problem')->search( { extra => { like => '%moderated_overdue,I1:0%' }, %params } )->count;
- # Reports solved within 5 days
+ my $moderated = $c->model('DB::Problem')->search( { extra => { like => '%moderated_overdue,I1:0%' }, %date_params } )->count;
+ # Reports solved within 5 days (sent back from subdiv)
my $subdiv_dealtwith = $c->model('DB::Problem')->search( { extra => { like => '%subdiv_overdue,I1:0%' }, %params } )->count;
+ # Reports solved within 5 days (marked as 'fixed - council', 'closed', or 'hidden'
+ my $fixed_in_time = $c->model('DB::Problem')->search( { extra => { like => '%closed_overdue,I1:0%' }, %date_params } )->count;
# Reports per category
my $per_category = $c->model('DB::Problem')->search( \%params, {
select => [ 'category', { count => 'id' } ],
@@ -649,7 +805,7 @@ sub admin_stats {
reports_spam => $hidden,
reports_assigned => $closed,
reports_moderated => $moderated,
- reports_dealtwith => $subdiv_dealtwith,
+ reports_dealtwith => $fixed_in_time,
reports_category_changed => $changed,
pictures_taken => $pictures_taken,
pictures_published => $pictures_published,
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/Alert.pm b/perllib/FixMyStreet/DB/Result/Alert.pm
index fc84c8fd5..4ce72f873 100644
--- a/perllib/FixMyStreet/DB/Result/Alert.pm
+++ b/perllib/FixMyStreet/DB/Result/Alert.pm
@@ -48,7 +48,7 @@ __PACKAGE__->belongs_to(
"alert_type",
"FixMyStreet::DB::Result::AlertType",
{ ref => "alert_type" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
__PACKAGE__->has_many(
"alerts_sent",
@@ -60,12 +60,12 @@ __PACKAGE__->belongs_to(
"user",
"FixMyStreet::DB::Result::User",
{ id => "user_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vump36YxUO4FQi5Do6DwvA
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:d9yIFiTGtbtFaULXZNKstQ
# You can replace this text with custom code or comments, and it will be preserved on regeneration
diff --git a/perllib/FixMyStreet/DB/Result/AlertSent.pm b/perllib/FixMyStreet/DB/Result/AlertSent.pm
index a537c95cd..422e010a9 100644
--- a/perllib/FixMyStreet/DB/Result/AlertSent.pm
+++ b/perllib/FixMyStreet/DB/Result/AlertSent.pm
@@ -26,12 +26,12 @@ __PACKAGE__->belongs_to(
"alert",
"FixMyStreet::DB::Result::Alert",
{ id => "alert_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:oN+36hDWJuc0hqkCW9BHOw
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:COwsprqRSNZS1IxJrPYgMQ
# You can replace this text with custom code or comments, and it will be preserved on regeneration
diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm
index bab16061b..be4adeca9 100644
--- a/perllib/FixMyStreet/DB/Result/Body.pm
+++ b/perllib/FixMyStreet/DB/Result/Body.pm
@@ -20,6 +20,8 @@ __PACKAGE__->add_columns(
},
"name",
{ data_type => "text", is_nullable => 0 },
+ "parent",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"endpoint",
{ data_type => "text", is_nullable => 1 },
"jurisdiction",
@@ -38,8 +40,8 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"send_extended_statuses",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
- "parent",
- { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+ "deleted",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
"external_url",
{ data_type => "text", is_nullable => 0 },
);
@@ -61,10 +63,10 @@ __PACKAGE__->belongs_to(
"FixMyStreet::DB::Result::User",
{ id => "comment_user_id" },
{
- is_deferrable => 1,
+ is_deferrable => 0,
join_type => "LEFT",
- on_delete => "CASCADE",
- on_update => "CASCADE",
+ on_delete => "NO ACTION",
+ on_update => "NO ACTION",
},
);
__PACKAGE__->has_many(
@@ -78,10 +80,10 @@ __PACKAGE__->belongs_to(
"FixMyStreet::DB::Result::Body",
{ id => "parent" },
{
- is_deferrable => 1,
+ is_deferrable => 0,
join_type => "LEFT",
- on_delete => "CASCADE",
- on_update => "CASCADE",
+ on_delete => "NO ACTION",
+ on_update => "NO ACTION",
},
);
__PACKAGE__->has_many(
@@ -92,8 +94,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-19 12:47:10
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:DdtXjMWRpz20ZHjtY3oP2w
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 18:11:23
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:hTOxxiiHmC8nmQK/p8dXhQ
sub url {
my ( $self, $c ) = @_;
diff --git a/perllib/FixMyStreet/DB/Result/BodyArea.pm b/perllib/FixMyStreet/DB/Result/BodyArea.pm
index 844a3277d..4447777dc 100644
--- a/perllib/FixMyStreet/DB/Result/BodyArea.pm
+++ b/perllib/FixMyStreet/DB/Result/BodyArea.pm
@@ -21,12 +21,12 @@ __PACKAGE__->belongs_to(
"body",
"FixMyStreet::DB::Result::Body",
{ id => "body_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-19 12:47:10
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:aAr+Nadyu8IckZlK6+PTNg
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:+hzie6kHleUBoEt199c/nQ
__PACKAGE__->set_primary_key(__PACKAGE__->columns);
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index c747f7fc1..e170a5655 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -54,6 +54,10 @@ __PACKAGE__->add_columns(
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
"problem_state",
{ data_type => "text", is_nullable => 1 },
+ "external_id",
+ { data_type => "text", is_nullable => 1 },
+ "extra",
+ { data_type => "text", is_nullable => 1 },
"send_fail_count",
{ data_type => "integer", default_value => 0, is_nullable => 0 },
"send_fail_reason",
@@ -62,55 +66,32 @@ __PACKAGE__->add_columns(
{ data_type => "timestamp", is_nullable => 1 },
"whensent",
{ data_type => "timestamp", is_nullable => 1 },
- "external_id",
- { data_type => "text", is_nullable => 1 },
- "extra",
- { data_type => "text", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->belongs_to(
"problem",
"FixMyStreet::DB::Result::Problem",
{ id => "problem_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
__PACKAGE__->belongs_to(
"user",
"FixMyStreet::DB::Result::User",
{ id => "user_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-07-11 18:53:26
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:tSejJzLxHD/fMWjpa10lfA
-
-__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;
- },
- }
-);
+# 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__->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';
@@ -145,9 +126,10 @@ sub check_for_errors {
$errors{update} = _('Please enter a message')
unless $self->text =~ m/\S/;
+ # Bromley Council custom character limit
if ( $self->text && $self->problem && $self->problem->bodies_str
- && $self->problem->bodies_str eq '2482' && length($self->text) > 2000 ) {
- $errors{update} = _('Updates are limited to 2000 characters in length. Please shorten your update');
+ && $self->problem->bodies_str eq '2482' && length($self->text) > 1750 ) {
+ $errors{update} = sprintf( _('Updates are limited to %s characters in length. Please shorten your update'), 1750 );
}
return \%errors;
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index 551bcd019..eca028c9b 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -53,32 +53,14 @@ __PACKAGE__->belongs_to(
"body",
"FixMyStreet::DB::Result::Body",
{ id => "body_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-13 12:34:33
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:imXq3EtrC0FrQwj+E2xfBw
+# 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 ec15600b6..a06a339bf 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -120,12 +120,12 @@ __PACKAGE__->belongs_to(
"user",
"FixMyStreet::DB::Result::User",
{ id => "user_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-13 15:13:48
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:H2P3Og37G569nQdQA1IWaA
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:U/4BT8EGfcCLKA/7LX+qyQ
# Add fake relationship to stored procedure table
__PACKAGE__->has_one(
@@ -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';
@@ -427,9 +388,16 @@ sub check_for_errors {
$self->category(undef);
}
- if ( $self->bodies_str && $self->detail &&
- $self->bodies_str eq '2482' && length($self->detail) > 2000 ) {
- $errors{detail} = _('Reports are limited to 2000 characters in length. Please shorten your report');
+ if ( $self->bodies_str && $self->detail ) {
+ # Custom character limit:
+ # Bromley Council
+ if ( $self->bodies_str eq '2482' && length($self->detail) > 1750 ) {
+ $errors{detail} = sprintf( _('Reports are limited to %s characters in length. Please shorten your report'), 1750 );
+ }
+ # Oxfordshire
+ if ( $self->bodies_str eq '2237' && length($self->detail) > 1700 ) {
+ $errors{detail} = sprintf( _('Reports are limited to %s characters in length. Please shorten your report'), 1700 );
+ }
}
return \%errors;
@@ -578,11 +546,11 @@ sub meta_line {
and $problem->category && $problem->category ne _('Other') )
{
$meta =
- sprintf( _('Reported by %s in the %s category anonymously at %s'),
+ sprintf( _('Reported via %s in the %s category anonymously at %s'),
$problem->service, $problem->category, $date_time );
}
elsif ( $problem->service ) {
- $meta = sprintf( _('Reported by %s anonymously at %s'),
+ $meta = sprintf( _('Reported via %s anonymously at %s'),
$problem->service, $date_time );
}
elsif ( $problem->category and $problem->category ne _('Other') ) {
@@ -598,13 +566,13 @@ sub meta_line {
and $problem->category && $problem->category ne _('Other') )
{
$meta = sprintf(
- _('Reported by %s in the %s category by %s at %s'),
+ _('Reported via %s in the %s category by %s at %s'),
$problem->service, $problem->category,
$problem->name, $date_time
);
}
elsif ( $problem->service ) {
- $meta = sprintf( _('Reported by %s by %s at %s'),
+ $meta = sprintf( _('Reported via %s by %s at %s'),
$problem->service, $problem->name, $date_time );
}
elsif ( $problem->category and $problem->category ne _('Other') ) {
diff --git a/perllib/FixMyStreet/DB/Result/Questionnaire.pm b/perllib/FixMyStreet/DB/Result/Questionnaire.pm
index fcaa17d99..7f9c79d9a 100644
--- a/perllib/FixMyStreet/DB/Result/Questionnaire.pm
+++ b/perllib/FixMyStreet/DB/Result/Questionnaire.pm
@@ -36,12 +36,12 @@ __PACKAGE__->belongs_to(
"problem",
"FixMyStreet::DB::Result::Problem",
{ id => "problem_id" },
- { is_deferrable => 1, on_delete => "CASCADE", on_update => "CASCADE" },
+ { is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-03-08 17:19:55
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:NGlSRjoBpDoIvK3EueqN6Q
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:oL1Hk4/bNG14CY74GA75SA
use DateTime::TimeZone;
use Moose;
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/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index 481b654c9..523382670 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -58,10 +58,10 @@ __PACKAGE__->belongs_to(
"FixMyStreet::DB::Result::Body",
{ id => "from_body" },
{
- is_deferrable => 1,
+ is_deferrable => 0,
join_type => "LEFT",
- on_delete => "CASCADE",
- on_update => "CASCADE",
+ on_delete => "NO ACTION",
+ on_update => "NO ACTION",
},
);
__PACKAGE__->has_many(
@@ -72,8 +72,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07017 @ 2012-12-14 09:23:59
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:aw374WQraL5ysOvUmUIU3w
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2013-09-10 17:11:54
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jRAtXRLRNozCmthAg9p0dA
__PACKAGE__->add_columns(
"password" => {
diff --git a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
index a2784950a..cc4fc67fc 100644
--- a/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/AlertType.pm
@@ -58,6 +58,7 @@ sub email_alerts ($) {
while (my $row = $query->fetchrow_hashref) {
my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($row->{alert_cobrand})->new();
+ $cobrand->set_lang_and_domain( $row->{alert_lang}, 1, FixMyStreet->path_to('locale')->stringify );
# Cobranded and non-cobranded messages can share a database. In this case, the conf file
# should specify a vhost to send the reports for each cobrand, so that they don't get sent
@@ -204,7 +205,7 @@ sub _send_aggregated_alert_email(%) {
my $cobrand = FixMyStreet::Cobrand->get_class_for_moniker($data{cobrand})->new();
- $cobrand->set_lang_and_domain( $data{lang}, 1 );
+ $cobrand->set_lang_and_domain( $data{lang}, 1, FixMyStreet->path_to('locale')->stringify );
if (!$data{alert_email}) {
my $user = FixMyStreet::App->model('DB::User')->find( {
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index 97d457297..5499af474 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -216,6 +216,11 @@ sub categories_summary {
return \%categories;
}
+sub get_admin_url {
+ my ($rs, $cobrand, $row) = @_;
+ return $cobrand->admin_base_url . '/report_edit/' . $row->id;
+}
+
sub send_reports {
my ( $rs, $site_override ) = @_;
@@ -259,10 +264,14 @@ sub send_reports {
}
$cobrand->set_lang_and_domain($row->lang, 1);
- if ( $row->is_from_abuser ) {
+ if ( $row->is_from_abuser) {
$row->update( { state => 'hidden' } );
debug_print("hiding because its sender is flagged as an abuser", $row->id) if $debug_mode;
next;
+ } elsif ( $row->title =~ /app store test/i ) {
+ $row->update( { state => 'hidden' } );
+ debug_print("hiding because it is an app store test message", $row->id) if $debug_mode;
+ next;
}
# Template variables for the email
@@ -274,7 +283,7 @@ sub send_reports {
$h{query} = $row->postcode;
$h{url} = $email_base_url . $row->url;
- $h{admin_url} = $cobrand->admin_base_url . 'report_edit/' . $row->id;
+ $h{admin_url} = $rs->get_admin_url($cobrand, $row);
$h{phone_line} = $h{phone} ? _('Phone:') . " $h{phone}\n\n" : '';
if ($row->photo) {
$h{has_photo} = _("This web page also contains a photo of the problem, provided by the user.") . "\n\n";
@@ -331,7 +340,10 @@ sub send_reports {
# XXX Only copes with at most one missing body
my ($bodies, $missing) = $row->bodies_str =~ /^([\d,]+)(?:\|(\d+))?/;
my @bodies = split(/,/, $bodies);
- $bodies = FixMyStreet::App->model("DB::Body")->search({ id => \@bodies });
+ $bodies = FixMyStreet::App->model("DB::Body")->search(
+ { id => \@bodies },
+ { order_by => 'name' },
+ );
$missing = FixMyStreet::App->model("DB::Body")->find($missing) if $missing;
my @dear;
diff --git a/perllib/FixMyStreet/Map/GoogleOL.pm b/perllib/FixMyStreet/Map/GoogleOL.pm
new file mode 100644
index 000000000..64baf8d36
--- /dev/null
+++ b/perllib/FixMyStreet/Map/GoogleOL.pm
@@ -0,0 +1,22 @@
+#!/usr/bin/perl
+#
+# FixMyStreet:Map::GoogleOL
+# Google maps on FixMyStreet, using OpenLayers.
+#
+# Copyright (c) 2013 UK Citizens Online Democracy. All rights reserved.
+# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/
+
+package FixMyStreet::Map::GoogleOL;
+use parent 'FixMyStreet::Map::OSM';
+
+use strict;
+
+sub map_type {
+ return '""';
+}
+
+sub map_template {
+ return 'google-ol';
+}
+
+1;
diff --git a/perllib/FixMyStreet/SendReport/Email.pm b/perllib/FixMyStreet/SendReport/Email.pm
index 9006e2f11..e8151f175 100644
--- a/perllib/FixMyStreet/SendReport/Email.pm
+++ b/perllib/FixMyStreet/SendReport/Email.pm
@@ -33,14 +33,24 @@ sub build_recipient_list {
$self->unconfirmed_notes->{$body_email}{$row->category} = $note;
}
+ my $body_name = $body->name;
# see something uses council areas but doesn't send to councils so just use a
# generic name here to minimise confusion
if ( $row->cobrand eq 'seesomething' ) {
- push @{ $self->to }, [ $body_email, 'See Something, Say Something' ];
+ $body_name = 'See Something, Say Something';
+ }
+
+ my @emails;
+ # allow multiple emails per contact
+ if ( $body_email =~ /,/ ) {
+ @emails = split(/,/, $body_email);
} else {
- push @{ $self->to }, [ $body_email, $body->name ];
+ @emails = ( $body_email );
+ }
+ for my $email ( @emails ) {
+ push @{ $self->to }, [ $email, $body_name ];
+ $recips{$email} = 1;
}
- $recips{$body_email} = 1;
}
return () unless $all_confirmed;
@@ -74,7 +84,7 @@ sub send {
# on a staging server send emails to ourselves rather than the bodies
if (mySociety::Config::get('STAGING_SITE') && !mySociety::Config::get('SEND_REPORTS_ON_STAGING') && !FixMyStreet->test_mode) {
- @recips = ( mySociety::Config::get('CONTACT_EMAIL') );
+ @recips = ( $row->user->email );
}
unless ( @recips ) {
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
diff --git a/perllib/Open311.pm b/perllib/Open311.pm
index 6c811d445..c8289a442 100644
--- a/perllib/Open311.pm
+++ b/perllib/Open311.pm
@@ -290,6 +290,7 @@ sub _populate_service_request_update_params {
my $name = $comment->name || $comment->user->name;
my ( $firstname, $lastname ) = ( $name =~ /(\w+)\.?\s+(.+)/ );
+ $lastname ||= '-';
# fall back to problem state as it's probably correct
my $state = $comment->problem_state || $comment->problem->state;
diff --git a/perllib/Open311/GetServiceRequestUpdates.pm b/perllib/Open311/GetServiceRequestUpdates.pm
index ae1f06a50..f7b758137 100644
--- a/perllib/Open311/GetServiceRequestUpdates.pm
+++ b/perllib/Open311/GetServiceRequestUpdates.pm
@@ -127,7 +127,9 @@ sub update_comments {
# actually changing the state of the problem
if ( FixMyStreet::DB::Result::Problem->council_states()->{$state} && $p->state ne $state &&
!( $p->is_fixed && FixMyStreet::DB::Result::Problem->fixed_states()->{$state} ) ) {
- $p->state($state);
+ if ($p->is_visible) {
+ $p->state($state);
+ }
$comment->problem_state($state);
}
}
@@ -137,17 +139,19 @@ sub update_comments {
$comment->insert();
if ( $self->suppress_alerts ) {
- my $alert = FixMyStreet::App->model('DB::Alert')->find( {
+ my @alerts = FixMyStreet::App->model('DB::Alert')->search( {
alert_type => 'new_updates',
parameter => $p->id,
confirmed => 1,
user_id => $p->user->id,
} );
- my $alerts_sent = FixMyStreet::App->model('DB::AlertSent')->find_or_create( {
- alert_id => $alert->id,
- parameter => $comment->id,
- } );
+ for my $alert (@alerts) {
+ my $alerts_sent = FixMyStreet::App->model('DB::AlertSent')->find_or_create( {
+ alert_id => $alert->id,
+ parameter => $comment->id,
+ } );
+ }
}
}
}