aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/DB
diff options
context:
space:
mode:
Diffstat (limited to 'perllib/FixMyStreet/DB')
-rw-r--r--perllib/FixMyStreet/DB/Factories.pm1
-rw-r--r--perllib/FixMyStreet/DB/RABXColumn.pm18
-rw-r--r--perllib/FixMyStreet/DB/Result/AdminLog.pm81
-rw-r--r--perllib/FixMyStreet/DB/Result/Body.pm45
-rw-r--r--perllib/FixMyStreet/DB/Result/Comment.pm17
-rw-r--r--perllib/FixMyStreet/DB/Result/Contact.pm55
-rw-r--r--perllib/FixMyStreet/DB/Result/ManifestTheme.pm47
-rw-r--r--perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm6
-rw-r--r--perllib/FixMyStreet/DB/Result/Problem.pm102
-rw-r--r--perllib/FixMyStreet/DB/Result/Role.pm53
-rw-r--r--perllib/FixMyStreet/DB/Result/User.pm147
-rw-r--r--perllib/FixMyStreet/DB/Result/UserRole.pm50
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Alert.pm7
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Comment.pm7
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Contact.pm64
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/Problem.pm31
-rw-r--r--perllib/FixMyStreet/DB/ResultSet/State.pm6
-rw-r--r--perllib/FixMyStreet/DB/Schema.pm1
18 files changed, 629 insertions, 109 deletions
diff --git a/perllib/FixMyStreet/DB/Factories.pm b/perllib/FixMyStreet/DB/Factories.pm
index 5af9ed38f..05c56e394 100644
--- a/perllib/FixMyStreet/DB/Factories.pm
+++ b/perllib/FixMyStreet/DB/Factories.pm
@@ -1,6 +1,7 @@
use strict;
use warnings;
use v5.14;
+use utf8;
use FixMyStreet::DB;
diff --git a/perllib/FixMyStreet/DB/RABXColumn.pm b/perllib/FixMyStreet/DB/RABXColumn.pm
index d14b48dc8..76eb21030 100644
--- a/perllib/FixMyStreet/DB/RABXColumn.pm
+++ b/perllib/FixMyStreet/DB/RABXColumn.pm
@@ -52,6 +52,8 @@ set_filtered_column behaviour to not trust the cache.
sub rabx_column {
my ($class, $col) = @_;
+ my $data_type = $class->column_info($col)->{data_type};
+
# Apply the filtering for this column
$class->filter_column(
$col => {
@@ -59,6 +61,10 @@ sub rabx_column {
my $self = shift;
my $ser = shift;
return undef unless defined $ser;
+ # Some RABX columns are text, when they should be bytea. For
+ # these we must re-encode the string returned from the
+ # database, so that it is decoded again by RABX.
+ utf8::encode($ser) if $data_type ne 'bytea';
my $h = new IO::String($ser);
return RABX::wire_rd($h);
},
@@ -68,6 +74,10 @@ sub rabx_column {
my $ser = '';
my $h = new IO::String($ser);
RABX::wire_wr( $data, $h );
+ # Some RABX columns are text, when they should be bytea. For
+ # these, we must re-decode the string encoded by RABX, so that
+ # it is encoded again when saved to the db.
+ utf8::decode($ser) if $data_type ne 'bytea';
return $ser;
},
}
@@ -77,14 +87,6 @@ sub rabx_column {
$RABX_COLUMNS{ _get_class_identifier($class) }{$col} = 1;
}
-# The underlying column should always be UTF-8 encoded bytes.
-sub get_column {
- my ($self, $col) = @_;
- my $res = $self->next::method ($col);
- utf8::encode($res) if $RABX_COLUMNS{_get_class_identifier($self)}{$col} && utf8::is_utf8($res);
- return $res;
-}
-
sub set_filtered_column {
my ($self, $col, $val) = @_;
diff --git a/perllib/FixMyStreet/DB/Result/AdminLog.pm b/perllib/FixMyStreet/DB/Result/AdminLog.pm
index 221690405..4c89138c9 100644
--- a/perllib/FixMyStreet/DB/Result/AdminLog.pm
+++ b/perllib/FixMyStreet/DB/Result/AdminLog.pm
@@ -61,4 +61,85 @@ __PACKAGE__->belongs_to(
# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-04-25 12:06:39
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BLPP1KitphuY56ptaXhzgg
+sub link {
+ my $self = shift;
+
+ my $type = $self->object_type;
+ my $id = $self->object_id;
+ return "/report/$id" if $type eq 'problem';
+ return "/admin/users/$id" if $type eq 'user';
+ return "/admin/body/$id" if $type eq 'body';
+ return "/admin/roles/$id" if $type eq 'role';
+ if ($type eq 'update') {
+ my $update = $self->object;
+ return "/report/" . $update->problem_id . "#update_$id";
+ }
+ if ($type eq 'moderation') {
+ my $mod = $self->object;
+ if ($mod->comment_id) {
+ my $update = $self->result_source->schema->resultset('Comment')->find($mod->comment_id);
+ return "/report/" . $update->problem_id . "#update_" . $mod->comment_id;
+ } else {
+ return "/report/" . $mod->problem_id;
+ }
+ }
+ if ($type eq 'template') {
+ my $template = $self->object;
+ return "/admin/templates/" . $template->body_id . "/$id";
+ }
+ if ($type eq 'category') {
+ my $category = $self->object;
+ return "/admin/body/" . $category->body_id . '/' . $category->category;
+ }
+ if ($type eq 'manifesttheme') {
+ my $theme = $self->object;
+ return "/admin/manifesttheme/" . $theme->cobrand;
+ }
+ return '';
+}
+
+sub actual_object_type {
+ my $self = shift;
+ my $type = $self->object_type;
+ return $type unless $type eq 'moderation' && $self->object;
+ return $self->object->comment_id ? 'update' : 'report';
+}
+
+sub object_summary {
+ my $self = shift;
+ my $object = $self->object;
+ return unless $object;
+
+ return $object->comment_id || $object->problem_id if $self->object_type eq 'moderation';
+ return $object->email || $object->phone || $object->id if $self->object_type eq 'user';
+
+ my $type_to_thing = {
+ body => 'name',
+ role => 'name',
+ template => 'title',
+ category => 'category',
+ manifesttheme => 'cobrand',
+ };
+ my $thing = $type_to_thing->{$self->object_type} || 'id';
+
+ return $object->$thing;
+}
+
+sub object {
+ my $self = shift;
+
+ my $type = $self->object_type;
+ my $id = $self->object_id;
+ my $type_to_object = {
+ moderation => 'ModerationOriginalData',
+ template => 'ResponseTemplate',
+ category => 'Contact',
+ update => 'Comment',
+ manifesttheme => 'ManifestTheme',
+ };
+ $type = $type_to_object->{$type} || ucfirst $type;
+ my $object = $self->result_source->schema->resultset($type)->find($id);
+ return $object;
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/Body.pm b/perllib/FixMyStreet/DB/Result/Body.pm
index 663181746..95debc910 100644
--- a/perllib/FixMyStreet/DB/Result/Body.pm
+++ b/perllib/FixMyStreet/DB/Result/Body.pm
@@ -117,6 +117,12 @@ __PACKAGE__->has_many(
{ cascade_copy => 0, cascade_delete => 0 },
);
__PACKAGE__->has_many(
+ "roles",
+ "FixMyStreet::DB::Result::Role",
+ { "foreign.body_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+__PACKAGE__->has_many(
"user_body_permissions",
"FixMyStreet::DB::Result::UserBodyPermission",
{ "foreign.body_id" => "self.id" },
@@ -130,8 +136,8 @@ __PACKAGE__->has_many(
);
-# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-04-25 12:06:39
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:8CuxbffDaYS7TFlgff1nEg
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-05-23 18:03:28
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:9sFgYQ9qhnZNcz3kUFYuvg
__PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
__PACKAGE__->rabx_column('extra');
@@ -187,11 +193,7 @@ sub first_area_children {
my $cobrand = $self->result_source->schema->cobrand;
- my $children = FixMyStreet::MapIt::call('area/children', $body_area->area_id,
- type => $cobrand->area_types_children,
- );
-
- return $children;
+ return $cobrand->fetch_area_children($body_area->area_id);
}
=head2 get_cobrand_handler
@@ -209,6 +211,33 @@ sub get_cobrand_handler {
return FixMyStreet::Cobrand->body_handler($self->areas);
}
+=item
+
+If get_cobrand_handler returns a cobrand, and that cobrand
+has a council_name, use it in preference to the body name.
+
+=cut
+
+sub cobrand_name {
+ my $self = shift;
+
+ # Because TfL covers all the boroughs in London, get_cobrand_handler
+ # may return another London cobrand if it is listed before tfl in
+ # ALLOWED_COBRANDS, because one of this body's area_ids will also
+ # match that cobrand's council_area_id. This leads to odd things like
+ # councils_text_all.html showing a message like "These will be sent to
+ # Bromley Council" when making a report within Westminster on the TfL
+ # cobrand.
+ # If the current body is TfL then we always want to show TfL as the cobrand name.
+ return $self->name if $self->name eq 'TfL' || $self->name eq 'Highways England';
+
+ my $handler = $self->get_cobrand_handler;
+ if ($handler && $handler->can('council_name')) {
+ return $handler->council_name;
+ }
+ return $self->name;
+}
+
sub calculate_average {
my ($self, $threshold) = @_;
$threshold ||= 0;
@@ -224,7 +253,7 @@ sub calculate_average {
'problem.state' => [ FixMyStreet::DB::Result::Problem->visible_states() ],
}, {
select => [
- { extract => "epoch from me.confirmed-problem.confirmed", -as => 'time' },
+ { extract => \"epoch from me.confirmed-problem.confirmed", -as => 'time' },
],
as => [ qw/time/ ],
rows => 100,
diff --git a/perllib/FixMyStreet/DB/Result/Comment.pm b/perllib/FixMyStreet/DB/Result/Comment.pm
index 5d0253ef4..b217bf96c 100644
--- a/perllib/FixMyStreet/DB/Result/Comment.pm
+++ b/perllib/FixMyStreet/DB/Result/Comment.pm
@@ -101,6 +101,7 @@ __PACKAGE__->load_components("+FixMyStreet::DB::RABXColumn");
__PACKAGE__->rabx_column('extra');
use Moo;
+use FixMyStreet::Template::SafeString;
use namespace::clean -except => [ 'meta' ];
use FixMyStreet::Template;
@@ -201,7 +202,7 @@ sub moderation_filter {
=head2 meta_line
Returns a string to be used on a report update, describing some of the metadata
-about an update
+about an update. Can include HTML.
=cut
@@ -225,10 +226,15 @@ sub meta_line {
} else {
$body = $self->user->body;
}
+ $body = FixMyStreet::Template::html_filter($body);
if ($body eq 'Bromley Council') {
$body = "$body <img src='/cobrands/bromley/favicon.png' alt=''>";
} elsif ($body eq 'Royal Borough of Greenwich') {
$body = "$body <img src='/cobrands/greenwich/favicon.png' alt=''>";
+ } elsif ($body eq 'Hounslow Borough Council') {
+ $body = 'Hounslow Highways';
+ } elsif ($body eq 'Isle of Wight Council') {
+ $body = 'Island Roads';
}
}
my $cobrand_always_view_body_user = $c->cobrand->call_hook("always_view_body_contribute_details");
@@ -255,7 +261,7 @@ sub meta_line {
$meta .= ', ' . _( 'and a defect raised' );
}
- return $meta;
+ return FixMyStreet::Template::SafeString->new($meta);
};
sub problem_state_processed {
@@ -272,7 +278,11 @@ sub problem_state_display {
return '' unless $state;
my $cobrand_name = $c->cobrand->moniker;
- $cobrand_name = 'bromley' if $self->problem->to_body_named('Bromley');
+ my $names = join(',,', @{$self->problem->body_names});
+ if ($names =~ /(Bromley|Isle of Wight|TfL)/) {
+ ($cobrand_name = lc $1) =~ s/ //g;
+ }
+
return FixMyStreet::DB->resultset("State")->display($state, 1, $cobrand_name);
}
@@ -282,6 +292,7 @@ sub is_latest {
{ problem_id => $self->problem_id, state => 'confirmed' },
{ order_by => [ { -desc => 'confirmed' }, { -desc => 'id' } ] }
)->first;
+ return unless $latest_update;
return $latest_update->id == $self->id;
}
diff --git a/perllib/FixMyStreet/DB/Result/Contact.pm b/perllib/FixMyStreet/DB/Result/Contact.pm
index 17620f279..affc6d480 100644
--- a/perllib/FixMyStreet/DB/Result/Contact.pm
+++ b/perllib/FixMyStreet/DB/Result/Contact.pm
@@ -93,12 +93,34 @@ __PACKAGE__->many_to_many( response_templates => 'contact_response_templates', '
__PACKAGE__->many_to_many( response_priorities => 'contact_response_priorities', 'response_priority' );
__PACKAGE__->many_to_many( defect_types => 'contact_defect_types', 'defect_type' );
+__PACKAGE__->might_have(
+ "translations",
+ "FixMyStreet::DB::Result::Translation",
+ sub {
+ my $args = shift;
+ return {
+ "$args->{foreign_alias}.object_id" => { -ident => "$args->{self_alias}.id" },
+ "$args->{foreign_alias}.tbl" => { '=' => \"?" },
+ "$args->{foreign_alias}.col" => { '=' => \"?" },
+ "$args->{foreign_alias}.lang" => { '=' => \"?" },
+ };
+ },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+
sub category_display {
my $self = shift;
- $self->translate_column('category');
+ $self->get_extra_metadata('display_name') || $self->translate_column('category');
}
-sub get_metadata_for_editing {
+sub groups {
+ my $self = shift;
+ my $groups = $self->get_extra_metadata('group') || [];
+ $groups = [ $groups ] unless ref $groups eq 'ARRAY';
+ return $groups;
+}
+
+sub get_all_metadata {
my $self = shift;
my @metadata = @{$self->get_extra_fields};
@@ -111,9 +133,19 @@ sub get_metadata_for_editing {
return \@metadata;
}
+sub get_metadata_for_editing {
+ my $self = shift;
+ my $metadata = $self->get_all_metadata;
+
+ # Ignore the special admin-form-created entry
+ my @metadata = grep { $_->{code} ne '_fms_disable_' } @$metadata;
+
+ return \@metadata;
+}
+
sub get_metadata_for_input {
my $self = shift;
- my $metadata = $self->get_metadata_for_editing;
+ my $metadata = $self->get_all_metadata;
# Also ignore any we have with a 'server_set' automated attribute
my @metadata = grep { !$_->{automated} || $_->{automated} ne 'server_set' } @$metadata;
@@ -121,9 +153,26 @@ sub get_metadata_for_input {
return \@metadata;
}
+sub get_metadata_for_storage {
+ my $self = shift;
+ my $metadata = $self->get_metadata_for_input;
+
+ # Also ignore any that were only for textual display
+ my @metadata = grep { ($_->{variable} || '') ne 'false' } @$metadata;
+
+ return \@metadata;
+}
+
sub id_field {
my $self = shift;
return $self->get_extra_metadata('id_field') || 'fixmystreet_id';
}
+sub disable_form_field {
+ my $self = shift;
+ my $metadata = $self->get_all_metadata;
+ my ($field) = grep { $_->{code} eq '_fms_disable_' } @$metadata;
+ return $field;
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/ManifestTheme.pm b/perllib/FixMyStreet/DB/Result/ManifestTheme.pm
new file mode 100644
index 000000000..a2f49eacb
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/ManifestTheme.pm
@@ -0,0 +1,47 @@
+use utf8;
+package FixMyStreet::DB::Result::ManifestTheme;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+__PACKAGE__->load_components(
+ "FilterColumn",
+ "FixMyStreet::InflateColumn::DateTime",
+ "FixMyStreet::EncodedColumn",
+);
+__PACKAGE__->table("manifest_theme");
+__PACKAGE__->add_columns(
+ "id",
+ {
+ data_type => "integer",
+ is_auto_increment => 1,
+ is_nullable => 0,
+ sequence => "manifest_theme_id_seq",
+ },
+ "cobrand",
+ { data_type => "text", is_nullable => 0 },
+ "name",
+ { data_type => "text", is_nullable => 0 },
+ "short_name",
+ { data_type => "text", is_nullable => 0 },
+ "background_colour",
+ { data_type => "text", is_nullable => 1 },
+ "theme_colour",
+ { data_type => "text", is_nullable => 1 },
+ "images",
+ { data_type => "text[]", is_nullable => 1 },
+);
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->add_unique_constraint("manifest_theme_cobrand_key", ["cobrand"]);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2020-01-30 14:30:42
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Sgbva7nEVkjqG/+lQL/ryw
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm b/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm
index 18d2a7683..1805e1fd2 100644
--- a/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm
+++ b/perllib/FixMyStreet/DB/Result/ModerationOriginalData.pm
@@ -74,6 +74,7 @@ __PACKAGE__->belongs_to(
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:FLKiZELcfBcc9VwHU2MZYQ
use Moo;
+use FixMyStreet::Template::SafeString;
use Text::Diff;
use Data::Dumper;
@@ -147,11 +148,12 @@ sub compare_photo {
push @deleted, $diff->Items(1);
push @added, $diff->Items(2);
}
- return (join ', ', map {
+ my $s = (join ', ', map {
"<del style='background-color:#fcc'>$_</del>";
} @deleted) . (join ', ', map {
"<ins style='background-color:#cfc'>$_</ins>";
} @added);
+ return FixMyStreet::Template::SafeString->new($s);
}
sub compare_extra {
@@ -212,7 +214,7 @@ sub string_diff {
$string .= $inserted;
}
}
- return $string;
+ return FixMyStreet::Template::SafeString->new($string);
}
1;
diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm
index dc45091ee..37563d327 100644
--- a/perllib/FixMyStreet/DB/Result/Problem.pm
+++ b/perllib/FixMyStreet/DB/Result/Problem.pm
@@ -201,6 +201,8 @@ use Moo;
use namespace::clean -except => [ 'meta' ];
use Utils;
use FixMyStreet::Map::FMS;
+use FixMyStreet::Template;
+use FixMyStreet::Template::SafeString;
use LWP::Simple qw($ua);
use RABX;
use URI;
@@ -338,6 +340,7 @@ around service => sub {
sub title_safe {
my $self = shift;
return _('Awaiting moderation') if $self->cobrand eq 'zurich' && $self->state eq 'submitted';
+ return sprintf("%s problem", $self->category) if $self->cobrand eq 'tfl' && $self->result_source->schema->cobrand->moniker ne 'tfl';
return $self->title;
}
@@ -362,6 +365,9 @@ sub check_for_errors {
$errors{title} = _('Please enter a subject')
unless $self->title =~ m/\S/;
+ $errors{title} = _('Please make sure you are not including an email address')
+ if mySociety::EmailUtil::is_valid_email($self->title);
+
$errors{detail} = _('Please enter some details')
unless $self->detail =~ m/\S/;
@@ -373,13 +379,6 @@ sub check_for_errors {
$errors{name} = _('Please enter your name');
}
- if ( $self->category
- && $self->category eq _('-- Pick a category --') )
- {
- $errors{category} = _('Please choose a category');
- $self->category(undef);
- }
-
return \%errors;
}
@@ -408,7 +407,28 @@ sub confirm {
sub category_display {
my $self = shift;
- $self->translate_column('category');
+ my $contact = $self->category_row;
+ return $self->category unless $contact; # Fallback; shouldn't happen, but some tests
+ return $contact->category_display;
+}
+
+=head2 category_row
+
+Returns the corresponding Contact object for this problem's category and body.
+If the report was sent to multiple bodies, only returns the first.
+
+=cut
+
+sub category_row {
+ my $self = shift;
+ my $schema = $self->result_source->schema;
+ my $body_id = $self->bodies_str_ids->[0];
+ return unless $body_id && $body_id =~ /^[0-9]+$/;
+ my $contact = $schema->resultset("Contact")->find({
+ body_id => $body_id,
+ category => $self->category,
+ });
+ return $contact;
}
sub bodies_str_ids {
@@ -505,6 +525,31 @@ sub tokenised_url {
return "/M/". $token->token;
}
+has view_token => (
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ my $token = FixMyStreet::DB->resultset('Token')->create({
+ scope => 'alert_to_reporter',
+ data => { id => $self->id }
+ });
+ },
+);
+
+=head2 view_url
+
+Return a url for this problem report that will always show it
+(even if e.g. a private report) but does not log the user in.
+
+=cut
+
+sub view_url {
+ my $self = shift;
+ return $self->url unless $self->non_public;
+ return "/R/" . $self->view_token->token;
+}
+
=head2 is_hidden
Returns 1 if the problem is in an hidden state otherwise 0.
@@ -652,16 +697,16 @@ sub body {
my $cache = $problem->result_source->schema->cache;
return $cache->{bodies}{$problem->external_body} //= $c->model('DB::Body')->find({ id => $problem->external_body });
} else {
- $body = $problem->external_body;
+ $body = FixMyStreet::Template::html_filter($problem->external_body);
}
} else {
my $bodies = $problem->bodies;
my @body_names = sort map {
my $name = $_->name;
if ($c and FixMyStreet->config('AREA_LINKS_FROM_PROBLEMS')) {
- '<a href="' . $_->url . '">' . $name . '</a>';
+ '<a href="' . $_->url . '">' . FixMyStreet::Template::html_filter($name) . '</a>';
} else {
- $name;
+ FixMyStreet::Template::html_filter($name);
}
} values %$bodies;
if ( scalar @body_names > 2 ) {
@@ -671,7 +716,7 @@ sub body {
$body = join( _(' and '), @body_names);
}
}
- return $body;
+ return FixMyStreet::Template::SafeString->new($body);
}
@@ -755,23 +800,26 @@ sub defect_types {
# Note: this only makes sense when called on a problem that has been sent!
sub can_display_external_id {
my $self = shift;
- if ($self->external_id && $self->send_method_used && $self->to_body_named('Oxfordshire|Lincolnshire')) {
+ if ($self->external_id && $self->to_body_named('Oxfordshire|Lincolnshire|Isle of Wight|East Sussex')) {
return 1;
}
return 0;
}
+# This can return HTML and is safe, so returns a FixMyStreet::Template::SafeString
sub duration_string {
my ( $problem, $c ) = @_;
my $body = $c->cobrand->call_hook(link_to_council_cobrand => $problem) || $problem->body($c);
my $handler = $c->cobrand->call_hook(get_body_handler_for_problem => $problem);
if ( $handler && $handler->call_hook('is_council_with_case_management') ) {
- return sprintf(_('Received by %s moments later'), $body);
+ my $s = sprintf(_('Received by %s moments later'), $body);
+ return FixMyStreet::Template::SafeString->new($s);
}
return unless $problem->whensent;
- return sprintf(_('Sent to %s %s later'), $body,
+ my $s = sprintf(_('Sent to %s %s later'), $body,
Utils::prettify_duration($problem->whensent->epoch - $problem->confirmed->epoch, 'minute')
);
+ return FixMyStreet::Template::SafeString->new($s);
}
sub local_coords {
@@ -889,6 +937,8 @@ bodies by some mechanism. Right now that mechanism is Open311.
sub updates_sent_to_body {
my $self = shift;
+
+ return 1 if $self->to_body_named('TfL');
return unless $self->send_method_used && $self->send_method_used =~ /Open311/;
# Some bodies only send updates *to* FMS, they don't receive updates.
@@ -1015,11 +1065,12 @@ sub pin_data {
problem => $self,
draggable => $opts{draggable},
type => $opts{type},
+ base_url => $c->cobrand->relative_url_for_report($self),
}
};
sub static_map {
- my ($self) = @_;
+ my ($self, %params) = @_;
return unless $IM;
@@ -1027,7 +1078,11 @@ sub static_map {
unless $FixMyStreet::Map::map_class->isa("FixMyStreet::Map::OSM");
my $map_data = $FixMyStreet::Map::map_class->generate_map_data(
- { cobrand => $self->get_cobrand_logged },
+ {
+ cobrand => $self->get_cobrand_logged,
+ distance => 1, # prevents the call to Gaze which isn't necessary
+ $params{zoom} ? ( zoom => $params{zoom} ) : (),
+ },
latitude => $self->latitude,
longitude => $self->longitude,
pins => $self->used_map
@@ -1084,7 +1139,7 @@ sub static_map {
$image->Extent( geometry => '512x384', gravity => 'NorthWest');
$image->Extent( geometry => '512x320', gravity => 'SouthWest');
- $image->Scale( geometry => "310x200>" );
+ $image->Scale( geometry => "310x200>" ) unless $params{full_size};
my @blobs = $image->ImageToBlob(magick => 'jpeg');
undef $image;
@@ -1161,4 +1216,15 @@ has inspection_log_entry => (
},
);
+has alerts => (
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ return $self->result_source->schema->resultset('Alert')->search({
+ alert_type => 'new_updates', parameter => $self->id
+ });
+ },
+);
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/Role.pm b/perllib/FixMyStreet/DB/Result/Role.pm
new file mode 100644
index 000000000..e35b0b195
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/Role.pm
@@ -0,0 +1,53 @@
+use utf8;
+package FixMyStreet::DB::Result::Role;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+__PACKAGE__->load_components(
+ "FilterColumn",
+ "FixMyStreet::InflateColumn::DateTime",
+ "FixMyStreet::EncodedColumn",
+);
+__PACKAGE__->table("roles");
+__PACKAGE__->add_columns(
+ "id",
+ {
+ data_type => "integer",
+ is_auto_increment => 1,
+ is_nullable => 0,
+ sequence => "roles_id_seq",
+ },
+ "body_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+ "name",
+ { data_type => "text", is_nullable => 1 },
+ "permissions",
+ { data_type => "text[]", is_nullable => 1 },
+);
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->add_unique_constraint("roles_body_id_name_key", ["body_id", "name"]);
+__PACKAGE__->belongs_to(
+ "body",
+ "FixMyStreet::DB::Result::Body",
+ { id => "body_id" },
+ { is_deferrable => 0, on_delete => "CASCADE,", on_update => "NO ACTION" },
+);
+__PACKAGE__->has_many(
+ "user_roles",
+ "FixMyStreet::DB::Result::UserRole",
+ { "foreign.role_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-05-23 18:03:28
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:KkzVQZuzExH8PhZLJsnZgg
+
+__PACKAGE__->many_to_many( users => 'user_roles', 'user' );
+
+1;
diff --git a/perllib/FixMyStreet/DB/Result/User.pm b/perllib/FixMyStreet/DB/Result/User.pm
index d01ba92d0..b0a05d0b7 100644
--- a/perllib/FixMyStreet/DB/Result/User.pm
+++ b/perllib/FixMyStreet/DB/Result/User.pm
@@ -24,22 +24,30 @@ __PACKAGE__->add_columns(
},
"email",
{ data_type => "text", is_nullable => 1 },
- "email_verified",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
"name",
{ data_type => "text", is_nullable => 1 },
"phone",
{ data_type => "text", is_nullable => 1 },
- "phone_verified",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
"password",
{ data_type => "text", default_value => "", is_nullable => 0 },
- "from_body",
- { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
"flagged",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "from_body",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 1 },
+ "title",
+ { data_type => "text", is_nullable => 1 },
+ "facebook_id",
+ { data_type => "bigint", is_nullable => 1 },
+ "twitter_id",
+ { data_type => "bigint", is_nullable => 1 },
"is_superuser",
{ data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "extra",
+ { data_type => "text", is_nullable => 1 },
+ "email_verified",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
+ "phone_verified",
+ { data_type => "boolean", default_value => \"false", is_nullable => 0 },
"created",
{
data_type => "timestamp",
@@ -54,16 +62,10 @@ __PACKAGE__->add_columns(
is_nullable => 0,
original => { default_value => \"now()" },
},
- "title",
- { data_type => "text", is_nullable => 1 },
- "twitter_id",
- { data_type => "bigint", is_nullable => 1 },
- "facebook_id",
- { data_type => "bigint", is_nullable => 1 },
- "extra",
- { data_type => "text", is_nullable => 1 },
"area_ids",
{ data_type => "integer[]", is_nullable => 1 },
+ "oidc_ids",
+ { data_type => "text[]", is_nullable => 1 },
);
__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint("users_facebook_id_key", ["facebook_id"]);
@@ -121,10 +123,16 @@ __PACKAGE__->has_many(
{ "foreign.user_id" => "self.id" },
{ cascade_copy => 0, cascade_delete => 0 },
);
+__PACKAGE__->has_many(
+ "user_roles",
+ "FixMyStreet::DB::Result::UserRole",
+ { "foreign.user_id" => "self.id" },
+ { cascade_copy => 0, cascade_delete => 0 },
+);
-# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-04-25 12:06:39
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:BCCqv3JCec8psuRk/SdCJQ
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-06-20 16:31:44
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Ryb6giJm/7N7svg/d+2GeA
# These are not fully unique constraints (they only are when the *_verified
# is true), but this is managed in ResultSet::User's find() wrapper.
@@ -136,6 +144,7 @@ __PACKAGE__->rabx_column('extra');
use Moo;
use Text::CSV;
+use List::MoreUtils 'uniq';
use FixMyStreet::SMS;
use mySociety::EmailUtil;
use namespace::clean -except => [ 'meta' ];
@@ -143,6 +152,7 @@ use namespace::clean -except => [ 'meta' ];
with 'FixMyStreet::Roles::Extra';
__PACKAGE__->many_to_many( planned_reports => 'user_planned_reports', 'report' );
+__PACKAGE__->many_to_many( roles => 'user_roles', 'role' );
sub cost {
FixMyStreet->test_mode ? 1 : 12;
@@ -153,10 +163,30 @@ __PACKAGE__->add_columns(
encode_column => 1,
encode_class => 'Crypt::Eksblowfish::Bcrypt',
encode_args => { cost => cost() },
- encode_check_method => 'check_password',
+ encode_check_method => '_check_password',
},
);
+sub check_password {
+ my $self = shift;
+ my $cobrand = $self->result_source->schema->cobrand;
+ if ($cobrand->moniker eq 'tfl') {
+ my $col_v = $self->get_extra_metadata('tfl_password');
+ return unless defined $col_v;
+ $self->_column_encoders->{password}->($_[0], $col_v) eq $col_v;
+ } else {
+ $self->_check_password(@_);
+ }
+}
+
+around password => sub {
+ my ($orig, $self) = (shift, shift);
+ if (@_) {
+ $self->set_extra_metadata(last_password_change => time());
+ }
+ $self->$orig(@_);
+};
+
=head2 username
Returns a verified email or phone for this user, preferring email,
@@ -188,6 +218,15 @@ sub latest_anonymity {
return $obj ? $obj->anonymous : 0;
}
+sub latest_visible_problem {
+ my $self = shift;
+ return $self->problems->search({
+ state => [ FixMyStreet::DB::Result::Problem->visible_states() ]
+ }, {
+ order_by => { -desc => 'id' }
+ })->single;
+}
+
=head2 check_for_errors
$error_hashref = $user->check_for_errors();
@@ -298,7 +337,11 @@ sub body {
sub moderating_user_name {
my $self = shift;
- return $self->body || _('an administrator');
+ my $body = $self->body;
+ if ( $body && $body eq 'Isle of Wight Council' ) {
+ $body = 'Island Roads';
+ }
+ return $body || _('an administrator');
}
=head2 belongs_to_body
@@ -375,7 +418,18 @@ has body_permissions => (
lazy => 1,
default => sub {
my $self = shift;
- return [ $self->user_body_permissions->all ];
+ my $perms = [];
+ foreach my $role ($self->roles->all) {
+ push @$perms, map { {
+ body_id => $role->body_id,
+ permission => $_,
+ } } @{$role->permissions};
+ }
+ push @$perms, map { {
+ body_id => $_->body_id,
+ permission => $_->permission_type,
+ } } $self->user_body_permissions->all;
+ return $perms;
},
);
@@ -392,8 +446,8 @@ sub permissions {
return unless $self->belongs_to_body($body_id);
- my @permissions = grep { $_->body_id == $self->from_body->id } @{$self->body_permissions};
- return { map { $_->permission_type => 1 } @permissions };
+ my @permissions = grep { $_->{body_id} == $self->from_body->id } @{$self->body_permissions};
+ return { map { $_->{permission} => 1 } @permissions };
}
sub has_permission_to {
@@ -404,18 +458,15 @@ sub has_permission_to {
my $cobrand = $self->result_source->schema->cobrand;
my $cobrand_perms = $cobrand->available_permissions;
my %available = map { %$_ } values %$cobrand_perms;
- # The 'trusted' permission is never set in the cobrand's
- # available_permissions (see note there in Default.pm) so include it here.
- $available{trusted} = 1;
return 0 unless $available{$permission_type};
return 1 if $self->is_superuser;
- return 0 if !$body_ids || (ref $body_ids && !@$body_ids);
- $body_ids = [ $body_ids ] unless ref $body_ids;
+ return 0 if !$body_ids || (ref $body_ids eq 'ARRAY' && !@$body_ids);
+ $body_ids = [ $body_ids ] unless ref $body_ids eq 'ARRAY';
my %body_ids = map { $_ => 1 } @$body_ids;
foreach (@{$self->body_permissions}) {
- return 1 if $_->permission_type eq $permission_type && $body_ids{$_->body_id};
+ return 1 if $_->{permission} eq $permission_type && $body_ids{$_->{body_id}};
}
return 0;
}
@@ -464,7 +515,7 @@ sub admin_user_body_permissions {
sub has_2fa {
my $self = shift;
- return $self->is_superuser && $self->get_extra_metadata('2fa_secret');
+ return $self->get_extra_metadata('2fa_secret');
}
sub contributing_as {
@@ -516,6 +567,7 @@ sub anonymize_account {
title => undef,
twitter_id => undef,
facebook_id => undef,
+ oidc_ids => undef,
});
}
@@ -565,14 +617,6 @@ sub is_planned_report {
return scalar grep { $_->report_id == $id } @{$self->active_user_planned_reports};
}
-sub update_reputation {
- my ( $self, $change ) = @_;
-
- my $reputation = $self->get_extra_metadata('reputation') || 0;
- $self->set_extra_metadata( reputation => $reputation + $change);
- $self->update;
-}
-
has categories => (
is => 'ro',
lazy => 1,
@@ -621,4 +665,35 @@ sub in_area {
return $self->areas_hash->{$area};
}
+has roles_hash => (
+ is => 'ro',
+ lazy => 1,
+ default => sub {
+ my $self = shift;
+ my %ids = map { $_->role_id => 1 } $self->user_roles->all;
+ return \%ids;
+ },
+);
+
+sub in_role {
+ my ($self, $role) = @_;
+ return $self->roles_hash->{$role};
+}
+
+sub add_oidc_id {
+ my ($self, $oidc_id) = @_;
+
+ my $oidc_ids = $self->oidc_ids || [];
+ my @oidc_ids = uniq ( $oidc_id, @$oidc_ids );
+ $self->oidc_ids(\@oidc_ids);
+}
+
+sub remove_oidc_id {
+ my ($self, $oidc_id) = @_;
+
+ my $oidc_ids = $self->oidc_ids || [];
+ my @oidc_ids = grep { $_ ne $oidc_id } @$oidc_ids;
+ $self->oidc_ids(scalar @oidc_ids ? \@oidc_ids : undef);
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/Result/UserRole.pm b/perllib/FixMyStreet/DB/Result/UserRole.pm
new file mode 100644
index 000000000..9186e2aa1
--- /dev/null
+++ b/perllib/FixMyStreet/DB/Result/UserRole.pm
@@ -0,0 +1,50 @@
+use utf8;
+package FixMyStreet::DB::Result::UserRole;
+
+# Created by DBIx::Class::Schema::Loader
+# DO NOT MODIFY THE FIRST PART OF THIS FILE
+
+use strict;
+use warnings;
+
+use base 'DBIx::Class::Core';
+__PACKAGE__->load_components(
+ "FilterColumn",
+ "FixMyStreet::InflateColumn::DateTime",
+ "FixMyStreet::EncodedColumn",
+);
+__PACKAGE__->table("user_roles");
+__PACKAGE__->add_columns(
+ "id",
+ {
+ data_type => "integer",
+ is_auto_increment => 1,
+ is_nullable => 0,
+ sequence => "user_roles_id_seq",
+ },
+ "role_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+ "user_id",
+ { data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
+);
+__PACKAGE__->set_primary_key("id");
+__PACKAGE__->belongs_to(
+ "role",
+ "FixMyStreet::DB::Result::Role",
+ { id => "role_id" },
+ { is_deferrable => 0, on_delete => "CASCADE,", on_update => "NO ACTION" },
+);
+__PACKAGE__->belongs_to(
+ "user",
+ "FixMyStreet::DB::Result::User",
+ { id => "user_id" },
+ { is_deferrable => 0, on_delete => "CASCADE,", on_update => "NO ACTION" },
+);
+
+
+# Created by DBIx::Class::Schema::Loader v0.07035 @ 2019-05-23 16:52:59
+# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1BSR4j0o5PApKEZmzVAnLg
+
+
+# You can replace this text with custom code or comments, and it will be preserved on regeneration
+1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Alert.pm b/perllib/FixMyStreet/DB/ResultSet/Alert.pm
index c61053fff..ddf80bc52 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Alert.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Alert.pm
@@ -7,11 +7,6 @@ use warnings;
sub timeline_created {
my ( $rs, $restriction ) = @_;
- my $prefetch =
- $rs->result_source->storage->sql_maker->quote_char ?
- [ qw/alert_type user/ ] :
- [ qw/alert_type/ ];
-
return $rs->search(
{
whensubscribed => { '>=', \"current_timestamp-'7 days'::interval" },
@@ -19,7 +14,7 @@ sub timeline_created {
%{ $restriction },
},
{
- prefetch => $prefetch,
+ prefetch => [ qw/alert_type user/ ],
}
);
}
diff --git a/perllib/FixMyStreet/DB/ResultSet/Comment.pm b/perllib/FixMyStreet/DB/ResultSet/Comment.pm
index b9a3df62d..034b86a40 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Comment.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Comment.pm
@@ -13,18 +13,13 @@ sub to_body {
sub timeline {
my ( $rs ) = @_;
- my $prefetch =
- $rs->result_source->storage->sql_maker->quote_char ?
- [ qw/user/ ] :
- [];
-
return $rs->search(
{
'me.state' => 'confirmed',
'me.created' => { '>=', \"current_timestamp-'7 days'::interval" },
},
{
- prefetch => $prefetch,
+ prefetch => 'user',
}
);
}
diff --git a/perllib/FixMyStreet/DB/ResultSet/Contact.pm b/perllib/FixMyStreet/DB/ResultSet/Contact.pm
index 8ef6d1ac5..801d20cc0 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Contact.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Contact.pm
@@ -3,6 +3,7 @@ use base 'DBIx::Class::ResultSet';
use strict;
use warnings;
+use POSIX qw(strcoll);
sub me { join('.', shift->current_source_alias, shift || q{}) }
@@ -16,7 +17,12 @@ Filter down to not deleted contacts (so active or inactive).
sub not_deleted {
my $rs = shift;
- return $rs->search( { $rs->me('state') => { '!=' => 'deleted' } } );
+ return $rs->search( { $rs->me('state') => { -not_in => [ 'deleted', 'staff' ] } } );
+}
+
+sub not_deleted_admin {
+ my $rs = shift;
+ return $rs->search( { $rs->me('state') => { -not_in => [ 'deleted' ] } } );
}
sub active {
@@ -24,6 +30,53 @@ sub active {
$rs->search( { $rs->me('state') => [ 'unconfirmed', 'confirmed' ] } );
}
+sub for_new_reports {
+ my ($rs, $c, $bodies) = @_;
+ my $params = {
+ $rs->me('body_id') => [ keys %$bodies ],
+ };
+
+ if ($c->user_exists && $c->user->is_superuser) {
+ # Everything normal OR any staff states
+ $params->{$rs->me('state')} = [ 'unconfirmed', 'confirmed', 'staff' ];
+ } elsif ($c->user_exists && $c->user->from_body) {
+ # Everything normal OR staff state in the user body
+ $params->{'-or'} = [
+ $rs->me('state') => [ 'unconfirmed', 'confirmed' ],
+ {
+ $rs->me('body_id') => $c->user->from_body->id,
+ $rs->me('state') => 'staff',
+ },
+ ];
+ } else {
+ $params->{$rs->me('state')} = [ 'unconfirmed', 'confirmed' ];
+ }
+
+ $rs->search($params, { prefetch => 'body' });
+}
+
+sub translated {
+ my $rs = shift;
+ my $schema = $rs->result_source->schema;
+ $rs->search(undef, {
+ '+columns' => { 'msgstr' => 'translations.msgstr' },
+ join => 'translations',
+ bind => [ 'category', $schema->lang, 'contact' ],
+ });
+}
+
+sub all_sorted {
+ my $rs = shift;
+
+ my @contacts = $rs->translated->all;
+ @contacts = sort {
+ my $a_name = $a->get_extra_metadata('display_name') || $a->get_column('msgstr') || $a->category;
+ my $b_name = $b->get_extra_metadata('display_name') || $b->get_column('msgstr') || $b->category;
+ strcoll($a_name, $b_name)
+ } @contacts;
+ return @contacts;
+}
+
sub summary_count {
my ( $rs, $restriction ) = @_;
@@ -37,4 +90,13 @@ sub summary_count {
);
}
+sub group_lookup {
+ my $rs = shift;
+ map {
+ my $group = $_->get_extra_metadata('group') || '';
+ $group = join(',', ref $group ? @$group : $group);
+ $_->category => $group
+ } $rs->all;
+}
+
1;
diff --git a/perllib/FixMyStreet/DB/ResultSet/Problem.pm b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
index 37fc34057..e23cf78e1 100644
--- a/perllib/FixMyStreet/DB/ResultSet/Problem.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/Problem.pm
@@ -141,7 +141,7 @@ sub _recent {
$query->{photo} = { '!=', undef } if $photos;
my $attrs = {
- order_by => { -desc => 'coalesce(confirmed, created)' },
+ order_by => { -desc => \'coalesce(confirmed, created)' },
rows => $num,
};
@@ -155,10 +155,11 @@ sub _recent {
} else {
$probs = Memcached::get($key);
if ($probs) {
- # Need to reattach schema so that confirmed column gets reinflated.
- $probs->[0]->result_source->schema( $rs->result_source->schema ) if $probs->[0];
- # Catch any cached ones since hidden
- $probs = [ grep { $_->photo && ! $_->is_hidden } @$probs ];
+ # Need to refetch to check if hidden since cached
+ $probs = [ $rs->search({
+ id => [ map { $_->id } @$probs ],
+ %$query,
+ }, $attrs)->all ];
} else {
$probs = [ $rs->search( $query, $attrs )->all ];
Memcached::set($key, $probs, _cache_timeout());
@@ -207,11 +208,6 @@ sub around_map {
sub timeline {
my ( $rs ) = @_;
- my $prefetch =
- $rs->result_source->storage->sql_maker->quote_char ?
- [ qw/user/ ] :
- [];
-
return $rs->search(
{
-or => {
@@ -221,7 +217,7 @@ sub timeline {
}
},
{
- prefetch => $prefetch,
+ prefetch => 'user',
}
);
}
@@ -245,12 +241,9 @@ sub unique_users {
return $rs->search( {
state => [ FixMyStreet::DB::Result::Problem->visible_states() ],
}, {
- select => [ { distinct => 'user_id' } ],
- as => [ 'user_id' ]
- } )->as_subselect_rs->search( undef, {
- select => [ { count => 'user_id' } ],
- as => [ 'count' ]
- } )->first->get_column('count');
+ columns => [ 'user_id' ],
+ distinct => 1,
+ } );
}
sub categories_summary {
@@ -273,7 +266,9 @@ sub categories_summary {
sub include_comment_counts {
my $rs = shift;
my $order_by = $rs->{attrs}{order_by};
- return $rs unless ref $order_by eq 'HASH' && $order_by->{-desc} eq 'comment_count';
+ return $rs unless
+ (ref $order_by eq 'ARRAY' && ref $order_by->[0] eq 'HASH' && $order_by->[0]->{-desc} eq 'comment_count')
+ || (ref $order_by eq 'HASH' && $order_by->{-desc} eq 'comment_count');
$rs->search({}, {
'+select' => [ {
"" => \'(select count(*) from comment where problem_id=me.id and state=\'confirmed\')',
diff --git a/perllib/FixMyStreet/DB/ResultSet/State.pm b/perllib/FixMyStreet/DB/ResultSet/State.pm
index 3e6169aeb..4f98efbf2 100644
--- a/perllib/FixMyStreet/DB/ResultSet/State.pm
+++ b/perllib/FixMyStreet/DB/ResultSet/State.pm
@@ -1,6 +1,7 @@
package FixMyStreet::DB::ResultSet::State;
use base 'DBIx::Class::ResultSet';
+use utf8;
use strict;
use warnings;
use Memcached;
@@ -74,8 +75,13 @@ sub display {
return $unchanging->{$label} if $unchanging->{$label};
if ($cobrand && $label eq 'not responsible') {
return 'third party responsibility' if $cobrand eq 'bromley';
+ return "not Island Roads’ responsibility" if $cobrand eq 'isleofwight';
+ return "not TfL’s responsibility" if $cobrand eq 'tfl';
return _("not the council's responsibility");
}
+ if ($cobrand && $cobrand eq 'oxfordshire' && $label eq 'unable to fix') {
+ return 'Investigation complete';
+ }
my ($state) = $rs->_filter(sub { $_->label eq $label });
return $label unless $state;
$state->name($translate_now->{$label}) if $translate_now->{$label};
diff --git a/perllib/FixMyStreet/DB/Schema.pm b/perllib/FixMyStreet/DB/Schema.pm
index be39069d8..e39a8422e 100644
--- a/perllib/FixMyStreet/DB/Schema.pm
+++ b/perllib/FixMyStreet/DB/Schema.pm
@@ -21,6 +21,7 @@ __PACKAGE__->load_namespaces(
use Moo;
use FixMyStreet;
+__PACKAGE__->storage_type('::DBI::PgServerCursor');
__PACKAGE__->connection(FixMyStreet->dbic_connect_info);
has lang => ( is => 'rw' );